auto import from //depot/cupcake/@135843
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..267a6aa
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,222 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Android-specific code.                        ==
+   =========================================================================
+
+Android Code
+Copyright 2005-2008 The Android Open Source Project
+
+This product includes software developed as part of
+The Android Open Source Project (http://source.android.com).
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for Apache Commons code.                              ==
+   =========================================================================
+
+Apache Commons
+Copyright 1999-2004 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for Jakarta Commons Logging.                          ==
+   =========================================================================
+
+Jakarta Commons Logging (JCL)
+Copyright 2005,2006 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Nuance code.                                  ==
+   =========================================================================
+
+These files are Copyright 2007 Nuance Communications, but released under
+the Apache2 License.
+
+                               Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/awt/Android.mk b/awt/Android.mk
new file mode 100644
index 0000000..c7480f5
--- /dev/null
+++ b/awt/Android.mk
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_RESOURCE_DIRS := resources
+
+LOCAL_JAVA_LIBRARIES := core framework
+
+LOCAL_MODULE:= android.awt
+
+LOCAL_DX_FLAGS := --core-library
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/awt/com/android/internal/awt/AndroidGraphics2D.java b/awt/com/android/internal/awt/AndroidGraphics2D.java
new file mode 100644
index 0000000..9a8ae02
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidGraphics2D.java
@@ -0,0 +1,1354 @@
+/*
+ * Copyright 2007, 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.android.internal.awt;
+
+import com.android.internal.awt.AndroidGraphicsConfiguration;
+import com.android.internal.graphics.NativeUtils;
+
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.PathIterator;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
+import java.awt.image.renderable.RenderableImage;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.font.AndroidGlyphVector;
+import org.apache.harmony.awt.gl.font.FontMetricsImpl;
+import org.apache.harmony.awt.gl.image.OffscreenImage;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.graphics.Typeface;
+import android.graphics.PixelXorXfermode;
+import android.view.Display;
+import android.view.WindowManager;
+import android.content.Context;
+
+public class AndroidGraphics2D extends Graphics2D {
+    
+    private int displayWidth, displayHeight;
+
+    protected Surface dstSurf = null;
+    protected MultiRectArea clip = null;
+
+    protected Composite composite = AlphaComposite.SrcOver;
+    protected AffineTransform transform = new AffineTransform();
+
+    private static AndroidGraphics2D mAg;
+    private static Canvas mC;
+
+    // Android Paint
+    public static Paint mP;
+
+    private static java.awt.Font mFnt;
+
+    // Cached Matrix
+    public static Matrix mM;
+    private static FontMetrics mFm;
+    private static RenderingHints mRh;
+    private static Color mBc;
+
+    private Area mCurrClip;
+    
+    public final static double RAD_360 = Math.PI / 180 * 360;
+    
+    // Image drawing
+    private AndroidJavaBlitter blitter;
+    private DirectColorModel cm;
+    private SinglePixelPackedSampleModel sm;
+    private WritableRaster wr;
+
+
+    public static AndroidGraphics2D getInstance() {
+        if (mAg == null) {
+            throw new RuntimeException("AndroidGraphics2D not instantiated!");
+        }
+        return mAg;
+    }
+
+    public static AndroidGraphics2D getInstance(Context ctx, Canvas c, Paint p) {
+        if (c == null || ctx == null) {
+            throw new RuntimeException(
+                    "Illegal argument, Canvas cannot be null!");
+        }
+        mAg = new AndroidGraphics2D(ctx, c, p);
+        return mAg;
+    }
+
+    private AndroidGraphics2D(Context ctx, Canvas c, Paint p) {
+        super();
+        mC = c;
+        mP = p;
+        mM = new Matrix();
+        mM.reset();
+        mM = mC.getMatrix();
+        Rect r = mC.getClipBounds();
+        int cl[] = {-1, r.top, r.left, -2, r.top, r.right, -2, r.bottom, r.right, -2, r.bottom, r.left};
+        mCurrClip = new Area(createShape(cl));
+        if(ctx != null) {
+            WindowManager wm = (WindowManager)ctx.getSystemService(Context.WINDOW_SERVICE);
+            Display d = wm.getDefaultDisplay();
+            displayWidth = d.getWidth();
+            displayHeight = d.getHeight();
+        }
+        blitter = new AndroidJavaBlitter(c);
+        cm = new DirectColorModel(32, 0xff0000, 0xff00, 0xff, 0xff000000);
+        sm = new SinglePixelPackedSampleModel(
+                DataBuffer.TYPE_INT, displayWidth, displayHeight, cm.getMasks());
+        wr = Raster.createWritableRaster(sm, null);
+        dstSurf = new ImageSurface(cm, wr);       
+    }
+
+    @Override
+    public void addRenderingHints(Map<?, ?> hints) {
+        if (mRh == null) {
+            mRh = (RenderingHints) hints;
+        }
+        mRh.add((RenderingHints) hints);
+    }
+
+    public float[] getMatrix() {
+        float[] f = new float[9];
+        mC.getMatrix().getValues(f);
+        return f;
+    }
+
+    /**
+     * 
+     * @return a Matrix in Android format
+     */
+    public float[] getInverseMatrix() {
+        AffineTransform af = new AffineTransform(createAWTMatrix(getMatrix()));
+        try {
+            af = af.createInverse();
+        } catch (NoninvertibleTransformException e) {
+        }
+        return createMatrix(af);
+    }
+
+    private Path getPath(Shape s) {
+        Path path = new Path();
+        PathIterator pi = s.getPathIterator(null);
+        while (pi.isDone() == false) {
+            getCurrentSegment(pi, path);
+            pi.next();
+        }
+        return path;
+    }
+
+    private void getCurrentSegment(PathIterator pi, Path path) {
+        float[] coordinates = new float[6];
+        int type = pi.currentSegment(coordinates);
+        switch (type) {
+        case PathIterator.SEG_MOVETO:
+            path.moveTo(coordinates[0], coordinates[1]);
+            break;
+        case PathIterator.SEG_LINETO:
+            path.lineTo(coordinates[0], coordinates[1]);
+            break;
+        case PathIterator.SEG_QUADTO:
+            path.quadTo(coordinates[0], coordinates[1], coordinates[2],
+                    coordinates[3]);
+            break;
+        case PathIterator.SEG_CUBICTO:
+            path.cubicTo(coordinates[0], coordinates[1], coordinates[2],
+                    coordinates[3], coordinates[4], coordinates[5]);
+            break;
+        case PathIterator.SEG_CLOSE:
+            path.close();
+            break;
+        default:
+            break;
+        }
+    }
+    
+    private Shape createShape(int[] arr) {
+        Shape s = new GeneralPath();
+        for(int i = 0; i < arr.length; i++) {
+            int type = arr[i];    
+            switch (type) {
+            case -1:
+                //MOVETO
+                ((GeneralPath)s).moveTo(arr[++i], arr[++i]);
+                break;
+            case -2:
+                //LINETO
+                ((GeneralPath)s).lineTo(arr[++i], arr[++i]);
+                break;
+            case -3:
+                //QUADTO
+                ((GeneralPath)s).quadTo(arr[++i], arr[++i], arr[++i],
+                        arr[++i]);
+                break;
+            case -4:
+                //CUBICTO
+                ((GeneralPath)s).curveTo(arr[++i], arr[++i], arr[++i],
+                        arr[++i], arr[++i], arr[++i]);
+                break;
+            case -5:
+                //CLOSE
+                return s;
+            default:
+                break;
+            }
+        }
+        return s;
+    }
+    /*
+    public int[] getPixels() {
+        return mC.getPixels();
+    }*/
+
+    public static float getRadian(float degree) {
+        return (float) ((Math.PI / 180) * degree);
+    }
+    
+    private Shape getShape() {
+        return null;
+    }
+
+    public static float getDegree(float radian) {
+        return (float) ((180 / Math.PI) * radian);
+    }
+
+    /*
+     * Degree in radian
+     */
+    public static float getEllipsisX(float degree, float princAxis) {
+        return (float) Math.cos(degree) * princAxis;
+    }
+
+    public static float getEllipsisY(float degree, float conAxis) {
+        return (float) Math.sin(degree) * conAxis;
+    }
+
+    @Override
+    public void clip(Shape s) {
+        mC.clipPath(getPath(s));
+    }
+
+    public void setCanvas(Canvas c) {
+        mC = c;
+    }
+
+    @Override
+    public void draw(Shape s) {
+        if (mP == null) {
+            mP = new Paint();
+        }
+        Paint.Style tmp = mP.getStyle();
+        mP.setStyle(Paint.Style.STROKE);
+        mC.drawPath(getPath(s), mP);
+        mP.setStyle(tmp);
+    }
+/*
+    private ArrayList getSegments(Shape s) {
+        ArrayList arr = new ArrayList();
+        PathIterator pi = s.getPathIterator(null);
+        while (pi.isDone() == false) {
+            getCurrentSegment(pi, arr);
+            pi.next();
+        }
+        return arr;
+    }
+
+    private void getCurrentSegment(PathIterator pi, ArrayList arr) {
+        float[] coordinates = new float[6];
+        int type = pi.currentSegment(coordinates);
+        switch (type) {
+        case PathIterator.SEG_MOVETO:
+            arr.add(new Integer(-1));
+            break;
+        case PathIterator.SEG_LINETO:
+            arr.add(new Integer(-2));
+            break;
+        case PathIterator.SEG_QUADTO:
+            arr.add(new Integer(-3));
+            break;
+        case PathIterator.SEG_CUBICTO:
+            arr.add(new Integer(-4));
+            break;
+        case PathIterator.SEG_CLOSE:
+            arr.add(new Integer(-5));
+            break;
+        default:
+            break;
+        }
+    }
+*/
+    /*
+     * Convenience method, not standard AWT
+     */
+    public void draw(Path s) {
+        if (mP == null) {
+            mP = new Paint();
+        }
+        Paint.Style tmp = mP.getStyle();
+        mP.setStyle(Paint.Style.STROKE);
+        s.transform(mM);
+        mC.drawPath(s, mP);
+        mP.setStyle(tmp);
+    }
+
+    @Override
+    public void drawGlyphVector(GlyphVector g, float x, float y) {
+        // TODO draw at x, y
+        // draw(g.getOutline());
+        /*
+        Matrix matrix = new Matrix();
+        matrix.setTranslate(x, y);
+        Path pth = getPath(g.getOutline());
+        pth.transform(matrix);
+        draw(pth);
+        */
+        Path path = new Path();
+        char[] c = ((AndroidGlyphVector)g).getGlyphs();
+        mP.getTextPath(c, 0, c.length, x, y, path);
+        mC.drawPath(path, mP);
+    }
+
+    @Override
+    public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
+        throw new RuntimeException("Not implemented!");
+    }
+
+    @Override
+    public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
+        throw new RuntimeException("Not implemented!");
+    }
+
+    @Override
+    public void drawString(AttributedCharacterIterator iterator, float x,
+            float y) {
+        throw new RuntimeException("AttributedCharacterIterator not supported!");
+
+    }
+
+    @Override
+    public void drawString(AttributedCharacterIterator iterator, int x, int y) {
+        throw new RuntimeException("AttributedCharacterIterator not supported!");
+
+    }
+
+    @Override
+    public void drawString(String s, float x, float y) {
+            if (mP == null) {
+                mP = new Paint();
+            }
+            Paint.Style tmp = mP.getStyle();
+
+            mP.setStyle(Paint.Style.FILL);
+            Path pth = new Path();
+            mP.getTextPath(s, 0, s.length(), x, y, pth);
+            mC.drawPath(pth, mP);
+            mP.setStyle(tmp);
+    }
+
+    @Override
+    public void drawString(String str, int x, int y) {
+            if (mP == null) {
+                mP = new Paint();
+            }
+            Paint.Style tmp = mP.getStyle();
+            mP.setStrokeWidth(0);
+
+            mC.drawText(str.toCharArray(), 0, str.toCharArray().length, x, y,
+                    mP);
+            mP.setStyle(tmp);
+    }
+
+    @Override
+    public void fill(Shape s) {
+            if (mP == null) {
+                mP = new Paint();
+            }
+            Paint.Style tmp = mP.getStyle();
+            mP.setStyle(Paint.Style.FILL);
+            mC.drawPath(getPath(s), mP);
+            mP.setStyle(tmp);
+    }
+
+    @Override
+    public Color getBackground() {
+        return mBc;
+    }
+
+    @Override
+    public Composite getComposite() {
+        throw new RuntimeException("Composite not implemented!");
+    }
+
+    @Override
+    public GraphicsConfiguration getDeviceConfiguration() {
+        return new AndroidGraphicsConfiguration();
+    }
+
+    @Override
+    public FontRenderContext getFontRenderContext() {
+        return new FontRenderContext(getTransform(), mP.isAntiAlias(), true);
+    }
+
+    @Override
+    public java.awt.Paint getPaint() {
+        throw new RuntimeException("AWT Paint not implemented in Android!");
+    }
+
+    public static Canvas getAndroidCanvas() {
+        return mC;
+    }
+    
+    public static Paint getAndroidPaint() {
+        return mP;
+    }
+
+    @Override
+    public RenderingHints getRenderingHints() {
+        return mRh;
+    }
+
+    @Override
+    public Stroke getStroke() {
+        if (mP != null) {
+            return new BasicStroke(mP.getStrokeWidth(), mP.getStrokeCap()
+                    .ordinal(), mP.getStrokeJoin().ordinal());
+        }
+        return null;
+    }
+
+    @Override
+    public AffineTransform getTransform() {
+        return new AffineTransform(createAWTMatrix(getMatrix()));
+    }
+
+    @Override
+    public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
+        // ???AWT TODO check if on stroke
+        return s.intersects(rect.getX(), rect.getY(), rect.getWidth(), rect
+                .getHeight());
+    }
+
+    @Override
+    public void rotate(double theta) {
+        mM.preRotate((float) AndroidGraphics2D
+                .getDegree((float) (RAD_360 - theta)));
+        mC.concat(mM);
+    }
+
+    @Override
+    public void rotate(double theta, double x, double y) {
+        mM.preRotate((float) AndroidGraphics2D.getDegree((float) theta),
+                (float) x, (float) y);
+        mC.concat(mM);
+    }
+
+    @Override
+    public void scale(double sx, double sy) {
+        mM.setScale((float) sx, (float) sy);
+        mC.concat(mM);
+    }
+
+    @Override
+    public void setBackground(Color color) {
+        mBc = color;
+        mC.clipRect(new Rect(0, 0, mC.getWidth(), mC.getHeight()));
+        // TODO don't limit to current clip
+        mC.drawARGB(color.getAlpha(), color.getRed(), color.getGreen(), color
+                .getBlue());
+    }
+
+    @Override
+    public void setComposite(Composite comp) {
+        throw new RuntimeException("Composite not implemented!");
+    }
+
+    public void setSpaint(Paint paint) {
+        mP = paint;
+    }
+
+    @Override
+    public void setPaint(java.awt.Paint paint) {
+        setColor((Color)paint);
+    }
+
+    @Override
+    public Object getRenderingHint(RenderingHints.Key key) {
+        if (mRh == null) {
+            return null;
+        }
+        return mRh.get(key);
+    }
+
+    @Override
+    public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) {
+        if (mRh == null) {
+            mRh = new RenderingHints(hintKey, hintValue);
+        } else {
+            mRh.put(hintKey, hintValue);
+        }
+        applyHints();
+    }
+
+    @Override
+    public void setRenderingHints(Map<?, ?> hints) {
+        mRh = (RenderingHints) hints;
+        applyHints();
+    }
+
+    private void applyHints() {
+        Object o;
+
+        // TODO do something like this:
+        /*
+         * Set s = mRh.keySet(); Iterator it = s.iterator(); while(it.hasNext()) {
+         * o = it.next(); }
+         */
+
+        // /////////////////////////////////////////////////////////////////////
+        // not supported in skia
+        /*
+         * o = mRh.get(RenderingHints.KEY_ALPHA_INTERPOLATION); if
+         * (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) { } else
+         * if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) { }
+         * else if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) { }
+         * 
+         * o = mRh.get(RenderingHints.KEY_COLOR_RENDERING); if
+         * (o.equals(RenderingHints.VALUE_COLOR_RENDER_DEFAULT)) { } else if
+         * (o.equals(RenderingHints.VALUE_COLOR_RENDER_QUALITY)) { } else if
+         * (o.equals(RenderingHints.VALUE_COLOR_RENDER_SPEED)) { }
+         * 
+         * o = mRh.get(RenderingHints.KEY_DITHERING); if
+         * (o.equals(RenderingHints.VALUE_DITHER_DEFAULT)) { } else if
+         * (o.equals(RenderingHints.VALUE_DITHER_DISABLE)) { } else if
+         * (o.equals(RenderingHints.VALUE_DITHER_ENABLE)) { }
+         * 
+         * o = mRh.get(RenderingHints.KEY_FRACTIONALMETRICS); if
+         * (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT)) { } else
+         * if (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_OFF)) { } else if
+         * (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_ON)) { }
+         * 
+         * o = mRh.get(RenderingHints.KEY_INTERPOLATION); if
+         * (o.equals(RenderingHints.VALUE_INTERPOLATION_BICUBIC)) { } else if
+         * (o.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) { } else if
+         * (o .equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) { }
+         * 
+         * o = mRh.get(RenderingHints.KEY_RENDERING); if
+         * (o.equals(RenderingHints.VALUE_RENDER_DEFAULT)) { } else if
+         * (o.equals(RenderingHints.VALUE_RENDER_QUALITY)) { } else if
+         * (o.equals(RenderingHints.VALUE_RENDER_SPEED)) { }
+         * 
+         * o = mRh.get(RenderingHints.KEY_STROKE_CONTROL); if
+         * (o.equals(RenderingHints.VALUE_STROKE_DEFAULT)) { } else if
+         * (o.equals(RenderingHints.VALUE_STROKE_NORMALIZE)) { } else if
+         * (o.equals(RenderingHints.VALUE_STROKE_PURE)) { }
+         */
+
+        o = mRh.get(RenderingHints.KEY_ANTIALIASING);
+        if (o != null) {
+            if (o.equals(RenderingHints.VALUE_ANTIALIAS_DEFAULT)) {
+                mP.setAntiAlias(false);
+            } else if (o.equals(RenderingHints.VALUE_ANTIALIAS_OFF)) {
+                mP.setAntiAlias(false);
+            } else if (o.equals(RenderingHints.VALUE_ANTIALIAS_ON)) {
+                mP.setAntiAlias(true);
+            }
+        }
+
+        o = mRh.get(RenderingHints.KEY_TEXT_ANTIALIASING);
+        if (o != null) {
+            if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT)) {
+                mP.setAntiAlias(false);
+            } else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)) {
+                mP.setAntiAlias(false);
+            } else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_ON)) {
+                mP.setAntiAlias(true);
+            }
+        }
+    }
+
+    @Override
+    public void setStroke(Stroke s) {
+        if (mP == null) {
+            mP = new Paint();
+        }
+        BasicStroke bs = (BasicStroke) s;
+        mP.setStyle(Paint.Style.STROKE);
+        mP.setStrokeWidth(bs.getLineWidth());
+
+        int cap = bs.getEndCap();
+        if (cap == 0) {
+            mP.setStrokeCap(Paint.Cap.BUTT);
+        } else if (cap == 1) {
+            mP.setStrokeCap(Paint.Cap.ROUND);
+        } else if (cap == 2) {
+            mP.setStrokeCap(Paint.Cap.SQUARE);
+        }
+
+        int join = bs.getLineJoin();
+        if (join == 0) {
+            mP.setStrokeJoin(Paint.Join.MITER);
+        } else if (join == 1) {
+            mP.setStrokeJoin(Paint.Join.ROUND);
+        } else if (join == 2) {
+            mP.setStrokeJoin(Paint.Join.BEVEL);
+        }
+    }
+
+    public static float[] createMatrix(AffineTransform Tx) {
+        double[] at = new double[9];
+        Tx.getMatrix(at);
+        float[] f = new float[at.length];
+        f[0] = (float) at[0];
+        f[1] = (float) at[2];
+        f[2] = (float) at[4];
+        f[3] = (float) at[1];
+        f[4] = (float) at[3];
+        f[5] = (float) at[5];
+        f[6] = 0;
+        f[7] = 0;
+        f[8] = 1;
+        return f;
+    }
+
+    private float[] createAWTMatrix(float[] matrix) {
+        float[] at = new float[9];
+        at[0] = matrix[0];
+        at[1] = matrix[3];
+        at[2] = matrix[1];
+        at[3] = matrix[4];
+        at[4] = matrix[2];
+        at[5] = matrix[5];
+        at[6] = 0;
+        at[7] = 0;
+        at[8] = 1;
+        return at;
+    }
+
+    public static Matrix createMatrixObj(AffineTransform Tx) {
+        Matrix m = new Matrix();
+        m.reset();
+        m.setValues(createMatrix(Tx));
+        return m;
+    }
+
+    @Override
+    public void setTransform(AffineTransform Tx) {
+        mM.reset();
+        /*
+         * if(Tx.isIdentity()) { mM = new Matrix(); }
+         */
+        mM.setValues(createMatrix(Tx));
+        Matrix m = new Matrix();
+        m.setValues(getInverseMatrix());
+        mC.concat(m);
+        mC.concat(mM);
+    }
+
+    @Override
+    public void shear(double shx, double shy) {
+        mM.setSkew((float) shx, (float) shy);
+        mC.concat(mM);
+    }
+
+    @Override
+    public void transform(AffineTransform Tx) {
+        Matrix m = new Matrix();
+        m.setValues(createMatrix(Tx));
+        mC.concat(m);
+    }
+
+    @Override
+    public void translate(double tx, double ty) {
+        mM.setTranslate((float) tx, (float) ty);
+        mC.concat(mM);
+    }
+
+    @Override
+    public void translate(int x, int y) {
+        mM.setTranslate((float) x, (float) y);
+        mC.concat(mM);
+    }
+
+    @Override
+    public void clearRect(int x, int y, int width, int height) {
+        mC.clipRect(x, y, x + width, y + height);
+        if (mBc != null) {
+            mC.drawARGB(mBc.getAlpha(), mBc.getBlue(), mBc.getGreen(), mBc
+                    .getRed());
+        } else {
+            mC.drawARGB(0xff, 0xff, 0xff, 0xff);
+        }
+    }
+
+    @Override
+    public void clipRect(int x, int y, int width, int height) {
+        int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y};
+        Shape shp = createShape(cl);
+        mCurrClip.intersect(new Area(shp));
+        mC.clipRect(new Rect(x, y, x + width, y + height), Region.Op.INTERSECT);
+    }
+
+    @Override
+    public void copyArea(int sx, int sy, int width, int height, int dx, int dy) {
+        copyArea(mC, sx, sy, width + dx, height + dy, dx, dy);
+    }
+
+    @Override
+    public Graphics create() {
+        return this;
+    }
+
+    @Override
+    public void dispose() {
+            mC = null;
+            mP = null;
+    }
+
+    @Override
+    public void drawArc(int x, int y, int width, int height, int sa, int ea) {
+            if (mP == null) {
+                mP = new Paint();
+            }
+            mP.setStrokeWidth(0);
+            mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (ea + sa),
+                       ea, true, mP);
+    }
+
+    
+    // ???AWT: only used for debuging, delete in final version
+    public void drawBitmap(Bitmap bm, float x, float y, Paint p) {
+        mC.drawBitmap(bm, x, y, null);
+    }
+    
+    @Override
+    public boolean drawImage(Image image, int x, int y, Color bgcolor,
+            ImageObserver imageObserver) {
+
+        if(image == null) {
+            return true;
+        }
+
+        boolean done = false;
+        boolean somebits = false;
+        Surface srcSurf = null;
+        if(image instanceof OffscreenImage){
+            OffscreenImage oi = (OffscreenImage) image;
+            if((oi.getState() & ImageObserver.ERROR) != 0) {
+                return false;
+            }
+            done = oi.prepareImage(imageObserver);
+            somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+            srcSurf = oi.getImageSurface();
+        }else{
+            done = true;
+            srcSurf = Surface.getImageSurface(image);
+        }
+
+        if(done || somebits) {
+            int w = srcSurf.getWidth();
+            int h = srcSurf.getHeight();
+            
+            blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, (AffineTransform) transform.clone(),
+                    composite, bgcolor, clip);
+        }
+        return done;
+    }
+
+    @Override
+    public boolean drawImage(Image image, int x, int y, ImageObserver imageObserver) {
+        return drawImage(image, x, y, null, imageObserver);
+    }
+
+    @Override
+    public boolean drawImage(Image image, int x, int y, int width, int height,
+            Color bgcolor, ImageObserver imageObserver) {
+
+        if(image == null) {
+            return true;
+        }
+        if(width == 0 || height == 0) {
+            return true;
+        }
+
+        boolean done = false;
+        boolean somebits = false;
+        Surface srcSurf = null;
+
+        if(image instanceof OffscreenImage){
+            OffscreenImage oi = (OffscreenImage) image;
+            if((oi.getState() & ImageObserver.ERROR) != 0) {
+                return false;
+            }
+            done = oi.prepareImage(imageObserver);
+            somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+            srcSurf = oi.getImageSurface();
+        }else{
+            done = true;
+            srcSurf = Surface.getImageSurface(image);
+        }
+
+        if(done || somebits) {
+            int w = srcSurf.getWidth();
+            int h = srcSurf.getHeight();
+            if(w == width && h == height){
+                blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+                        (AffineTransform) transform.clone(),
+                        composite, bgcolor, clip);
+            }else{
+                AffineTransform xform = new AffineTransform();
+                xform.setToScale((float)width / w, (float)height / h);
+                blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+                        (AffineTransform) transform.clone(),
+                        xform, composite, bgcolor, clip);
+            }
+        }
+        return done;
+    }
+
+    @Override
+    public boolean drawImage(Image image, int x, int y, int width, int height,
+            ImageObserver imageObserver) {
+        return drawImage(image, x, y, width, height, null, imageObserver);
+    }
+
+    @Override
+    public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
+            int sx1, int sy1, int sx2, int sy2, Color bgcolor,
+            ImageObserver imageObserver) {
+
+        if(image == null) {
+            return true;
+        }
+        if(dx1 == dx2 || dy1 == dy2 || sx1 == sx2 || sy1 == sy2) {
+            return true;
+        }
+
+        boolean done = false;
+        boolean somebits = false;
+        Surface srcSurf = null;
+        if(image instanceof OffscreenImage){
+            OffscreenImage oi = (OffscreenImage) image;
+            if((oi.getState() & ImageObserver.ERROR) != 0) {
+                return false;
+            }
+            done = oi.prepareImage(imageObserver);
+            somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+            srcSurf = oi.getImageSurface();
+        }else{
+            done = true;
+            srcSurf = Surface.getImageSurface(image);
+        }
+
+        if(done || somebits) {
+
+            int dstX = dx1;
+            int dstY = dy1;
+            int srcX = sx1;
+            int srcY = sy1;
+
+            int dstW = dx2 - dx1;
+            int dstH = dy2 - dy1;
+            int srcW = sx2 - sx1;
+            int srcH = sy2 - sy1;
+
+            if(srcW == dstW && srcH == dstH){
+                blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
+                        (AffineTransform) transform.clone(),
+                        composite, bgcolor, clip);
+            }else{
+                AffineTransform xform = new AffineTransform();
+                xform.setToScale((float)dstW / srcW, (float)dstH / srcH);
+                blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
+                        (AffineTransform) transform.clone(),
+                        xform, composite, bgcolor, clip);
+            }
+        }
+        return done;
+    }
+
+    @Override
+    public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
+            int sx1, int sy1, int sx2, int sy2, ImageObserver imageObserver) {
+
+        return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null,
+                imageObserver);
+     }
+
+    @Override
+    public void drawImage(BufferedImage bufImage, BufferedImageOp op,
+            int x, int y) {
+
+        if(bufImage == null) {
+            return;
+        }
+
+        if(op == null) {
+            drawImage(bufImage, x, y, null);
+        } else if(op instanceof AffineTransformOp){
+            AffineTransformOp atop = (AffineTransformOp) op;
+            AffineTransform xform = atop.getTransform();
+            Surface srcSurf = Surface.getImageSurface(bufImage);
+            int w = srcSurf.getWidth();
+            int h = srcSurf.getHeight();
+            blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+                    (AffineTransform) transform.clone(), xform,
+                    composite, null, clip);
+        } else {
+            bufImage = op.filter(bufImage, null);
+            Surface srcSurf = Surface.getImageSurface(bufImage);
+            int w = srcSurf.getWidth();
+            int h = srcSurf.getHeight();
+            blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+                    (AffineTransform) transform.clone(),
+                    composite, null, clip);
+        }
+    }
+
+    @Override
+    public boolean drawImage(Image image, AffineTransform trans,
+            ImageObserver imageObserver) {
+
+        if(image == null) {
+            return true;
+        }
+        if(trans == null || trans.isIdentity()) {
+            return drawImage(image, 0, 0, imageObserver);
+        }
+
+        boolean done = false;
+        boolean somebits = false;
+        Surface srcSurf = null;
+        if(image instanceof OffscreenImage){
+            OffscreenImage oi = (OffscreenImage) image;
+            if((oi.getState() & ImageObserver.ERROR) != 0) {
+                return false;
+            }
+            done = oi.prepareImage(imageObserver);
+            somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+            srcSurf = oi.getImageSurface();
+        }else{
+            done = true;
+            srcSurf = Surface.getImageSurface(image);
+        }
+
+        if(done || somebits) {
+            int w = srcSurf.getWidth();
+            int h = srcSurf.getHeight();
+            AffineTransform xform = (AffineTransform) transform.clone();
+            xform.concatenate(trans);
+            blitter.blit(0, 0, srcSurf, 0, 0, dstSurf, w, h, xform, composite,
+                    null, clip);
+        }
+        return done;
+    }
+        
+    @Override
+    public void drawLine(int x1, int y1, int x2, int y2) {
+        if (mP == null) {
+            mP = new Paint();
+        }
+            mC.drawLine(x1, y1, x2, y2, mP);
+    }
+
+    @Override
+    public void drawOval(int x, int y, int width, int height) {
+            if (mP == null) {
+                mP = new Paint();
+            }
+            mP.setStyle(Paint.Style.STROKE);
+            mC.drawOval(new RectF(x, y, x + width, y + height), mP);
+    }
+
+    @Override
+    public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) {
+            if (mP == null) {
+                mP = new Paint();
+            }
+            mC.drawLine(xpoints[npoints - 1], ypoints[npoints - 1], xpoints[0],
+                    ypoints[0], mP);
+            for (int i = 0; i < npoints - 1; i++) {
+                mC.drawLine(xpoints[i], ypoints[i], xpoints[i + 1],
+                        ypoints[i + 1], mP);
+            }
+    }
+
+    @Override
+    public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) {
+        for (int i = 0; i < npoints - 1; i++) {
+            drawLine(xpoints[i], ypoints[i], xpoints[i + 1], ypoints[i + 1]);
+        }
+
+    }
+
+    @Override
+    public void drawRoundRect(int x, int y, int width, int height,
+            int arcWidth, int arcHeight) {
+            if (mP == null) {
+                mP = new Paint();
+            }
+            mC.drawRoundRect(new RectF(x, y, width, height), arcWidth,
+                    arcHeight, mP);
+    }
+
+    @Override
+    public void fillArc(int x, int y, int width, int height, int sa, int ea) {
+            if (mP == null) {
+                mP = new Paint();
+            }
+            
+            Paint.Style tmp = mP.getStyle();
+            mP.setStyle(Paint.Style.FILL_AND_STROKE);
+            mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (sa + ea),
+                    ea, true, mP);
+            
+            mP.setStyle(tmp);
+    }
+
+    @Override
+    public void fillOval(int x, int y, int width, int height) {
+            if (mP == null) {
+                mP = new Paint();
+            }
+            Paint.Style tmp = mP.getStyle();
+            mP.setStyle(Paint.Style.FILL);
+            mC.drawOval(new RectF(x, y, x + width, y + height), mP);
+            mP.setStyle(tmp);
+    }
+
+    @Override
+    public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) {
+            if (mP == null) {
+                mP = new Paint();
+            }
+            Paint.Style tmp = mP.getStyle();
+            mC.save(Canvas.CLIP_SAVE_FLAG);
+
+            mP.setStyle(Paint.Style.FILL);
+
+            GeneralPath filledPolygon = new GeneralPath(
+                    GeneralPath.WIND_EVEN_ODD, npoints);
+            filledPolygon.moveTo(xpoints[0], ypoints[0]);
+            for (int index = 1; index < xpoints.length; index++) {
+                filledPolygon.lineTo(xpoints[index], ypoints[index]);
+            }
+            filledPolygon.closePath();
+            Path path = getPath(filledPolygon);
+            mC.clipPath(path);
+            mC.drawPath(path, mP);
+
+            mP.setStyle(tmp);
+            mC.restore();
+    }
+
+    @Override
+    public void fillRect(int x, int y, int width, int height) {
+            if (mP == null) {
+                mP = new Paint();
+            }
+            Paint.Style tmp = mP.getStyle();
+            mP.setStyle(Paint.Style.FILL);
+            mC.drawRect(new Rect(x, y, x + width, y + height), mP);
+            mP.setStyle(tmp);
+    }
+
+    @Override
+    public void drawRect(int x, int y, int width, int height) {
+        int[] xpoints = { x, x, x + width, x + width };
+        int[] ypoints = { y, y + height, y + height, y };
+        drawPolygon(xpoints, ypoints, 4);
+    }
+
+    @Override
+    public void fillRoundRect(int x, int y, int width, int height,
+            int arcWidth, int arcHeight) {
+            if (mP == null) {
+                mP = new Paint();
+            }
+            mP.setStyle(Paint.Style.FILL);
+            mC.drawRoundRect(new RectF(x, y, x + width, y + height), arcWidth,
+                    arcHeight, mP);
+    }
+
+    @Override
+    public Shape getClip() {
+        return mCurrClip;
+    }
+
+    @Override
+    public Rectangle getClipBounds() {
+            Rect r = mC.getClipBounds();
+            return new Rectangle(r.left, r.top, r.width(), r.height());
+    }
+
+    @Override
+    public Color getColor() {
+        if (mP != null) {
+            return new Color(mP.getColor());
+        }
+        return null;
+    }
+
+    @Override
+    public Font getFont() {
+        return mFnt;
+    }
+
+    @Override
+    public FontMetrics getFontMetrics(Font font) {
+        mFm = new FontMetricsImpl(font);
+        return mFm;
+    }
+
+    @Override
+    public void setClip(int x, int y, int width, int height) {
+        int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y};
+        mCurrClip = new Area(createShape(cl));
+        mC.clipRect(x, y, x + width, y + height, Region.Op.REPLACE);
+
+    }
+
+    @Override
+    public void setClip(Shape clip) {
+        mCurrClip = new Area(clip);
+        mC.clipPath(getPath(clip), Region.Op.REPLACE);
+    }
+
+    @Override
+    public void setColor(Color c) {
+        if (mP == null) {
+            mP = new Paint();
+        }
+        mP.setColor(c.getRGB());
+    }
+
+    /**
+     * Font mapping:
+     * 
+     * Family:
+     * 
+     * Android         AWT
+     * -------------------------------------
+     * serif           Serif / TimesRoman
+     * sans-serif      SansSerif / Helvetica
+     * monospace       Monospaced / Courier
+     * 
+     * Style:
+     * 
+     * Android            AWT
+     * -------------------------------------
+     * normal          Plain
+     * bold            bold
+     * italic          italic
+     * 
+     */
+    @Override
+    public void setFont(Font font) {
+        if (font == null) {
+            return;
+        }
+        if (mP == null) {
+            mP = new Paint();
+        }
+
+        mFnt = font;
+        Typeface tf = null;
+        int sty = font.getStyle();
+        String nam = font.getName();
+        String aF = "";
+        if (nam != null) {
+            if (nam.equalsIgnoreCase("Serif")
+                    || nam.equalsIgnoreCase("TimesRoman")) {
+                aF = "serif";
+            } else if (nam.equalsIgnoreCase("SansSerif")
+                    || nam.equalsIgnoreCase("Helvetica")) {
+                aF = "sans-serif";
+            } else if (nam.equalsIgnoreCase("Monospaced")
+                    || nam.equalsIgnoreCase("Courier")) {
+                aF = "monospace";
+            }
+        }
+
+        switch (sty) {
+        case Font.PLAIN:
+            tf = Typeface.create(aF, Typeface.NORMAL);
+            break;
+        case Font.BOLD:
+            tf = Typeface.create(aF, Typeface.BOLD);
+            break;
+        case Font.ITALIC:
+            tf = Typeface.create(aF, Typeface.ITALIC);
+            break;
+        case Font.BOLD | Font.ITALIC:
+            tf = Typeface.create(aF, Typeface.BOLD_ITALIC);
+            break;
+        default:
+            tf = Typeface.DEFAULT;
+        }
+
+        mP.setTextSize(font.getSize());
+        mP.setTypeface(tf);
+    }
+
+    @Override
+    public void drawBytes(byte[] data, int offset, int length, int x, int y) {
+        drawString(new String(data, offset, length), x, y);
+    }
+    
+    @Override
+    public void drawPolygon(Polygon p) {
+        drawPolygon(p.xpoints, p.ypoints, p.npoints);
+    }
+
+    @Override
+    public void fillPolygon(Polygon p) {
+        fillPolygon(p.xpoints, p.ypoints, p.npoints);
+    }
+    
+    @Override
+    public Rectangle getClipBounds(Rectangle r) {
+        Shape clip = getClip();
+        if (clip != null) {
+            Rectangle b = clip.getBounds();
+            r.x = b.x;
+            r.y = b.y;
+            r.width = b.width;
+            r.height = b.height;
+        }
+        return r;
+    }
+    
+    @Override
+    public boolean hitClip(int x, int y, int width, int height) {
+        return getClipBounds().intersects(new Rectangle(x, y, width, height));
+    }
+    
+    @Override
+    public void drawChars(char[] data, int offset, int length, int x, int y) {
+        mC.drawText(data, offset, length, x, y, mP);
+    }
+    
+    @Override
+    public void setPaintMode() {
+        if (mP == null) {
+            mP = new Paint();
+        }
+        mP.setXfermode(null);
+    }
+
+    @Override
+    public void setXORMode(Color color) {
+        if (mP == null) {
+            mP = new Paint();
+        }
+        mP.setXfermode(new PixelXorXfermode(color.getRGB()));
+    }
+    
+    @Override
+    public void fill3DRect(int x, int y, int width, int height, boolean raised) {
+        Color color = getColor();
+        Color colorUp, colorDown;
+        if (raised) {
+            colorUp = color.brighter();
+            colorDown = color.darker();
+            setColor(color);
+        } else {
+            colorUp = color.darker();
+            colorDown = color.brighter();
+            setColor(colorUp);
+        }
+
+        width--;
+        height--;
+        fillRect(x+1, y+1, width-1, height-1);
+
+        setColor(colorUp);
+        fillRect(x, y, width, 1);
+        fillRect(x, y+1, 1, height);
+
+        setColor(colorDown);
+        fillRect(x+width, y, 1, height);
+        fillRect(x+1, y+height, width, 1);
+    }
+    
+    @Override
+    public void draw3DRect(int x, int y, int width, int height, boolean raised) {
+        Color color = getColor();
+        Color colorUp, colorDown;
+        if (raised) {
+            colorUp = color.brighter();
+            colorDown = color.darker();
+        } else {
+            colorUp = color.darker();
+            colorDown = color.brighter();
+        }
+
+        setColor(colorUp);
+        fillRect(x, y, width, 1);
+        fillRect(x, y+1, 1, height);
+
+        setColor(colorDown);
+        fillRect(x+width, y, 1, height);
+        fillRect(x+1, y+height, width, 1);
+    }
+
+    public void copyArea(Canvas canvas, int sx, int sy, int width, int height, int dx, int dy) {
+        sx += getTransform().getTranslateX();
+        sy += getTransform().getTranslateY();
+
+        NativeUtils.nativeScrollRect(canvas,
+                new Rect(sx, sy, sx + width, sy + height),
+                dx, dy);
+    }
+}
diff --git a/awt/com/android/internal/awt/AndroidGraphicsConfiguration.java b/awt/com/android/internal/awt/AndroidGraphicsConfiguration.java
new file mode 100644
index 0000000..0c888cd
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidGraphicsConfiguration.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2007, 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.android.internal.awt;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.VolatileImage;
+
+import android.graphics.Canvas;
+
+public class AndroidGraphicsConfiguration extends GraphicsConfiguration {
+
+    @Override
+    public BufferedImage createCompatibleImage(int width, int height) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public BufferedImage createCompatibleImage(int width, int height,
+            int transparency) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public VolatileImage createCompatibleVolatileImage(int width, int height) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public VolatileImage createCompatibleVolatileImage(int width, int height,
+            int transparency) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Rectangle getBounds() {
+        Canvas c = AndroidGraphics2D.getAndroidCanvas();
+        if(c != null)
+            return new Rectangle(0, 0, c.getWidth(), c.getHeight());
+        return null;
+    }
+
+    @Override
+    public ColorModel getColorModel() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public ColorModel getColorModel(int transparency) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public AffineTransform getDefaultTransform() {
+        return new AffineTransform();
+    }
+
+    @Override
+    public GraphicsDevice getDevice() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public AffineTransform getNormalizingTransform() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}
diff --git a/awt/com/android/internal/awt/AndroidGraphicsFactory.java b/awt/com/android/internal/awt/AndroidGraphicsFactory.java
new file mode 100644
index 0000000..ca255b5
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidGraphicsFactory.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2007, 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.android.internal.awt;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.peer.FontPeer;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.font.AndroidFont;
+import org.apache.harmony.awt.gl.font.FontManager;
+import org.apache.harmony.awt.gl.font.FontMetricsImpl;
+import org.apache.harmony.awt.gl.font.AndroidFontManager;
+import org.apache.harmony.awt.wtk.NativeWindow;
+import org.apache.harmony.awt.wtk.WindowFactory;
+import org.apache.harmony.awt.gl.CommonGraphics2DFactory;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.content.Context;
+
+public class AndroidGraphicsFactory extends CommonGraphics2DFactory {
+    
+    public GraphicsEnvironment createGraphicsEnvironment(WindowFactory wf) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Font embedFont(String fontFilePath) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public FontManager getFontManager() {
+        return AndroidFontManager.inst;
+    }
+
+    public FontMetrics getFontMetrics(Font font) {
+        return new FontMetricsImpl(font);
+    }
+
+    public FontPeer getFontPeer(Font font) {
+        //return getFontManager().getFontPeer(font.getName(), font.getStyle(), font.getSize());
+        return new AndroidFont(font.getName(), font.getStyle(), font.getSize());
+    }
+
+    public Graphics2D getGraphics2D(NativeWindow win, int translateX,
+            int translateY, MultiRectArea clip) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Graphics2D getGraphics2D(NativeWindow win, int translateX,
+            int translateY, int width, int height) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Graphics2D getGraphics2D(Context ctx, Canvas c, Paint p) {
+        return AndroidGraphics2D.getInstance(ctx, c, p);
+    }
+
+    public Graphics2D getGraphics2D(Canvas c, Paint p) {
+        throw new RuntimeException("Not supported!");
+    }
+
+    public Graphics2D getGraphics2D() {
+        return AndroidGraphics2D.getInstance();
+    }
+
+}
diff --git a/awt/com/android/internal/awt/AndroidImageDecoder.java b/awt/com/android/internal/awt/AndroidImageDecoder.java
new file mode 100644
index 0000000..81b2e1a
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidImageDecoder.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2007, 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.android.internal.awt;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+//import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.IndexColorModel;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+
+import org.apache.harmony.awt.gl.image.DecodingImageSource;
+import org.apache.harmony.awt.gl.image.ImageDecoder;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class AndroidImageDecoder extends ImageDecoder {
+    
+    private static final int hintflags =
+        ImageConsumer.SINGLEFRAME | // PNG is a static image
+        ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible
+        ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines
+    
+    // Each pixel is a grayscale sample.
+    private static final int PNG_COLOR_TYPE_GRAY = 0;
+    // Each pixel is an R,G,B triple.
+    private static final int PNG_COLOR_TYPE_RGB = 2;
+    // Each pixel is a palette index, a PLTE chunk must appear.
+    private static final int PNG_COLOR_TYPE_PLTE = 3;
+    // Each pixel is a grayscale sample, followed by an alpha sample.
+    private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4;
+    // Each pixel is an R,G,B triple, followed by an alpha sample.
+    private static final int PNG_COLOR_TYPE_RGBA = 6;
+    
+    private static final int NB_OF_LINES_PER_CHUNK = 1;  // 0 = full image
+    
+    Bitmap bm;  // The image as decoded by Android
+    
+    // Header information
+    int imageWidth; // Image size
+    int imageHeight;  
+    int colorType;  // One of the PNG_ constants from above
+    int bitDepth;   // Number of bits per color
+    byte cmap[];    // The color palette for index color models
+    ColorModel model;  // The corresponding AWT color model
+    
+    boolean transferInts; // Is transfer of type int or byte?
+    int dataElementsPerPixel;
+
+    // Buffers for decoded image data
+    byte byteOut[];
+    int intOut[];
+
+    
+    public AndroidImageDecoder(DecodingImageSource src, InputStream is) {
+        super(src, is);
+        dataElementsPerPixel = 1;
+    }
+
+    @Override
+    /**
+     * All the decoding is done in Android
+     * 
+     * AWT???: Method returns only once the image is completly 
+     * decoded; decoding is not done asynchronously
+     */
+    public void decodeImage() throws IOException {
+        try {
+            bm = BitmapFactory.decodeStream(inputStream);
+            if (bm == null) {
+                throw new IOException("Input stream empty and no image cached");
+            }
+
+            // Check size
+            imageWidth = bm.getWidth();
+            imageHeight = bm.getHeight();
+            if (imageWidth < 0 || imageHeight < 0 ) {
+                throw new RuntimeException("Illegal image size: " 
+                        + imageWidth + ", " + imageHeight);
+            }
+            
+            // We got the image fully decoded; now send all image data to AWT
+            setDimensions(imageWidth, imageHeight);
+            model = createColorModel();
+            setColorModel(model);
+            setHints(hintflags);
+            setProperties(new Hashtable<Object, Object>()); // Empty
+            sendPixels(NB_OF_LINES_PER_CHUNK != 0 ? NB_OF_LINES_PER_CHUNK : imageHeight);
+            imageComplete(ImageConsumer.STATICIMAGEDONE);        
+        } catch (IOException e) {
+            throw e;
+        } catch (RuntimeException e) {
+            imageComplete(ImageConsumer.IMAGEERROR);
+            throw e;
+        } finally {
+            closeStream();
+        }
+    }
+    
+    /**
+     * Create the AWT color model
+     *
+     * ???AWT: Android Bitmaps are always of type: ARGB-8888-Direct color model
+     * 
+     * However, we leave the code here for a more powerfull decoder 
+     * that returns a native model, and the conversion is then handled
+     * in AWT. With such a decoder, we would need to get the colorType, 
+     * the bitDepth, (and the color palette for an index color model)
+     * from the image and construct the correct color model here.
+     */
+    private ColorModel createColorModel() {
+        ColorModel cm = null;
+        int bmModel = 5; // TODO This doesn't exist: bm.getColorModel();
+        cmap = null;
+           
+        switch (bmModel) {
+        // A1_MODEL
+        case 1: 
+            colorType = PNG_COLOR_TYPE_GRAY;
+            bitDepth = 1;
+            break;
+            
+        // A8_MODEL
+        case 2:
+            colorType = PNG_COLOR_TYPE_GRAY_ALPHA;
+            bitDepth = 8;
+            break;
+            
+        // INDEX8_MODEL
+        // RGB_565_MODEL
+        // ARGB_8888_MODEL
+        case 3:
+        case 4: 
+        case 5: 
+            colorType = bm.hasAlpha() ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB;
+            bitDepth = 8;
+            break;
+
+        default:
+            // awt.3C=Unknown PNG color type
+            throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+        }
+        
+        switch (colorType) {
+        
+            case PNG_COLOR_TYPE_GRAY: {
+                if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 &&  bitDepth != 1) {
+                    // awt.3C=Unknown PNG color type
+                    throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+                }
+
+                // Create gray color model
+                int numEntries = 1 << bitDepth;
+                int scaleFactor = 255 / (numEntries-1);
+                byte comps[] = new byte[numEntries];
+                for (int i = 0; i < numEntries; i++) {
+                    comps[i] = (byte) (i * scaleFactor);
+                }
+                cm = new IndexColorModel(bitDepth, numEntries, comps, comps, comps);
+
+                transferInts = false;
+                break;
+            }
+
+            case PNG_COLOR_TYPE_RGB: {
+                if (bitDepth != 8) {
+                    // awt.3C=Unknown PNG color type
+                    throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+                }
+                
+                cm = new DirectColorModel(24, 0xff0000, 0xFF00, 0xFF);
+                
+                transferInts = true;
+                break;
+            }
+
+            case PNG_COLOR_TYPE_PLTE: {
+                if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) {
+                    // awt.3C=Unknown PNG color type
+                    throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+                }
+
+                if (cmap == null) {
+                    throw new IllegalStateException("Palette color type is not supported");
+                }
+
+                cm = new IndexColorModel(bitDepth, cmap.length / 3, cmap, 0, false);
+
+                transferInts = false;
+                break;
+            }
+
+            case PNG_COLOR_TYPE_GRAY_ALPHA: {
+                if (bitDepth != 8) {
+                    // awt.3C=Unknown PNG color type
+                    throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+                }
+
+                cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
+                        true, false,
+                        Transparency.TRANSLUCENT,
+                        DataBuffer.TYPE_BYTE);
+
+                transferInts = false;
+                dataElementsPerPixel = 2;
+                break;
+            }
+
+            case PNG_COLOR_TYPE_RGBA: {
+                if (bitDepth != 8) {
+                    // awt.3C=Unknown PNG color type
+                    throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+                }
+
+                cm = ColorModel.getRGBdefault();
+
+                transferInts = true;
+                break;
+            }
+            default:
+                // awt.3C=Unknown PNG color type
+                throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+        }
+        
+        return cm;
+    }
+    
+    private void sendPixels(int nbOfLinesPerChunk) {
+        int w = imageWidth;
+        int h = imageHeight;
+        int n = 1;
+        if (nbOfLinesPerChunk > 0 && nbOfLinesPerChunk <= h) {
+            n = nbOfLinesPerChunk;
+        }
+        
+        if (transferInts) {
+            // Create output buffer
+            intOut = new int[w * n];
+            for (int yi = 0; yi < h; yi += n) {
+                // Last chunk might contain less liness
+                if (n > 1 && h - yi < n ) {
+                    n = h - yi;
+                }
+                bm.getPixels(intOut, 0, w, 0, yi, w, n);
+                setPixels(0, yi, w, n, model, intOut, 0, w);
+            }
+        } else {
+            // Android bitmaps always store ints (ARGB-8888 direct model)
+            throw new RuntimeException("Byte transfer not supported");
+        }
+    }
+    
+}
diff --git a/awt/com/android/internal/awt/AndroidJavaBlitter.java b/awt/com/android/internal/awt/AndroidJavaBlitter.java
new file mode 100644
index 0000000..423b534
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidJavaBlitter.java
@@ -0,0 +1,536 @@
+/*
+ * Copyright 2007, 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.android.internal.awt;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.XORComposite;
+import org.apache.harmony.awt.gl.render.Blitter;
+
+import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferInt;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+public class AndroidJavaBlitter implements Blitter {
+
+    private Canvas canvas;
+    private Paint paint;
+    private int colorCache;
+        
+    public AndroidJavaBlitter(Canvas c) {
+        this.canvas = c;
+        this.paint = new Paint();
+        this.paint.setStrokeWidth(1);
+    }
+    
+    /**
+     * Instead of multiplication and division we are using values from
+     * Lookup tables.
+     */
+    static byte mulLUT[][]; // Lookup table for multiplication
+    static byte divLUT[][]; // Lookup table for division
+
+    static{
+        mulLUT = new byte[256][256];
+        for(int i = 0; i < 256; i++){
+            for(int j = 0; j < 256; j++){
+                mulLUT[i][j] = (byte)((float)(i * j)/255 + 0.5f);
+            }
+        }
+        divLUT = new byte[256][256];
+        for(int i = 1; i < 256; i++){
+            for(int j = 0; j < i; j++){
+                divLUT[i][j] = (byte)(((float)j / 255) / ((float)i/ 255) * 255 + 0.5f);
+            }
+            for(int j = i; j < 256; j++){
+                divLUT[i][j] = (byte)255;
+            }
+        }
+    }
+
+    final static int AlphaCompositeMode = 1;
+    final static int XORMode = 2;
+
+    public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, AffineTransform sysxform,
+            AffineTransform xform, Composite comp, Color bgcolor,
+            MultiRectArea clip) {
+        
+        if(xform == null){
+            blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+                    sysxform, comp, bgcolor, clip);
+        }else{
+            double scaleX = xform.getScaleX();
+            double scaleY = xform.getScaleY();
+            double scaledX = dstX / scaleX;
+            double scaledY = dstY / scaleY;
+            AffineTransform at = new AffineTransform();
+            at.setToTranslation(scaledX, scaledY);
+            xform.concatenate(at);
+            sysxform.concatenate(xform);
+            blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height,
+                    sysxform, comp, bgcolor, clip);
+        }
+
+    }
+
+    public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, AffineTransform sysxform,
+            Composite comp, Color bgcolor, MultiRectArea clip) {
+        
+        if(sysxform == null) {
+            sysxform = new AffineTransform();
+        }
+        int type = sysxform.getType();
+        switch(type){
+            case AffineTransform.TYPE_TRANSLATION:
+                dstX += sysxform.getTranslateX();
+                dstY += sysxform.getTranslateY();
+            case AffineTransform.TYPE_IDENTITY:
+                simpleBlit(srcX, srcY, srcSurf, dstX, dstY, dstSurf,
+                        width, height, comp, bgcolor, clip);
+                break;
+            default:
+                int srcW = srcSurf.getWidth();
+                int srcH = srcSurf.getHeight();
+
+                int w = srcX + width < srcW ? width : srcW - srcX;
+                int h = srcY + height < srcH ? height : srcH - srcY;
+
+                ColorModel srcCM = srcSurf.getColorModel();
+                Raster srcR = srcSurf.getRaster().createChild(srcX, srcY,
+                        w, h, 0, 0, null);
+
+                ColorModel dstCM = dstSurf.getColorModel();
+                WritableRaster dstR = dstSurf.getRaster();
+
+                transformedBlit(srcCM, srcR, 0, 0, dstCM, dstR, dstX, dstY, w, h,
+                        sysxform, comp, bgcolor, clip);
+
+        }
+    }
+
+    public void simpleBlit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, Composite comp,
+            Color bgcolor, MultiRectArea clip) {
+
+        // TODO It's possible, though unlikely that we might encounter non-int[]
+        // data buffers. In this case the following code needs to have several
+        // branches that take this into account.
+        data = (DataBufferInt)srcSurf.getRaster().getDataBuffer();
+        int[] pixels = data.getData();
+        if (!srcSurf.getColorModel().hasAlpha()) {
+            // This wouldn't be necessary if Android supported RGB_888.
+            for (int i = 0; i < pixels.length; i++) {
+                pixels[i] = pixels[i] | 0xff000000;
+            }
+        }
+        bmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
+        canvas.drawBitmap(bmap, dstX, dstY, paint);
+    }
+    
+    public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, Composite comp,
+            Color bgcolor, MultiRectArea clip) {
+
+        javaBlt(srcX, srcY, srcSurf.getWidth(), srcSurf.getHeight(),
+                srcSurf.getColorModel(), srcSurf.getRaster(), dstX, dstY,
+                dstSurf.getWidth(), dstSurf.getHeight(),
+                dstSurf.getColorModel(), dstSurf.getRaster(),
+                width, height, comp, bgcolor, clip);
+
+    }
+    
+    public void javaBlt(int srcX, int srcY, int srcW, int srcH,
+            ColorModel srcCM, Raster srcRast, int dstX, int dstY,
+            int dstW, int dstH, ColorModel dstCM, WritableRaster dstRast,
+            int width, int height, Composite comp, Color bgcolor,
+            MultiRectArea clip){
+        
+        int srcX2 = srcW - 1;
+        int srcY2 = srcH - 1;
+        int dstX2 = dstW - 1;
+        int dstY2 = dstH - 1;
+
+        if(srcX < 0){
+            width += srcX;
+            srcX = 0;
+        }
+        if(srcY < 0){
+            height += srcY;
+            srcY = 0;
+        }
+
+        if(dstX < 0){
+            width += dstX;
+            srcX -= dstX;
+            dstX = 0;
+        }
+        if(dstY < 0){
+            height += dstY;
+            srcY -= dstY;
+            dstY = 0;
+        }
+
+        if(srcX > srcX2 || srcY > srcY2) {
+            return;
+        }
+        if(dstX > dstX2 || dstY > dstY2) {
+            return;
+        }
+
+        if(srcX + width > srcX2) {
+            width = srcX2 - srcX + 1;
+        }
+        if(srcY + height > srcY2) {
+            height = srcY2 - srcY + 1;
+        }
+        if(dstX + width > dstX2) {
+            width = dstX2 - dstX + 1;
+        }
+        if(dstY + height > dstY2) {
+            height = dstY2 - dstY + 1;
+        }
+
+        if(width <= 0 || height <= 0) {
+            return;
+        }
+
+        int clipRects[];
+        if(clip != null) {
+            clipRects = clip.rect;
+        } else {
+            clipRects = new int[]{5, 0, 0, dstW - 1, dstH - 1};
+        }
+
+        boolean isAlphaComp = false;
+        int rule = 0;
+        float alpha = 0;
+        boolean isXORComp = false;
+        Color xorcolor = null;
+        CompositeContext cont = null;
+
+        if(comp instanceof AlphaComposite){
+            isAlphaComp = true;
+            AlphaComposite ac = (AlphaComposite) comp;
+            rule = ac.getRule();
+            alpha = ac.getAlpha();
+        }else if(comp instanceof XORComposite){
+            isXORComp = true;
+            XORComposite xcomp = (XORComposite) comp;
+            xorcolor = xcomp.getXORColor();
+        }else{
+            cont = comp.createContext(srcCM, dstCM, null);
+        }
+
+        for(int i = 1; i < clipRects[0]; i += 4){
+            int _sx = srcX;
+            int _sy = srcY;
+
+            int _dx = dstX;
+            int _dy = dstY;
+
+            int _w = width;
+            int _h = height;
+
+            int cx = clipRects[i];          // Clipping left top X
+            int cy = clipRects[i + 1];      // Clipping left top Y
+            int cx2 = clipRects[i + 2];     // Clipping right bottom X
+            int cy2 = clipRects[i + 3];     // Clipping right bottom Y
+
+            if(_dx > cx2 || _dy > cy2 || dstX2 < cx || dstY2 < cy) {
+                continue;
+            }
+
+            if(cx > _dx){
+                int shx = cx - _dx;
+                _w -= shx;
+                _dx = cx;
+                _sx += shx;
+            }
+
+            if(cy > _dy){
+                int shy = cy - _dy;
+                _h -= shy;
+                _dy = cy;
+                _sy += shy;
+            }
+
+            if(_dx + _w > cx2 + 1){
+                _w = cx2 - _dx + 1;
+            }
+
+            if(_dy + _h > cy2 + 1){
+                _h = cy2 - _dy + 1;
+            }
+
+            if(_sx > srcX2 || _sy > srcY2) {
+                continue;
+            }
+
+            if(isAlphaComp){
+                alphaCompose(_sx, _sy, srcCM, srcRast, _dx, _dy,
+                        dstCM, dstRast, _w, _h, rule, alpha, bgcolor);
+            }else if(isXORComp){
+                xorCompose(_sx, _sy, srcCM, srcRast, _dx, _dy,
+                        dstCM, dstRast, _w, _h, xorcolor);
+            }else{
+                Raster sr = srcRast.createChild(_sx, _sy, _w, _h, 0, 0, null);
+                WritableRaster dr = dstRast.createWritableChild(_dx, _dy,
+                        _w, _h, 0, 0, null);
+                cont.compose(sr, dr, dr);
+            }
+        }
+        
+    }
+
+    DataBufferInt data;
+    Bitmap bmap, bmp;
+    
+    void alphaCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast,
+            int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast,
+            int width, int height, int rule, float alpha, Color bgcolor){
+        
+        Object srcPixel = getTransferArray(srcRast, 1);
+        data = (DataBufferInt)srcRast.getDataBuffer();
+        int pix[] = data.getData();
+        bmap = Bitmap.createBitmap(pix, width, height, Bitmap.Config.RGB_565);
+        canvas.drawBitmap(bmap, dstX, dstY, paint);
+    }
+    
+    void render(int[] img, int x, int y, int width, int height) {
+        canvas.drawBitmap(Bitmap.createBitmap(img, width, height, Bitmap.Config.ARGB_8888), x, y, paint);
+    }
+
+    void xorCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast,
+            int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast,
+            int width, int height, Color xorcolor){
+
+        data = (DataBufferInt)srcRast.getDataBuffer();
+        int pix[] = data.getData();
+        bmap = Bitmap.createBitmap(pix, width, height, Bitmap.Config.RGB_565);
+        canvas.drawBitmap(bmap, dstX, dstY, paint);
+    }
+    
+    private void transformedBlit(ColorModel srcCM, Raster srcR, int srcX, int srcY,
+            ColorModel dstCM, WritableRaster dstR, int dstX, int dstY,
+            int width, int height, AffineTransform at, Composite comp,
+            Color bgcolor, MultiRectArea clip) {
+        
+        data = (DataBufferInt)srcR.getDataBuffer();
+        int[] pixels = data.getData();
+        if (!srcCM.hasAlpha()) {
+            // This wouldn't be necessary if Android supported RGB_888.
+            for (int i = 0; i < pixels.length; i++) {
+                pixels[i] = pixels[i] | 0xff000000;
+            }
+        }
+        bmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
+        
+        Matrix tm = new Matrix();
+        tm.setConcat(canvas.getMatrix(), AndroidGraphics2D.createMatrixObj(at));
+        if(at.getType() > 1) {
+            bmp = Bitmap.createBitmap(bmap, 0, 0, width, height, tm, true);
+        } else {
+            bmp = Bitmap.createBitmap(bmap, 0, 0, width, height, tm, false);
+        }
+        canvas.drawBitmap(bmp, dstX + (float)at.getTranslateX(), dstY + (float)at.getTranslateY(), paint);
+    }
+
+    private Rectangle2D getBounds2D(AffineTransform at, Rectangle r) {
+        int x = r.x;
+        int y = r.y;
+        int width = r.width;
+        int height = r.height;
+
+        float[] corners = {
+            x, y,
+            x + width, y,
+            x + width, y + height,
+            x, y + height
+        };
+
+        at.transform(corners, 0, corners, 0, 4);
+
+        Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0);
+        bounds.add(corners[2], corners[3]);
+        bounds.add(corners[4], corners[5]);
+        bounds.add(corners[6], corners[7]);
+
+        return bounds;
+    }
+
+    private int compose(int srcRGB, boolean isSrcAlphaPre,
+            int dstRGB, boolean dstHasAlpha, boolean isDstAlphaPre,
+            int rule, int srcConstAlpha){
+
+        int sa, sr, sg, sb, da, dr, dg, db;
+
+        sa = (srcRGB >> 24) & 0xff;
+        sr = (srcRGB >> 16) & 0xff;
+        sg = (srcRGB >> 8) & 0xff;
+        sb = srcRGB & 0xff;
+
+        if(isSrcAlphaPre){
+            sa = mulLUT[srcConstAlpha][sa] & 0xff;
+            sr = mulLUT[srcConstAlpha][sr] & 0xff;
+            sg = mulLUT[srcConstAlpha][sg] & 0xff;
+            sb = mulLUT[srcConstAlpha][sb] & 0xff;
+        }else{
+            sa = mulLUT[srcConstAlpha][sa] & 0xff;
+            sr = mulLUT[sa][sr] & 0xff;
+            sg = mulLUT[sa][sg] & 0xff;
+            sb = mulLUT[sa][sb] & 0xff;
+        }
+
+        da = (dstRGB >> 24) & 0xff;
+        dr = (dstRGB >> 16) & 0xff;
+        dg = (dstRGB >> 8) & 0xff;
+        db = dstRGB & 0xff;
+
+        if(!isDstAlphaPre){
+            dr = mulLUT[da][dr] & 0xff;
+            dg = mulLUT[da][dg] & 0xff;
+            db = mulLUT[da][db] & 0xff;
+        }
+
+        int Fs = 0;
+        int Fd = 0;
+        switch(rule){
+        case AlphaComposite.CLEAR:
+            break;
+
+        case AlphaComposite.DST:
+            Fd = 255;
+            break;
+
+        case AlphaComposite.DST_ATOP:
+            Fs = 255 - da;
+            Fd = sa;
+            break;
+
+        case AlphaComposite.DST_IN:
+            Fd = sa;
+            break;
+
+        case AlphaComposite.DST_OUT:
+            Fd = 255 - sa;
+            break;
+
+        case AlphaComposite.DST_OVER:
+            Fs = 255 - da;
+            Fd = 255;
+            break;
+
+        case AlphaComposite.SRC:
+            Fs = 255;
+            break;
+
+        case AlphaComposite.SRC_ATOP:
+            Fs = da;
+            Fd = 255 - sa;
+            break;
+
+        case AlphaComposite.SRC_IN:
+            Fs = da;
+            break;
+
+        case AlphaComposite.SRC_OUT:
+            Fs = 255 - da;
+            break;
+
+        case AlphaComposite.SRC_OVER:
+            Fs = 255;
+            Fd = 255 - sa;
+            break;
+
+        case AlphaComposite.XOR:
+            Fs = 255 - da;
+            Fd = 255 - sa;
+            break;
+        }
+        dr = (mulLUT[sr][Fs] & 0xff) + (mulLUT[dr][Fd] & 0xff);
+        dg = (mulLUT[sg][Fs] & 0xff) + (mulLUT[dg][Fd] & 0xff);
+        db = (mulLUT[sb][Fs] & 0xff) + (mulLUT[db][Fd] & 0xff);
+
+        da = (mulLUT[sa][Fs] & 0xff) + (mulLUT[da][Fd] & 0xff);
+
+        if(!isDstAlphaPre){
+            if(da != 255){
+                dr = divLUT[da][dr] & 0xff;
+                dg = divLUT[da][dg] & 0xff;
+                db = divLUT[da][db] & 0xff;
+            }
+        }
+        if(!dstHasAlpha) {
+            da = 0xff;
+        }
+        dstRGB = (da << 24) | (dr << 16) | (dg << 8) | db;
+
+        return dstRGB;
+
+    }
+    
+    /**
+     * Allocate an array that can be use to store the result for a 
+     * Raster.getDataElements call.
+     * @param raster  Raster (type) where the getDataElements call will be made. 
+     * @param nbPixels  How many pixels to store in the array at most
+     * @return the result array or null
+     */
+    private Object getTransferArray(Raster raster, int nbPixels) {
+        int transferType = raster.getTransferType();
+        int nbDataElements = raster.getSampleModel().getNumDataElements();
+        int n = nbDataElements * nbPixels;
+        switch (transferType) {
+        case DataBuffer.TYPE_BYTE:
+            return new byte[n];
+        case DataBuffer.TYPE_SHORT:
+        case DataBuffer.TYPE_USHORT:
+            return new short[n];
+        case DataBuffer.TYPE_INT:
+            return new int[n];
+        case DataBuffer.TYPE_FLOAT:
+            return new float[n];
+        case DataBuffer.TYPE_DOUBLE:
+            return new double[n];
+        case DataBuffer.TYPE_UNDEFINED:
+        default:
+            return null;
+        }
+    }
+    
+    /**
+     * Draw a pixel
+     */
+    private void dot(int x, int y, int clr) {
+        if (colorCache != clr) {
+            paint.setColor(clr);  
+            colorCache = clr;
+        }
+        canvas.drawLine(x, y, x + 1, y + 1, paint);
+    }
+}
diff --git a/awt/com/android/internal/awt/AndroidNativeEventQueue.java b/awt/com/android/internal/awt/AndroidNativeEventQueue.java
new file mode 100644
index 0000000..fc30614
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidNativeEventQueue.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2007, 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.android.internal.awt;
+
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+
+public class AndroidNativeEventQueue extends NativeEventQueue {
+    
+    private Object eventMonitor;
+    
+    public AndroidNativeEventQueue() {
+        super();
+        eventMonitor = getEventMonitor();
+    }
+
+    @Override
+    public void awake() {
+        synchronized (eventMonitor) {
+            eventMonitor.notify();
+        }
+    }
+
+    @Override
+    public void dispatchEvent() {
+        //???AWT
+        System.out.println(getClass()+": empty method called");
+    }
+
+    @Override
+    public long getJavaWindow() {
+        //???AWT
+        System.out.println(getClass()+": empty method called");
+        return 0;
+    }
+
+    @Override
+    public void performLater(Task task) {
+        //???AWT
+        System.out.println(getClass()+": empty method called");
+    }
+
+    @Override
+    public void performTask(Task task) {
+        //???AWT
+        System.out.println(getClass()+": empty method called");
+    }
+
+    @Override
+    public boolean waitEvent() {
+        while (isEmpty() ) {
+            synchronized (eventMonitor) {
+                try {
+                    eventMonitor.wait(1000);
+                } catch (InterruptedException ignore) {
+                }
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/awt/com/android/internal/awt/AndroidWTK.java b/awt/com/android/internal/awt/AndroidWTK.java
new file mode 100644
index 0000000..1609d11
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidWTK.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2007, 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.android.internal.awt;
+
+import java.awt.GraphicsDevice;
+
+import org.apache.harmony.awt.wtk.CursorFactory;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+import org.apache.harmony.awt.wtk.NativeIM;
+import org.apache.harmony.awt.wtk.NativeMouseInfo;
+import org.apache.harmony.awt.wtk.NativeRobot;
+import org.apache.harmony.awt.wtk.SystemProperties;
+import org.apache.harmony.awt.wtk.WTK;
+import org.apache.harmony.awt.wtk.WindowFactory;
+
+public class AndroidWTK extends WTK {
+
+    private AndroidGraphicsFactory mAgf;
+    private AndroidNativeEventQueue mAneq;
+    
+    @Override
+    public CursorFactory getCursorFactory() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public GraphicsFactory getGraphicsFactory() {
+        if(mAgf == null) {
+            mAgf = new AndroidGraphicsFactory();
+        }
+        return mAgf;
+    }
+
+    @Override
+    public NativeEventQueue getNativeEventQueue() {
+        if(mAneq == null) {
+            mAneq = new AndroidNativeEventQueue();
+        }
+        return mAneq;
+    }
+
+    @Override
+    public NativeIM getNativeIM() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public NativeMouseInfo getNativeMouseInfo() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public NativeRobot getNativeRobot(GraphicsDevice screen) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public SystemProperties getSystemProperties() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public WindowFactory getWindowFactory() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}
diff --git a/awt/com/android/internal/awt/AwtFactory.java b/awt/com/android/internal/awt/AwtFactory.java
new file mode 100644
index 0000000..6e667b2
--- /dev/null
+++ b/awt/com/android/internal/awt/AwtFactory.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2007, 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.android.internal.awt;
+
+import java.awt.Graphics2D;
+import java.awt.Toolkit;
+
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+public class AwtFactory {
+    
+    private static GraphicsFactory gf;
+    
+    /**
+     * Use this method to get acces to AWT drawing primitives and to
+     * render into the surface area of a Android widget. Origin and 
+     * clip of the returned graphics object are the same as in the
+     * corresponding Android widget. 
+     * 
+     * @param c Canvas of the android widget to draw into
+     * @param p The default drawing parameters such as font, 
+     * stroke, foreground and background colors, etc.
+     * @return The AWT Graphics object that makes all AWT 
+     * drawing primitives available in the androind world.
+     */
+    public static Graphics2D getAwtGraphics(Canvas c, Paint p) {
+        // AWT?? TODO: test it!
+        if (null == gf) {
+            Toolkit tk = Toolkit.getDefaultToolkit();
+            gf = tk.getGraphicsFactory();
+        }
+        return gf.getGraphics2D(c, p);
+    }
+
+}
diff --git a/awt/com/android/internal/awt/ImageOutputStreamWrapper.java b/awt/com/android/internal/awt/ImageOutputStreamWrapper.java
new file mode 100644
index 0000000..92185fd
--- /dev/null
+++ b/awt/com/android/internal/awt/ImageOutputStreamWrapper.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2007, 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.android.internal.awt;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.imageio.stream.ImageOutputStream;
+
+public class ImageOutputStreamWrapper extends OutputStream {
+	
+	protected ImageOutputStream mIos;
+	
+	private byte[] mBuff;
+	
+	public ImageOutputStreamWrapper(ImageOutputStream ios) {
+		if (null == ios) {
+			throw new IllegalArgumentException("ImageOutputStream must not be null");
+		}
+		this.mIos = ios;
+		this.mBuff = new byte[1];
+	}
+
+	public ImageOutputStream getImageOutputStream() {
+		return mIos;
+	}
+	
+	@Override
+	public void write(int oneByte) throws IOException {
+		mBuff[0] = (byte)oneByte;
+		mIos.write(mBuff, 0, 1);
+	}
+
+	public void write(byte[] b) throws IOException {
+		mIos.write(b, 0, b.length);
+	}
+	
+	public void write(byte[] b, int off, int len) throws IOException {
+		mIos.write(b, off, len);
+	}
+	
+	public void flush() throws IOException {
+		mIos.flush();
+	}
+	
+    public void close() throws IOException {
+    	if (mIos == null) {
+    		throw new IOException("Stream already closed");
+    	}
+        mIos = null;
+    }
+}
diff --git a/awt/java/awt/AWTEvent.java b/awt/java/awt/AWTEvent.java
new file mode 100644
index 0000000..a8dc83a
--- /dev/null
+++ b/awt/java/awt/AWTEvent.java
@@ -0,0 +1,681 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev, Michael Danilov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.util.EventObject;
+import java.util.Hashtable;
+import java.util.EventListener;
+
+import java.awt.event.*;
+
+/**
+ * The abstract class AWTEvent is the base class for all AWT events. This class
+ * and its subclasses supersede the original java.awt.Event class.
+ * 
+ * @since Android 1.0
+ */
+public abstract class AWTEvent extends EventObject {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -1825314779160409405L;
+
+    /**
+     * The Constant COMPONENT_EVENT_MASK indicates the event relates to a
+     * component.
+     */
+    public static final long COMPONENT_EVENT_MASK = 1;
+
+    /**
+     * The Constant CONTAINER_EVENT_MASK indicates the event relates to a
+     * container.
+     */
+    public static final long CONTAINER_EVENT_MASK = 2;
+
+    /**
+     * The Constant FOCUS_EVENT_MASK indicates the event relates to the focus.
+     */
+    public static final long FOCUS_EVENT_MASK = 4;
+
+    /**
+     * The Constant KEY_EVENT_MASK indicates the event relates to a key.
+     */
+    public static final long KEY_EVENT_MASK = 8;
+
+    /**
+     * The Constant MOUSE_EVENT_MASK indicates the event relates to the mouse.
+     */
+    public static final long MOUSE_EVENT_MASK = 16;
+
+    /**
+     * The Constant MOUSE_MOTION_EVENT_MASK indicates the event relates to a
+     * mouse motion.
+     */
+    public static final long MOUSE_MOTION_EVENT_MASK = 32;
+
+    /**
+     * The Constant WINDOW_EVENT_MASK indicates the event relates to a window.
+     */
+    public static final long WINDOW_EVENT_MASK = 64;
+
+    /**
+     * The Constant ACTION_EVENT_MASK indicates the event relates to an action.
+     */
+    public static final long ACTION_EVENT_MASK = 128;
+
+    /**
+     * The Constant ADJUSTMENT_EVENT_MASK indicates the event relates to an
+     * adjustment.
+     */
+    public static final long ADJUSTMENT_EVENT_MASK = 256;
+
+    /**
+     * The Constant ITEM_EVENT_MASK indicates the event relates to an item.
+     */
+    public static final long ITEM_EVENT_MASK = 512;
+
+    /**
+     * The Constant TEXT_EVENT_MASK indicates the event relates to text.
+     */
+    public static final long TEXT_EVENT_MASK = 1024;
+
+    /**
+     * The Constant INPUT_METHOD_EVENT_MASK indicates the event relates to an
+     * input method.
+     */
+    public static final long INPUT_METHOD_EVENT_MASK = 2048;
+
+    /**
+     * The Constant PAINT_EVENT_MASK indicates the event relates to a paint
+     * method.
+     */
+    public static final long PAINT_EVENT_MASK = 8192;
+
+    /**
+     * The Constant INVOCATION_EVENT_MASK indicates the event relates to a
+     * method invocation.
+     */
+    public static final long INVOCATION_EVENT_MASK = 16384;
+
+    /**
+     * The Constant HIERARCHY_EVENT_MASK indicates the event relates to a
+     * hierarchy.
+     */
+    public static final long HIERARCHY_EVENT_MASK = 32768;
+
+    /**
+     * The Constant HIERARCHY_BOUNDS_EVENT_MASK indicates the event relates to
+     * hierarchy bounds.
+     */
+    public static final long HIERARCHY_BOUNDS_EVENT_MASK = 65536;
+
+    /**
+     * The Constant MOUSE_WHEEL_EVENT_MASK indicates the event relates to the
+     * mouse wheel.
+     */
+    public static final long MOUSE_WHEEL_EVENT_MASK = 131072;
+
+    /**
+     * The Constant WINDOW_STATE_EVENT_MASK indicates the event relates to a
+     * window state.
+     */
+    public static final long WINDOW_STATE_EVENT_MASK = 262144;
+
+    /**
+     * The Constant WINDOW_FOCUS_EVENT_MASK indicates the event relates to a
+     * window focus.
+     */
+    public static final long WINDOW_FOCUS_EVENT_MASK = 524288;
+
+    /**
+     * The Constant RESERVED_ID_MAX indicates the maximum value for reserved AWT
+     * event IDs.
+     */
+    public static final int RESERVED_ID_MAX = 1999;
+
+    /**
+     * The Constant eventsMap.
+     */
+    private static final Hashtable<Integer, EventDescriptor> eventsMap = new Hashtable<Integer, EventDescriptor>();
+
+    /**
+     * The converter.
+     */
+    private static EventConverter converter;
+
+    /**
+     * The ID of the event.
+     */
+    protected int id;
+
+    /**
+     * The consumed indicates whether or not the event is sent back down to the
+     * peer once the source has processed it (false means it's sent to the peer,
+     * true means it's not).
+     */
+    protected boolean consumed;
+
+    /**
+     * The dispatched by kfm.
+     */
+    boolean dispatchedByKFM;
+
+    /**
+     * The is posted.
+     */
+    transient boolean isPosted;
+
+    static {
+        eventsMap.put(new Integer(KeyEvent.KEY_TYPED), new EventDescriptor(KEY_EVENT_MASK,
+                KeyListener.class));
+        eventsMap.put(new Integer(KeyEvent.KEY_PRESSED), new EventDescriptor(KEY_EVENT_MASK,
+                KeyListener.class));
+        eventsMap.put(new Integer(KeyEvent.KEY_RELEASED), new EventDescriptor(KEY_EVENT_MASK,
+                KeyListener.class));
+        eventsMap.put(new Integer(MouseEvent.MOUSE_CLICKED), new EventDescriptor(MOUSE_EVENT_MASK,
+                MouseListener.class));
+        eventsMap.put(new Integer(MouseEvent.MOUSE_PRESSED), new EventDescriptor(MOUSE_EVENT_MASK,
+                MouseListener.class));
+        eventsMap.put(new Integer(MouseEvent.MOUSE_RELEASED), new EventDescriptor(MOUSE_EVENT_MASK,
+                MouseListener.class));
+        eventsMap.put(new Integer(MouseEvent.MOUSE_MOVED), new EventDescriptor(
+                MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class));
+        eventsMap.put(new Integer(MouseEvent.MOUSE_ENTERED), new EventDescriptor(MOUSE_EVENT_MASK,
+                MouseListener.class));
+        eventsMap.put(new Integer(MouseEvent.MOUSE_EXITED), new EventDescriptor(MOUSE_EVENT_MASK,
+                MouseListener.class));
+        eventsMap.put(new Integer(MouseEvent.MOUSE_DRAGGED), new EventDescriptor(
+                MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class));
+        eventsMap.put(new Integer(MouseEvent.MOUSE_WHEEL), new EventDescriptor(
+                MOUSE_WHEEL_EVENT_MASK, MouseWheelListener.class));
+        eventsMap.put(new Integer(ComponentEvent.COMPONENT_MOVED), new EventDescriptor(
+                COMPONENT_EVENT_MASK, ComponentListener.class));
+        eventsMap.put(new Integer(ComponentEvent.COMPONENT_RESIZED), new EventDescriptor(
+                COMPONENT_EVENT_MASK, ComponentListener.class));
+        eventsMap.put(new Integer(ComponentEvent.COMPONENT_SHOWN), new EventDescriptor(
+                COMPONENT_EVENT_MASK, ComponentListener.class));
+        eventsMap.put(new Integer(ComponentEvent.COMPONENT_HIDDEN), new EventDescriptor(
+                COMPONENT_EVENT_MASK, ComponentListener.class));
+        eventsMap.put(new Integer(FocusEvent.FOCUS_GAINED), new EventDescriptor(FOCUS_EVENT_MASK,
+                FocusListener.class));
+        eventsMap.put(new Integer(FocusEvent.FOCUS_LOST), new EventDescriptor(FOCUS_EVENT_MASK,
+                FocusListener.class));
+        eventsMap.put(new Integer(PaintEvent.PAINT), new EventDescriptor(PAINT_EVENT_MASK, null));
+        eventsMap.put(new Integer(PaintEvent.UPDATE), new EventDescriptor(PAINT_EVENT_MASK, null));
+        eventsMap.put(new Integer(WindowEvent.WINDOW_OPENED), new EventDescriptor(
+                WINDOW_EVENT_MASK, WindowListener.class));
+        eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSING), new EventDescriptor(
+                WINDOW_EVENT_MASK, WindowListener.class));
+        eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSED), new EventDescriptor(
+                WINDOW_EVENT_MASK, WindowListener.class));
+        eventsMap.put(new Integer(WindowEvent.WINDOW_DEICONIFIED), new EventDescriptor(
+                WINDOW_EVENT_MASK, WindowListener.class));
+        eventsMap.put(new Integer(WindowEvent.WINDOW_ICONIFIED), new EventDescriptor(
+                WINDOW_EVENT_MASK, WindowListener.class));
+        eventsMap.put(new Integer(WindowEvent.WINDOW_STATE_CHANGED), new EventDescriptor(
+                WINDOW_STATE_EVENT_MASK, WindowStateListener.class));
+        eventsMap.put(new Integer(WindowEvent.WINDOW_LOST_FOCUS), new EventDescriptor(
+                WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class));
+        eventsMap.put(new Integer(WindowEvent.WINDOW_GAINED_FOCUS), new EventDescriptor(
+                WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class));
+        eventsMap.put(new Integer(WindowEvent.WINDOW_DEACTIVATED), new EventDescriptor(
+                WINDOW_EVENT_MASK, WindowListener.class));
+        eventsMap.put(new Integer(WindowEvent.WINDOW_ACTIVATED), new EventDescriptor(
+                WINDOW_EVENT_MASK, WindowListener.class));
+        eventsMap.put(new Integer(HierarchyEvent.HIERARCHY_CHANGED), new EventDescriptor(
+                HIERARCHY_EVENT_MASK, HierarchyListener.class));
+        eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_MOVED), new EventDescriptor(
+                HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class));
+        eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_RESIZED), new EventDescriptor(
+                HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class));
+        eventsMap.put(new Integer(ContainerEvent.COMPONENT_ADDED), new EventDescriptor(
+                CONTAINER_EVENT_MASK, ContainerListener.class));
+        eventsMap.put(new Integer(ContainerEvent.COMPONENT_REMOVED), new EventDescriptor(
+                CONTAINER_EVENT_MASK, ContainerListener.class));
+        eventsMap.put(new Integer(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED), new EventDescriptor(
+                INPUT_METHOD_EVENT_MASK, InputMethodListener.class));
+        eventsMap.put(new Integer(InputMethodEvent.CARET_POSITION_CHANGED), new EventDescriptor(
+                INPUT_METHOD_EVENT_MASK, InputMethodListener.class));
+        eventsMap.put(new Integer(InvocationEvent.INVOCATION_DEFAULT), new EventDescriptor(
+                INVOCATION_EVENT_MASK, null));
+        eventsMap.put(new Integer(ItemEvent.ITEM_STATE_CHANGED), new EventDescriptor(
+                ITEM_EVENT_MASK, ItemListener.class));
+        eventsMap.put(new Integer(TextEvent.TEXT_VALUE_CHANGED), new EventDescriptor(
+                TEXT_EVENT_MASK, TextListener.class));
+        eventsMap.put(new Integer(ActionEvent.ACTION_PERFORMED), new EventDescriptor(
+                ACTION_EVENT_MASK, ActionListener.class));
+        eventsMap.put(new Integer(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED), new EventDescriptor(
+                ADJUSTMENT_EVENT_MASK, AdjustmentListener.class));
+        converter = new EventConverter();
+    }
+
+    /**
+     * Instantiates a new AWT event from the specified Event object.
+     * 
+     * @param event
+     *            the Event object.
+     */
+    public AWTEvent(Event event) {
+        this(event.target, event.id);
+    }
+
+    /**
+     * Instantiates a new AWT event with the specified object and type.
+     * 
+     * @param source
+     *            the source Object.
+     * @param id
+     *            the event's type.
+     */
+    public AWTEvent(Object source, int id) {
+        super(source);
+        this.id = id;
+        consumed = false;
+    }
+
+    /**
+     * Gets the event's type.
+     * 
+     * @return the event type ID.
+     */
+    public int getID() {
+        return id;
+    }
+
+    /**
+     * Sets a new source for the AWTEvent.
+     * 
+     * @param newSource
+     *            the new source Object for the AWTEvent.
+     */
+    public void setSource(Object newSource) {
+        source = newSource;
+    }
+
+    /**
+     * Returns a String representation of the AWTEvent.
+     * 
+     * @return the String representation of the AWTEvent.
+     */
+    @Override
+    public String toString() {
+        /*
+         * The format is based on 1.5 release behavior which can be revealed by
+         * the following code: AWTEvent event = new AWTEvent(new Component(){},
+         * 1){}; System.out.println(event);
+         */
+        String name = ""; //$NON-NLS-1$
+
+        if (source instanceof Component && (source != null)) {
+            Component comp = (Component)getSource();
+            name = comp.getName();
+            if (name == null) {
+                name = ""; //$NON-NLS-1$
+            }
+        }
+
+        return (getClass().getName() + "[" + paramString() + "]" //$NON-NLS-1$ //$NON-NLS-2$
+                + " on " + (name.length() > 0 ? name : source)); //$NON-NLS-1$
+    }
+
+    /**
+     * Returns a string representation of the AWTEvent state.
+     * 
+     * @return a string representation of the AWTEvent state.
+     */
+    public String paramString() {
+        // nothing to implement: all event types must override this method
+        return ""; //$NON-NLS-1$
+    }
+
+    /**
+     * Checks whether or not this AWTEvent has been consumed.
+     * 
+     * @return true, if this AWTEvent has been consumed, false otherwise.
+     */
+    protected boolean isConsumed() {
+        return consumed;
+    }
+
+    /**
+     * Consumes the AWTEvent.
+     */
+    protected void consume() {
+        consumed = true;
+    }
+
+    /**
+     * Convert AWTEvent object to a corresponding (deprecated) Event object.
+     * 
+     * @return new Event object which is a converted AWTEvent object or null if
+     *         the conversion is not possible
+     */
+    Event getEvent() {
+
+        if (id == ActionEvent.ACTION_PERFORMED) {
+            ActionEvent ae = (ActionEvent)this;
+            return converter.convertActionEvent(ae);
+
+        } else if (id == AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED) {
+            AdjustmentEvent ae = (AdjustmentEvent)this;
+            return converter.convertAdjustmentEvent(ae);
+
+            // ???AWT
+            // } else if (id == ComponentEvent.COMPONENT_MOVED
+            // && source instanceof Window) {
+            // //the only type of Component events is COMPONENT_MOVED on window
+            // ComponentEvent ce = (ComponentEvent) this;
+            // return converter.convertComponentEvent(ce);
+
+        } else if (id >= FocusEvent.FOCUS_FIRST && id <= FocusEvent.FOCUS_LAST) {
+            // nothing to convert
+
+            // ???AWT
+            // } else if (id == ItemEvent.ITEM_STATE_CHANGED) {
+            // ItemEvent ie = (ItemEvent) this;
+            // return converter.convertItemEvent(ie);
+
+        } else if (id == KeyEvent.KEY_PRESSED || id == KeyEvent.KEY_RELEASED) {
+            KeyEvent ke = (KeyEvent)this;
+            return converter.convertKeyEvent(ke);
+        } else if (id >= MouseEvent.MOUSE_FIRST && id <= MouseEvent.MOUSE_LAST) {
+            MouseEvent me = (MouseEvent)this;
+            return converter.convertMouseEvent(me);
+        } else if (id == WindowEvent.WINDOW_CLOSING || id == WindowEvent.WINDOW_ICONIFIED
+                || id == WindowEvent.WINDOW_DEICONIFIED) {
+            // nothing to convert
+        } else {
+            return null;
+        }
+        return new Event(source, id, null);
+    }
+
+    /**
+     * The class EventDescriptor.
+     */
+    static final class EventDescriptor {
+
+        /**
+         * The event mask.
+         */
+        final long eventMask;
+
+        /**
+         * The listener type.
+         */
+        final Class<? extends EventListener> listenerType;
+
+        /**
+         * Instantiates a new event descriptor.
+         * 
+         * @param eventMask
+         *            the event mask.
+         * @param listenerType
+         *            the listener type.
+         */
+        EventDescriptor(long eventMask, Class<? extends EventListener> listenerType) {
+            this.eventMask = eventMask;
+            this.listenerType = listenerType;
+        }
+
+    }
+
+    /**
+     * The class EventTypeLookup.
+     */
+    static final class EventTypeLookup {
+
+        /**
+         * The last event.
+         */
+        private AWTEvent lastEvent = null;
+
+        /**
+         * The last event descriptor.
+         */
+        private EventDescriptor lastEventDescriptor = null;
+
+        /**
+         * Gets the event descriptor.
+         * 
+         * @param event
+         *            the event.
+         * @return the event descriptor.
+         */
+        EventDescriptor getEventDescriptor(AWTEvent event) {
+            synchronized (this) {
+                if (event != lastEvent) {
+                    lastEvent = event;
+                    lastEventDescriptor = eventsMap.get(new Integer(event.id));
+                }
+
+                return lastEventDescriptor;
+            }
+        }
+
+        /**
+         * Gets the event mask.
+         * 
+         * @param event
+         *            the event.
+         * @return the event mask.
+         */
+        long getEventMask(AWTEvent event) {
+            final EventDescriptor ed = getEventDescriptor(event);
+            return ed == null ? -1 : ed.eventMask;
+        }
+    }
+
+    /**
+     * The class EventConverter.
+     */
+    static final class EventConverter {
+
+        /**
+         * The constant OLD_MOD_MASK.
+         */
+        static final int OLD_MOD_MASK = Event.ALT_MASK | Event.CTRL_MASK | Event.META_MASK
+                | Event.SHIFT_MASK;
+
+        /**
+         * Convert action event.
+         * 
+         * @param ae
+         *            the ae.
+         * @return the event.
+         */
+        Event convertActionEvent(ActionEvent ae) {
+            Event evt = new Event(ae.getSource(), ae.getID(), ae.getActionCommand());
+            evt.when = ae.getWhen();
+            evt.modifiers = ae.getModifiers() & OLD_MOD_MASK;
+
+            /*
+             * if (source instanceof Button) { arg = ((Button)
+             * source).getLabel(); } else if (source instanceof Checkbox) { arg
+             * = new Boolean(((Checkbox) source).getState()); } else if (source
+             * instanceof CheckboxMenuItem) { arg = ((CheckboxMenuItem)
+             * source).getLabel(); } else if (source instanceof Choice) { arg =
+             * ((Choice) source).getSelectedItem(); } else if (source instanceof
+             * List) { arg = ((List) source).getSelectedItem(); } else if
+             * (source instanceof MenuItem) { arg = ((MenuItem)
+             * source).getLabel(); } else if (source instanceof TextField) { arg
+             * = ((TextField) source).getText(); }
+             */
+            return evt;
+        }
+
+        /**
+         * Convert adjustment event.
+         * 
+         * @param ae
+         *            the ae.
+         * @return the event.
+         */
+        Event convertAdjustmentEvent(AdjustmentEvent ae) {
+            // TODO: Event.SCROLL_BEGIN/SCROLL_END
+            return new Event(ae.source, ae.id + ae.getAdjustmentType() - 1, new Integer(ae
+                    .getValue()));
+        }
+
+        /**
+         * Convert component event.
+         * 
+         * @param ce
+         *            the ce.
+         * @return the event.
+         */
+        Event convertComponentEvent(ComponentEvent ce) {
+            Component comp = ce.getComponent();
+            Event evt = new Event(comp, Event.WINDOW_MOVED, null);
+            evt.x = comp.getX();
+            evt.y = comp.getY();
+            return evt;
+        }
+
+        // ???AWT
+        /*
+         * Event convertItemEvent(ItemEvent ie) { int oldId = ie.id +
+         * ie.getStateChange() - 1; Object source = ie.source; int idx = -1; if
+         * (source instanceof List) { List list = (List) source; idx =
+         * list.getSelectedIndex(); } else if (source instanceof Choice) {
+         * Choice choice = (Choice) source; idx = choice.getSelectedIndex(); }
+         * Object arg = idx >= 0 ? new Integer(idx) : null; return new
+         * Event(source, oldId, arg); }
+         */
+
+        /**
+         * Convert key event.
+         * 
+         * @param ke
+         *            the ke.
+         * @return the event.
+         */
+        Event convertKeyEvent(KeyEvent ke) {
+            int oldId = ke.id;
+            // leave only old Event's modifiers
+
+            int mod = ke.getModifiers() & OLD_MOD_MASK;
+            Component comp = ke.getComponent();
+            char keyChar = ke.getKeyChar();
+            int keyCode = ke.getKeyCode();
+            int key = convertKey(keyChar, keyCode);
+            if (key >= Event.HOME && key <= Event.INSERT) {
+                oldId += 2; // non-ASCII key -> action key
+            }
+            return new Event(comp, ke.getWhen(), oldId, 0, 0, key, mod);
+        }
+
+        /**
+         * Convert mouse event.
+         * 
+         * @param me
+         *            the me.
+         * @return the event.
+         */
+        Event convertMouseEvent(MouseEvent me) {
+            int id = me.id;
+            if (id != MouseEvent.MOUSE_CLICKED) {
+                Event evt = new Event(me.source, id, null);
+                evt.x = me.getX();
+                evt.y = me.getY();
+                int mod = me.getModifiers();
+                // in Event modifiers mean button number for mouse events:
+                evt.modifiers = mod & (Event.ALT_MASK | Event.META_MASK);
+                if (id == MouseEvent.MOUSE_PRESSED) {
+                    evt.clickCount = me.getClickCount();
+                }
+                return evt;
+            }
+            return null;
+        }
+
+        /**
+         * Convert key.
+         * 
+         * @param keyChar
+         *            the key char.
+         * @param keyCode
+         *            the key code.
+         * @return the int.
+         */
+        int convertKey(char keyChar, int keyCode) {
+            int key;
+            // F1 - F12
+            if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12) {
+                key = Event.F1 + keyCode - KeyEvent.VK_F1;
+            } else {
+                switch (keyCode) {
+                    default: // non-action key
+                        key = keyChar;
+                        break;
+                    // action keys:
+                    case KeyEvent.VK_HOME:
+                        key = Event.HOME;
+                        break;
+                    case KeyEvent.VK_END:
+                        key = Event.END;
+                        break;
+                    case KeyEvent.VK_PAGE_UP:
+                        key = Event.PGUP;
+                        break;
+                    case KeyEvent.VK_PAGE_DOWN:
+                        key = Event.PGDN;
+                        break;
+                    case KeyEvent.VK_UP:
+                        key = Event.UP;
+                        break;
+                    case KeyEvent.VK_DOWN:
+                        key = Event.DOWN;
+                        break;
+                    case KeyEvent.VK_LEFT:
+                        key = Event.LEFT;
+                        break;
+                    case KeyEvent.VK_RIGHT:
+                        key = Event.RIGHT;
+                        break;
+                    case KeyEvent.VK_PRINTSCREEN:
+                        key = Event.PRINT_SCREEN;
+                        break;
+                    case KeyEvent.VK_SCROLL_LOCK:
+                        key = Event.SCROLL_LOCK;
+                        break;
+                    case KeyEvent.VK_CAPS_LOCK:
+                        key = Event.CAPS_LOCK;
+                        break;
+                    case KeyEvent.VK_NUM_LOCK:
+                        key = Event.NUM_LOCK;
+                        break;
+                    case KeyEvent.VK_PAUSE:
+                        key = Event.PAUSE;
+                        break;
+                    case KeyEvent.VK_INSERT:
+                        key = Event.INSERT;
+                        break;
+                }
+            }
+            return key;
+        }
+
+    }
+
+}
diff --git a/awt/java/awt/AWTException.java b/awt/java/awt/AWTException.java
new file mode 100644
index 0000000..6590b73
--- /dev/null
+++ b/awt/java/awt/AWTException.java
@@ -0,0 +1,47 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+/**
+ * The AWTException class is used to provide notification and information about
+ * AWT errors.
+ * 
+ * @since Android 1.0
+ */
+public class AWTException extends Exception {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -1900414231151323879L;
+
+    /**
+     * Instantiates a new AWT exception with the specified message.
+     * 
+     * @param msg
+     *            the specific message for current exception.
+     */
+    public AWTException(String msg) {
+        super(msg);
+    }
+
+}
diff --git a/awt/java/awt/AWTKeyStroke.java b/awt/java/awt/AWTKeyStroke.java
new file mode 100644
index 0000000..f01f6f0
--- /dev/null
+++ b/awt/java/awt/AWTKeyStroke.java
@@ -0,0 +1,712 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The AWTKeyStroke holds all of the information for the complete act of 
+ * typing a character. This includes the events that are generated when 
+ * the key is pressed, released, or typed (pressed and released generating
+ * a Unicode character result) which are associated with the event
+ * objects KeyEvent.KEY_PRESSED, KeyEvent.KEY_RELEASED, or KeyEvent.KEY_TYPED.
+ * It also holds information about which modifiers (such as control or 
+ * shift) were used in conjunction with the keystroke. The following masks 
+ * are available to identify the modifiers:
+ * <ul>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.META_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_MASK</li>
+ * <li>java.awt.event.InputEvent.META_MASK</li>  
+ * <li>java.awt.event.InputEvent.SHIFT_MASK</li>
+ * </ul>  
+ * <br>
+ *  The AWTKeyStroke is unique, and applications should not create their own 
+ *  instances of AWTKeyStroke. All applications should use getAWTKeyStroke 
+ *  methods for obtaining instances of AWTKeyStroke.
+ *  
+ *  @since Android 1.0
+ */
+public class AWTKeyStroke implements Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -6430539691155161871L;
+
+    /**
+     * The Constant cache.
+     */
+    private static final Map<AWTKeyStroke, AWTKeyStroke> cache = new HashMap<AWTKeyStroke, AWTKeyStroke>(); // Map
+
+    // <
+    // AWTKeyStroke
+    // ,
+    // ?
+    // extends
+    // AWTKeyStroke
+    // >
+
+    /**
+     * The Constant keyEventTypesMap.
+     */
+    private static final Map<Integer, String> keyEventTypesMap = new HashMap<Integer, String>(); // Map
+
+    // <
+    // int
+    // ,
+    // String
+    // >
+
+    private static Constructor<?> subConstructor;
+
+    static {
+        keyEventTypesMap.put(new Integer(KeyEvent.KEY_PRESSED), "pressed"); //$NON-NLS-1$
+        keyEventTypesMap.put(new Integer(KeyEvent.KEY_RELEASED), "released"); //$NON-NLS-1$
+        keyEventTypesMap.put(new Integer(KeyEvent.KEY_TYPED), "typed"); //$NON-NLS-1$
+    }
+
+    /**
+     * The key char.
+     */
+    private char keyChar;
+
+    /**
+     * The key code.
+     */
+    private int keyCode;
+
+    /**
+     * The modifiers.
+     */
+    private int modifiers;
+
+    /**
+     * The on key release.
+     */
+    private boolean onKeyRelease;
+
+    /**
+     * Instantiates a new AWTKeyStroke. getAWTKeyStroke method should be used by
+     * applications code.
+     * 
+     * @param keyChar
+     *            the key char.
+     * @param keyCode
+     *            the key code.
+     * @param modifiers
+     *            the modifiers.
+     * @param onKeyRelease
+     *            true if AWTKeyStroke is for a key release, false otherwise.
+     */
+    protected AWTKeyStroke(char keyChar, int keyCode, int modifiers, boolean onKeyRelease) {
+        setAWTKeyStroke(keyChar, keyCode, modifiers, onKeyRelease);
+    }
+
+    /**
+     * Sets the AWT key stroke.
+     * 
+     * @param keyChar
+     *            the key char.
+     * @param keyCode
+     *            the key code.
+     * @param modifiers
+     *            the modifiers.
+     * @param onKeyRelease
+     *            the on key release.
+     */
+    private void setAWTKeyStroke(char keyChar, int keyCode, int modifiers, boolean onKeyRelease) {
+        this.keyChar = keyChar;
+        this.keyCode = keyCode;
+        this.modifiers = modifiers;
+        this.onKeyRelease = onKeyRelease;
+    }
+
+    /**
+     * Instantiates a new AWTKeyStroke with default parameters:
+     * KeyEvent.CHAR_UNDEFINED key char, KeyEvent.VK_UNDEFINED key code, without
+     * modifiers and false key realized value.
+     */
+    protected AWTKeyStroke() {
+        this(KeyEvent.CHAR_UNDEFINED, KeyEvent.VK_UNDEFINED, 0, false);
+    }
+
+    /**
+     * Returns the unique number value for AWTKeyStroke object.
+     * 
+     * @return the integer unique value of the AWTKeyStroke object.
+     */
+    @Override
+    public int hashCode() {
+        return modifiers + (keyCode != KeyEvent.VK_UNDEFINED ? keyCode : keyChar)
+                + (onKeyRelease ? -1 : 0);
+    }
+
+    /**
+     * Gets the set of modifiers for the AWTKeyStroke object.
+     * 
+     * @return the integer value which contains modifiers.
+     */
+    public final int getModifiers() {
+        return modifiers;
+    }
+
+    /**
+     * Compares this AWTKeyStroke object to the specified object.
+     * 
+     * @param anObject
+     *            the specified AWTKeyStroke object to compare with this
+     *            instance.
+     * @return true if objects are identical, false otherwise.
+     */
+    @Override
+    public final boolean equals(Object anObject) {
+        if (anObject instanceof AWTKeyStroke) {
+            AWTKeyStroke key = (AWTKeyStroke)anObject;
+            return ((key.keyCode == keyCode) && (key.keyChar == keyChar)
+                    && (key.modifiers == modifiers) && (key.onKeyRelease == onKeyRelease));
+        }
+        return false;
+    }
+
+    /**
+     * Returns the string representation of the AWTKeyStroke. This string should
+     * contain key stroke properties.
+     * 
+     * @return the string representation of the AWTKeyStroke.
+     */
+    @Override
+    public String toString() {
+        int type = getKeyEventType();
+        return InputEvent.getModifiersExText(getModifiers()) + " " + //$NON-NLS-1$
+                keyEventTypesMap.get(new Integer(type)) + " " + //$NON-NLS-1$
+                (type == KeyEvent.KEY_TYPED ? new String(new char[] {
+                    keyChar
+                }) : KeyEvent.getKeyText(keyCode));
+    }
+
+    /**
+     * Gets the key code for the AWTKeyStroke object.
+     * 
+     * @return the key code for the AWTKeyStroke object.
+     */
+    public final int getKeyCode() {
+        return keyCode;
+    }
+
+    /**
+     * Gets the key character for the AWTKeyStroke object.
+     * 
+     * @return the key character for the AWTKeyStroke object.
+     */
+    public final char getKeyChar() {
+        return keyChar;
+    }
+
+    /**
+     * Gets the AWT key stroke.
+     * 
+     * @param keyChar
+     *            the key char.
+     * @param keyCode
+     *            the key code.
+     * @param modifiers
+     *            the modifiers.
+     * @param onKeyRelease
+     *            the on key release.
+     * @return the AWT key stroke.
+     */
+    private static AWTKeyStroke getAWTKeyStroke(char keyChar, int keyCode, int modifiers,
+            boolean onKeyRelease) {
+        AWTKeyStroke key = newInstance(keyChar, keyCode, modifiers, onKeyRelease);
+
+        AWTKeyStroke value = cache.get(key);
+        if (value == null) {
+            value = key;
+            cache.put(key, value);
+        }
+        return value;
+    }
+
+    /**
+     * New instance.
+     * 
+     * @param keyChar
+     *            the key char.
+     * @param keyCode
+     *            the key code.
+     * @param modifiers
+     *            the modifiers.
+     * @param onKeyRelease
+     *            the on key release.
+     * @return the AWT key stroke.
+     */
+    private static AWTKeyStroke newInstance(char keyChar, int keyCode, int modifiers,
+            boolean onKeyRelease) {
+        AWTKeyStroke key;
+        // ???AWT
+        // if (subConstructor == null) {
+        key = new AWTKeyStroke();
+        // ???AWT
+        // } else {
+        // try {
+        // key = (AWTKeyStroke) subConstructor.newInstance();
+        // } catch (Exception e) {
+        // throw new RuntimeException(e);
+        // }
+        // }
+        int allModifiers = getAllModifiers(modifiers);
+        key.setAWTKeyStroke(keyChar, keyCode, allModifiers, onKeyRelease);
+        return key;
+    }
+
+    /**
+     * Adds the mask.
+     * 
+     * @param mod
+     *            the mod.
+     * @param mask
+     *            the mask.
+     * @return the int.
+     */
+    private static int addMask(int mod, int mask) {
+        return ((mod & mask) != 0) ? (mod | mask) : mod;
+    }
+
+    /**
+     * Return all (old & new) modifiers corresponding to.
+     * 
+     * @param mod
+     *            old or new modifiers.
+     * @return old and new modifiers together.
+     */
+    static int getAllModifiers(int mod) {
+        int allMod = mod;
+        int shift = (InputEvent.SHIFT_MASK | InputEvent.SHIFT_DOWN_MASK);
+        int ctrl = (InputEvent.CTRL_MASK | InputEvent.CTRL_DOWN_MASK);
+        int meta = (InputEvent.META_MASK | InputEvent.META_DOWN_MASK);
+        int alt = (InputEvent.ALT_MASK | InputEvent.ALT_DOWN_MASK);
+        int altGr = (InputEvent.ALT_GRAPH_MASK | InputEvent.ALT_GRAPH_DOWN_MASK);
+        // button modifiers are not converted between old & new
+
+        allMod = addMask(allMod, shift);
+        allMod = addMask(allMod, ctrl);
+        allMod = addMask(allMod, meta);
+        allMod = addMask(allMod, alt);
+        allMod = addMask(allMod, altGr);
+
+        return allMod;
+    }
+
+    /**
+     * Returns an instance of AWTKeyStroke for parsed string. The string must
+     * have the following syntax:
+     *<p>
+     * &lt;modifiers&gt;* (&lt;typedID&gt; | &lt;pressedReleasedID&gt;)
+     *<p>
+     * modifiers := shift | control | ctrl | meta | alt | altGraph <br>
+     * typedID := typed <typedKey> <br>
+     * typedKey := string of length 1 giving the Unicode character. <br>
+     * pressedReleasedID := (pressed | released) <key> <br>
+     * key := KeyEvent key code name, i.e. the name following "VK_".
+     * <p>
+     * 
+     * @param s
+     *            the String which contains key stroke parameters.
+     * @return the AWTKeyStroke for string.
+     * @throws IllegalArgumentException
+     *             if string has incorrect format or null.
+     */
+    public static AWTKeyStroke getAWTKeyStroke(String s) {
+        if (s == null) {
+            // awt.65=null argument
+            throw new IllegalArgumentException(Messages.getString("awt.65")); //$NON-NLS-1$
+        }
+
+        StringTokenizer tokenizer = new StringTokenizer(s);
+
+        Boolean release = null;
+        int modifiers = 0;
+        int keyCode = KeyEvent.VK_UNDEFINED;
+        char keyChar = KeyEvent.CHAR_UNDEFINED;
+        boolean typed = false;
+        long modifier = 0;
+        String token = null;
+        do {
+            token = getNextToken(tokenizer);
+            modifier = parseModifier(token);
+            modifiers |= modifier;
+        } while (modifier > 0);
+
+        typed = parseTypedID(token);
+
+        if (typed) {
+            token = getNextToken(tokenizer);
+            keyChar = parseTypedKey(token);
+
+        }
+        if (keyChar == KeyEvent.CHAR_UNDEFINED) {
+            release = parsePressedReleasedID(token);
+            if (release != null) {
+                token = getNextToken(tokenizer);
+            }
+            keyCode = parseKey(token);
+        }
+        if (tokenizer.hasMoreTokens()) {
+            // awt.66=Invalid format
+            throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+        }
+
+        return getAWTKeyStroke(keyChar, keyCode, modifiers, release == Boolean.TRUE);
+    }
+
+    /**
+     * Gets the next token.
+     * 
+     * @param tokenizer
+     *            the tokenizer.
+     * @return the next token.
+     */
+    private static String getNextToken(StringTokenizer tokenizer) {
+        try {
+            return tokenizer.nextToken();
+        } catch (NoSuchElementException exception) {
+            // awt.66=Invalid format
+            throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Gets the key code.
+     * 
+     * @param s
+     *            the s.
+     * @return the key code.
+     */
+    static int getKeyCode(String s) {
+        try {
+            Field vk = KeyEvent.class.getField("VK_" + s); //$NON-NLS-1$
+            return vk.getInt(null);
+        } catch (Exception e) {
+            if (s.length() != 1) {
+                // awt.66=Invalid format
+                throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+            }
+            return KeyEvent.VK_UNDEFINED;
+        }
+    }
+
+    /**
+     * Gets an instance of the AWTKeyStroke for specified character.
+     * 
+     * @param keyChar
+     *            the keyboard character value.
+     * @return a AWTKeyStroke for specified character.
+     */
+    public static AWTKeyStroke getAWTKeyStroke(char keyChar) {
+        return getAWTKeyStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false);
+    }
+
+    /**
+     * Returns an instance of AWTKeyStroke for a given key code, set of
+     * modifiers, and specified key released flag value. The key codes are
+     * defined in java.awt.event.KeyEvent class. The set of modifiers is given
+     * as a bitwise combination of masks taken from the following list:
+     * <ul>
+     * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.ALT_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.CTRL_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.META_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.SHIFT_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.ALT_GRAPH_MASK</li> <li>
+     * java.awt.event.InputEvent.ALT_MASK</li> <li>
+     * java.awt.event.InputEvent.CTRL_MASK</li> <li>
+     * java.awt.event.InputEvent.META_MASK</li> <li>
+     * java.awt.event.InputEvent.SHIFT_MASK</li>
+     * </ul>
+     * <br>
+     * 
+     * @param keyCode
+     *            the specified key code of keyboard.
+     * @param modifiers
+     *            the bit set of modifiers.
+     * @param onKeyRelease
+     *            the value which represents whether this AWTKeyStroke shall
+     *            represents a key release.
+     * @return the AWTKeyStroke.
+     */
+    public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers, boolean onKeyRelease) {
+        return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers, onKeyRelease);
+    }
+
+    /**
+     * Returns AWTKeyStroke for a specified character and set of modifiers. The
+     * set of modifiers is given as a bitwise combination of masks taken from
+     * the following list:
+     * <ul>
+     * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.ALT_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.CTRL_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.META_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.SHIFT_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.ALT_GRAPH_MASK</li> <li>
+     * java.awt.event.InputEvent.ALT_MASK</li> <li>
+     * java.awt.event.InputEvent.CTRL_MASK</li> <li>
+     * java.awt.event.InputEvent.META_MASK</li> <li>
+     * java.awt.event.InputEvent.SHIFT_MASK</li>
+     * </ul>
+     * 
+     * @param keyChar
+     *            the Character object which represents keyboard character
+     *            value.
+     * @param modifiers
+     *            the bit set of modifiers.
+     * @return the AWTKeyStroke object.
+     * @throws IllegalArgumentException
+     *             if keyChar value is null.
+     */
+    public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers) {
+        if (keyChar == null) {
+            // awt.01='{0}' parameter is null
+            throw new IllegalArgumentException(Messages.getString("awt.01", "keyChar")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        return getAWTKeyStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED, modifiers, false);
+    }
+
+    /**
+     * Returns an instance of AWTKeyStroke for a specified key code and set of
+     * modifiers. The key codes are defined in java.awt.event.KeyEvent class.
+     * The set of modifiers is given as a bitwise combination of masks taken
+     * from the following list:
+     * <ul>
+     * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.ALT_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.CTRL_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.META_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.SHIFT_DOWN_MASK</li> <li>
+     * java.awt.event.InputEvent.ALT_GRAPH_MASK</li> <li>
+     * java.awt.event.InputEvent.ALT_MASK</li> <li>
+     * java.awt.event.InputEvent.CTRL_MASK</li> <li>
+     * java.awt.event.InputEvent.META_MASK</li> <li>
+     * java.awt.event.InputEvent.SHIFT_MASK</li>
+     * </ul>
+     * 
+     * @param keyCode
+     *            the specified key code of keyboard.
+     * @param modifiers
+     *            the bit set of modifiers.
+     * @return the AWTKeyStroke.
+     */
+    public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) {
+        return getAWTKeyStroke(keyCode, modifiers, false);
+    }
+
+    /**
+     * Gets the AWTKeyStroke for a key event. This method obtains the key char
+     * and key code from the specified key event.
+     * 
+     * @param anEvent
+     *            the key event which identifies the desired AWTKeyStroke.
+     * @return the AWTKeyStroke for the key event.
+     */
+    public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) {
+        int id = anEvent.getID();
+        char undef = KeyEvent.CHAR_UNDEFINED;
+        char keyChar = (id == KeyEvent.KEY_TYPED ? anEvent.getKeyChar() : undef);
+        int keyCode = (keyChar == undef ? anEvent.getKeyCode() : KeyEvent.VK_UNDEFINED);
+        return getAWTKeyStroke(keyChar, keyCode, anEvent.getModifiersEx(),
+                id == KeyEvent.KEY_RELEASED);
+    }
+
+    /**
+     * Gets the key event type for the AWTKeyStroke object.
+     * 
+     * @return the key event type: KeyEvent.KEY_PRESSED, KeyEvent.KEY_TYPED, or
+     *         KeyEvent.KEY_RELEASED.
+     */
+    public final int getKeyEventType() {
+        if (keyCode == KeyEvent.VK_UNDEFINED) {
+            return KeyEvent.KEY_TYPED;
+        }
+        return (onKeyRelease ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED);
+    }
+
+    /**
+     * Returns true if the key event is associated with the AWTKeyStroke is
+     * KEY_RELEASED, false otherwise.
+     * 
+     * @return true, if if the key event associated with the AWTKeyStroke is
+     *         KEY_RELEASED, false otherwise.
+     */
+    public final boolean isOnKeyRelease() {
+        return onKeyRelease;
+    }
+
+    /**
+     * Read resolve.
+     * 
+     * @return the object.
+     * @throws ObjectStreamException
+     *             the object stream exception.
+     */
+    protected Object readResolve() throws ObjectStreamException {
+        return getAWTKeyStroke(this.keyChar, this.keyCode, this.modifiers, this.onKeyRelease);
+    }
+
+    /**
+     * Register subclass.
+     * 
+     * @param subclass
+     *            the subclass.
+     */
+    protected static void registerSubclass(Class<?> subclass) {
+        // ???AWT
+        /*
+         * if (subclass == null) { // awt.01='{0}' parameter is null throw new
+         * IllegalArgumentException(Messages.getString("awt.01", "subclass"));
+         * //$NON-NLS-1$ //$NON-NLS-2$ } if (!
+         * AWTKeyStroke.class.isAssignableFrom(subclass)) { // awt.67=subclass
+         * is not derived from AWTKeyStroke throw new
+         * ClassCastException(Messages.getString("awt.67")); //$NON-NLS-1$ } try
+         * { subConstructor = subclass.getDeclaredConstructor();
+         * subConstructor.setAccessible(true); } catch (SecurityException e) {
+         * throw new RuntimeException(e); } catch (NoSuchMethodException e) { //
+         * awt.68=subclass could not be instantiated throw new
+         * IllegalArgumentException(Messages.getString("awt.68")); //$NON-NLS-1$
+         * } cache.clear(); //flush the cache
+         */
+    }
+
+    /**
+     * Parses the modifier.
+     * 
+     * @param strMod
+     *            the str mod.
+     * @return the long.
+     */
+    private static long parseModifier(String strMod) {
+        long modifiers = 0l;
+        if (strMod.equals("shift")) { //$NON-NLS-1$
+            modifiers |= InputEvent.SHIFT_DOWN_MASK;
+        } else if (strMod.equals("control") || strMod.equals("ctrl")) { //$NON-NLS-1$ //$NON-NLS-2$
+            modifiers |= InputEvent.CTRL_DOWN_MASK;
+        } else if (strMod.equals("meta")) { //$NON-NLS-1$
+            modifiers |= InputEvent.META_DOWN_MASK;
+        } else if (strMod.equals("alt")) { //$NON-NLS-1$
+            modifiers |= InputEvent.ALT_DOWN_MASK;
+        } else if (strMod.equals("altGraph")) { //$NON-NLS-1$
+            modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
+        } else if (strMod.equals("button1")) { //$NON-NLS-1$
+            modifiers |= InputEvent.BUTTON1_DOWN_MASK;
+        } else if (strMod.equals("button2")) { //$NON-NLS-1$
+            modifiers |= InputEvent.BUTTON2_DOWN_MASK;
+        } else if (strMod.equals("button3")) { //$NON-NLS-1$
+            modifiers |= InputEvent.BUTTON3_DOWN_MASK;
+        }
+        return modifiers;
+    }
+
+    /**
+     * Parses the typed id.
+     * 
+     * @param strTyped
+     *            the str typed.
+     * @return true, if successful.
+     */
+    private static boolean parseTypedID(String strTyped) {
+        if (strTyped.equals("typed")) { //$NON-NLS-1$
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Parses the typed key.
+     * 
+     * @param strChar
+     *            the str char.
+     * @return the char.
+     */
+    private static char parseTypedKey(String strChar) {
+        char keyChar = KeyEvent.CHAR_UNDEFINED;
+
+        if (strChar.length() != 1) {
+            // awt.66=Invalid format
+            throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+        }
+        keyChar = strChar.charAt(0);
+        return keyChar;
+    }
+
+    /**
+     * Parses the pressed released id.
+     * 
+     * @param str
+     *            the str.
+     * @return the boolean.
+     */
+    private static Boolean parsePressedReleasedID(String str) {
+
+        if (str.equals("pressed")) { //$NON-NLS-1$
+            return Boolean.FALSE;
+        } else if (str.equals("released")) { //$NON-NLS-1$
+            return Boolean.TRUE;
+        }
+        return null;
+    }
+
+    /**
+     * Parses the key.
+     * 
+     * @param strCode
+     *            the str code.
+     * @return the int.
+     */
+    private static int parseKey(String strCode) {
+        int keyCode = KeyEvent.VK_UNDEFINED;
+
+        keyCode = getKeyCode(strCode);
+
+        if (keyCode == KeyEvent.VK_UNDEFINED) {
+            // awt.66=Invalid format
+            throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+        }
+        return keyCode;
+    }
+}
diff --git a/awt/java/awt/AWTListenerList.java b/awt/java/awt/AWTListenerList.java
new file mode 100644
index 0000000..3327d63
--- /dev/null
+++ b/awt/java/awt/AWTListenerList.java
@@ -0,0 +1,47 @@
+/*
+ *  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.
+ */
+
+package java.awt;
+
+import java.util.EventListener;
+
+import org.apache.harmony.awt.ListenerList;
+
+final class AWTListenerList<T extends EventListener> extends ListenerList<T> {
+    private static final long serialVersionUID = -2622077171532840953L;
+
+    private final Component owner;
+    
+    AWTListenerList() {
+        super();
+        this.owner = null;
+    }
+
+    AWTListenerList(Component owner) {
+        super();
+        this.owner = owner;
+    }
+
+    @Override
+    public void addUserListener(T listener) {
+        super.addUserListener(listener);
+
+        if (owner != null) {
+            owner.deprecatedEventHandler = false;
+        }
+    }
+}
diff --git a/awt/java/awt/AWTPermission.java b/awt/java/awt/AWTPermission.java
new file mode 100644
index 0000000..4bd8357
--- /dev/null
+++ b/awt/java/awt/AWTPermission.java
@@ -0,0 +1,61 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.security.BasicPermission;
+
+/**
+ * The AWTPermission specifies the name of the permission and the corresponding
+ * action list.
+ * 
+ * @since Android 1.0
+ */
+public final class AWTPermission extends BasicPermission {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 8890392402588814465L;
+
+    /**
+     * Instantiates a new AWTPermission with defined name and actions.
+     * 
+     * @param name
+     *            the name of a new AWTPermission.
+     * @param actions
+     *            the actions of a new AWTPermission.
+     */
+    public AWTPermission(String name, String actions) {
+        super(name, actions);
+    }
+
+    /**
+     * Instantiates a new AWT permission with the defined name.
+     * 
+     * @param name
+     *            the name of a new AWTPermission.
+     */
+    public AWTPermission(String name) {
+        super(name);
+    }
+
+}
diff --git a/awt/java/awt/ActiveEvent.java b/awt/java/awt/ActiveEvent.java
new file mode 100644
index 0000000..7044623
--- /dev/null
+++ b/awt/java/awt/ActiveEvent.java
@@ -0,0 +1,39 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+/**
+ * This interface defines events that know how to dispatch themselves. Such
+ * event can be placed upon the event queue and its dispatch method will be
+ * called when the event is dispatched.
+ * 
+ * @since Android 1.0
+ */
+public interface ActiveEvent {
+
+    /**
+     * Dispatches the event to the listeners of the event's source, or does
+     * whatever it is this event is supposed to do.
+     */
+    public void dispatch();
+
+}
diff --git a/awt/java/awt/Adjustable.java b/awt/java/awt/Adjustable.java
new file mode 100644
index 0000000..baf80f7
--- /dev/null
+++ b/awt/java/awt/Adjustable.java
@@ -0,0 +1,166 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.event.AdjustmentListener;
+
+/**
+ * The Adjustable interface represents an adjustable numeric value contained
+ * within a bounded range of values, such as the current location in scrollable
+ * region or the value of a gauge.
+ * 
+ * @since Android 1.0
+ */
+public interface Adjustable {
+
+    /**
+     * The Constant HORIZONTAL indicates that the Adjustable's orientation is
+     * horizontal.
+     */
+    public static final int HORIZONTAL = 0;
+
+    /**
+     * The Constant VERTICAL indicates that the Adjustable's orientation is
+     * vertical.
+     */
+    public static final int VERTICAL = 1;
+
+    /**
+     * The Constant NO_ORIENTATION indicates that the Adjustable has no
+     * orientation.
+     */
+    public static final int NO_ORIENTATION = 2;
+
+    /**
+     * Gets the value of the Adjustable.
+     * 
+     * @return the current value of the Adjustable.
+     */
+    public int getValue();
+
+    /**
+     * Sets the value to the Adjustable object.
+     * 
+     * @param a0
+     *            the new value of the Adjustable object.
+     */
+    public void setValue(int a0);
+
+    /**
+     * Adds the AdjustmentListener to current Adjustment.
+     * 
+     * @param a0
+     *            the AdjustmentListener object.
+     */
+    public void addAdjustmentListener(AdjustmentListener a0);
+
+    /**
+     * Gets the block increment of the Adjustable.
+     * 
+     * @return the block increment of the Adjustable.
+     */
+    public int getBlockIncrement();
+
+    /**
+     * Gets the maximum value of the Adjustable.
+     * 
+     * @return the maximum value of the Adjustable.
+     */
+    public int getMaximum();
+
+    /**
+     * Gets the minimum value of the Adjustable.
+     * 
+     * @return the minimum value of the Adjustable.
+     */
+    public int getMinimum();
+
+    /**
+     * Gets the orientation of the Adjustable.
+     * 
+     * @return the orientation of the Adjustable.
+     */
+    public int getOrientation();
+
+    /**
+     * Gets the unit increment of the Adjustable.
+     * 
+     * @return the unit increment of the Adjustable.
+     */
+    public int getUnitIncrement();
+
+    /**
+     * Gets the visible amount of the Adjustable.
+     * 
+     * @return the visible amount of the Adjustable.
+     */
+    public int getVisibleAmount();
+
+    /**
+     * Removes the adjustment listener of the Adjustable.
+     * 
+     * @param a0
+     *            the specified AdjustmentListener to be removed.
+     */
+    public void removeAdjustmentListener(AdjustmentListener a0);
+
+    /**
+     * Sets the block increment for the Adjustable.
+     * 
+     * @param a0
+     *            the new block increment.
+     */
+    public void setBlockIncrement(int a0);
+
+    /**
+     * Sets the maximum value of the Adjustable.
+     * 
+     * @param a0
+     *            the new maximum of the Adjustable.
+     */
+    public void setMaximum(int a0);
+
+    /**
+     * Sets the minimum value of the Adjustable.
+     * 
+     * @param a0
+     *            the new minimum of the Adjustable.
+     */
+    public void setMinimum(int a0);
+
+    /**
+     * Sets the unit increment of the Adjustable.
+     * 
+     * @param a0
+     *            the new unit increment of the Adjustable.
+     */
+    public void setUnitIncrement(int a0);
+
+    /**
+     * Sets the visible amount of the Adjustable.
+     * 
+     * @param a0
+     *            the new visible amount of the Adjustable.
+     */
+    public void setVisibleAmount(int a0);
+
+}
diff --git a/awt/java/awt/AlphaComposite.java b/awt/java/awt/AlphaComposite.java
new file mode 100644
index 0000000..8389eb4
--- /dev/null
+++ b/awt/java/awt/AlphaComposite.java
@@ -0,0 +1,352 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.RenderingHints;
+import java.awt.image.ColorModel;
+
+import org.apache.harmony.awt.gl.ICompositeContext;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The AlphaComposite class defines a basic alpha compositing rules for
+ * combining source and destination colors to achieve blending and transparency
+ * effects with graphics and images.
+ * 
+ * @since Android 1.0
+ */
+public final class AlphaComposite implements Composite {
+
+    /**
+     * The Constant CLEAR indicates that both the color and the alpha of the
+     * destination are cleared (Porter-Duff Clear rule).
+     */
+    public static final int CLEAR = 1;
+
+    /**
+     * The Constant SRC indicates that the source is copied to the destination
+     * (Porter-Duff Source rule).
+     */
+    public static final int SRC = 2;
+
+    /**
+     * The Constant DST indicates that the destination is left untouched
+     * (Porter-Duff Destination rule).
+     */
+    public static final int DST = 9;
+
+    /**
+     * The Constant SRC_OVER indicates that the source is composited over the
+     * destination (Porter-Duff Source Over Destination rule).
+     */
+    public static final int SRC_OVER = 3;
+
+    /**
+     * The Constant DST_OVER indicates that The destination is composited over
+     * the source and the result replaces the destination (Porter-Duff
+     * Destination Over Source rule).
+     */
+    public static final int DST_OVER = 4;
+
+    /**
+     * The Constant SRC_IN indicates that the part of the source lying inside of
+     * the destination replaces the destination (Porter-Duff Source In
+     * Destination rule).
+     */
+    public static final int SRC_IN = 5;
+
+    /**
+     * The Constant DST_IN indicates that the part of the destination lying
+     * inside of the source replaces the destination (Porter-Duff Destination In
+     * Source rule).
+     */
+    public static final int DST_IN = 6;
+
+    /**
+     * The Constant SRC_OUT indicates that the part of the source lying outside
+     * of the destination replaces the destination (Porter-Duff Source Held Out
+     * By Destination rule).
+     */
+    public static final int SRC_OUT = 7;
+
+    /**
+     * The Constant DST_OUT indicates that the part of the destination lying
+     * outside of the source replaces the destination (Porter-Duff Destination
+     * Held Out By Source rule).
+     */
+    public static final int DST_OUT = 8;
+
+    /**
+     * The Constant SRC_ATOP indicates that the part of the source lying inside
+     * of the destination is composited onto the destination (Porter-Duff Source
+     * Atop Destination rule).
+     */
+    public static final int SRC_ATOP = 10;
+
+    /**
+     * The Constant DST_ATOP indicates that the part of the destination lying
+     * inside of the source is composited over the source and replaces the
+     * destination (Porter-Duff Destination Atop Source rule).
+     */
+    public static final int DST_ATOP = 11;
+
+    /**
+     * The Constant XOR indicates that the part of the source that lies outside
+     * of the destination is combined with the part of the destination that lies
+     * outside of the source (Porter-Duff Source Xor Destination rule).
+     */
+    public static final int XOR = 12;
+
+    /**
+     * AlphaComposite object with the opaque CLEAR rule and an alpha of 1.0f.
+     */
+    public static final AlphaComposite Clear = new AlphaComposite(CLEAR);
+
+    /**
+     * AlphaComposite object with the opaque SRC rule and an alpha of 1.0f.
+     */
+    public static final AlphaComposite Src = new AlphaComposite(SRC);
+
+    /**
+     * AlphaComposite object with the opaque DST rule and an alpha of 1.0f.
+     */
+    public static final AlphaComposite Dst = new AlphaComposite(DST);
+
+    /**
+     * AlphaComposite object with the opaque SRC_OVER rule and an alpha of 1.0f.
+     */
+    public static final AlphaComposite SrcOver = new AlphaComposite(SRC_OVER);
+
+    /**
+     * AlphaComposite object with the opaque DST_OVER rule and an alpha of 1.0f.
+     */
+    public static final AlphaComposite DstOver = new AlphaComposite(DST_OVER);
+
+    /**
+     * AlphaComposite object with the opaque SRC_IN rule and an alpha of 1.0f.
+     */
+    public static final AlphaComposite SrcIn = new AlphaComposite(SRC_IN);
+
+    /**
+     * AlphaComposite object with the opaque DST_IN rule and an alpha of 1.0f.
+     */
+    public static final AlphaComposite DstIn = new AlphaComposite(DST_IN);
+
+    /**
+     * AlphaComposite object with the opaque SRC_OUT rule and an alpha of 1.0f.
+     */
+    public static final AlphaComposite SrcOut = new AlphaComposite(SRC_OUT);
+
+    /**
+     * AlphaComposite object with the opaque DST_OUT rule and an alpha of 1.0f.
+     */
+    public static final AlphaComposite DstOut = new AlphaComposite(DST_OUT);
+
+    /**
+     * AlphaComposite object with the opaque SRC_ATOP rule and an alpha of 1.0f.
+     */
+    public static final AlphaComposite SrcAtop = new AlphaComposite(SRC_ATOP);
+
+    /**
+     * AlphaComposite object with the opaque DST_ATOP rule and an alpha of 1.0f.
+     */
+    public static final AlphaComposite DstAtop = new AlphaComposite(DST_ATOP);
+
+    /**
+     * AlphaComposite object with the opaque XOR rule and an alpha of 1.0f.
+     */
+    public static final AlphaComposite Xor = new AlphaComposite(XOR);
+
+    /**
+     * The rule.
+     */
+    private int rule;
+
+    /**
+     * The alpha.
+     */
+    private float alpha;
+
+    /**
+     * Instantiates a new alpha composite. Creates a context for the compositing
+     * operation. The context contains state that is used in performing the
+     * compositing operation.
+     * 
+     * @param rule
+     *            the rule.
+     * @param alpha
+     *            the alpha.
+     */
+    private AlphaComposite(int rule, float alpha) {
+        if (rule < CLEAR || rule > XOR) {
+            // awt.11D=Unknown rule
+            throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$
+        }
+        if (alpha < 0.0f || alpha > 1.0f) {
+            // awt.11E=Wrong alpha value
+            throw new IllegalArgumentException(Messages.getString("awt.11E")); //$NON-NLS-1$
+        }
+
+        this.rule = rule;
+        this.alpha = alpha;
+    }
+
+    /**
+     * Instantiates a new alpha composite.
+     * 
+     * @param rule
+     *            the rule.
+     */
+    private AlphaComposite(int rule) {
+        this(rule, 1.0f);
+    }
+
+    /**
+     * Creates a CompositeContext object with the specified source ColorModel,
+     * destination ColorModel and RenderingHints parameters for a composing
+     * operation.
+     * 
+     * @param srcColorModel
+     *            the source's ColorModel.
+     * @param dstColorModel
+     *            the destination's ColorModel.
+     * @param hints
+     *            the RenderingHints object.
+     * @return the CompositeContext object.
+     * @see java.awt.Composite#createContext(java.awt.image.ColorModel,
+     *      java.awt.image.ColorModel, java.awt.RenderingHints)
+     */
+    public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel,
+            RenderingHints hints) {
+        return new ICompositeContext(this, srcColorModel, dstColorModel);
+    }
+
+    /**
+     * Compares the AlphaComposite object with the specified object.
+     * 
+     * @param obj
+     *            the Object to be compared.
+     * @return true, if the AlphaComposite object is equal to the specified
+     *         object.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof AlphaComposite)) {
+            return false;
+        }
+        AlphaComposite other = (AlphaComposite)obj;
+        return (this.rule == other.getRule() && this.alpha == other.getAlpha());
+    }
+
+    /**
+     * Returns the hash code of the AlphaComposite object.
+     * 
+     * @return the hash code of the AlphaComposite object.
+     */
+    @Override
+    public int hashCode() {
+        int hash = Float.floatToIntBits(alpha);
+        int tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= rule;
+        return hash;
+    }
+
+    /**
+     * Gets the compositing rule of this AlphaComposite object.
+     * 
+     * @return the compositing rule of this AlphaComposite object.
+     */
+    public int getRule() {
+        return rule;
+    }
+
+    /**
+     * Gets the alpha value of this AlphaComposite object; returns 1.0 if this
+     * AlphaComposite object doesn't have alpha value.
+     * 
+     * @return the alpha value of this AlphaComposite object or 1.0 if this
+     *         AlphaComposite object doesn't have alpha value.
+     */
+    public float getAlpha() {
+        return alpha;
+    }
+
+    /**
+     * Gets the AlphaComposite instance with the specified rule and alpha value.
+     * 
+     * @param rule
+     *            the compositing rule.
+     * @param alpha
+     *            the alpha value.
+     * @return the AlphaComposite instance.
+     */
+    public static AlphaComposite getInstance(int rule, float alpha) {
+        if (alpha == 1.0f) {
+            return getInstance(rule);
+        }
+        return new AlphaComposite(rule, alpha);
+    }
+
+    /**
+     * Gets the AlphaComposite instance with the specified rule.
+     * 
+     * @param rule
+     *            the compositing rule.
+     * @return the AlphaComposite instance.
+     */
+    public static AlphaComposite getInstance(int rule) {
+        switch (rule) {
+            case CLEAR:
+                return Clear;
+            case SRC:
+                return Src;
+            case DST:
+                return Dst;
+            case SRC_OVER:
+                return SrcOver;
+            case DST_OVER:
+                return DstOver;
+            case SRC_IN:
+                return SrcIn;
+            case DST_IN:
+                return DstIn;
+            case SRC_OUT:
+                return SrcOut;
+            case DST_OUT:
+                return DstOut;
+            case SRC_ATOP:
+                return SrcAtop;
+            case DST_ATOP:
+                return DstAtop;
+            case XOR:
+                return Xor;
+            default:
+                // awt.11D=Unknown rule
+                throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$
+        }
+    }
+
+}
diff --git a/awt/java/awt/BasicStroke.java b/awt/java/awt/BasicStroke.java
new file mode 100644
index 0000000..2457815
--- /dev/null
+++ b/awt/java/awt/BasicStroke.java
@@ -0,0 +1,2443 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.geom.GeneralPath;
+import java.awt.geom.PathIterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The BasicStroke class specifies a set of rendering attributes for the
+ * outlines of graphics primitives. The BasicStroke attributes describe the
+ * shape of the pen which draws the outline of a Shape and the decorations
+ * applied at the ends and joins of path segments of the Shape. The BasicStroke
+ * has the following rendering attributes:
+ * <p>
+ * <ul>
+ * <li>line width -the pen width which draws the outlines.</li>
+ * <li>end caps - indicates the decoration applied to the ends of unclosed
+ * subpaths and dash segments. The BasicStroke defines three different
+ * decorations: CAP_BUTT, CAP_ROUND, and CAP_SQUARE.</li>
+ * <li>line joins - indicates the decoration applied at the intersection of two
+ * path segments and at the intersection of the endpoints of a subpath. The
+ * BasicStroke defines three decorations: JOIN_BEVEL, JOIN_MITER, and
+ * JOIN_ROUND.</li>
+ * <li>miter limit - the limit to trim a line join that has a JOIN_MITER
+ * decoration.</li>
+ * <li>dash attributes - the definition of how to make a dash pattern by
+ * alternating between opaque and transparent sections</li>
+ * </ul>
+ * </p>
+ * 
+ * @since Android 1.0
+ */
+public class BasicStroke implements Stroke {
+
+    /**
+     * The Constant CAP_BUTT indicates the ends of unclosed subpaths and dash
+     * segments have no added decoration.
+     */
+    public static final int CAP_BUTT = 0;
+
+    /**
+     * The Constant CAP_ROUND indicates the ends of unclosed subpaths and dash
+     * segments have a round decoration.
+     */
+    public static final int CAP_ROUND = 1;
+
+    /**
+     * The Constant CAP_SQUARE indicates the ends of unclosed subpaths and dash
+     * segments have a square projection.
+     */
+    public static final int CAP_SQUARE = 2;
+
+    /**
+     * The Constant JOIN_MITER indicates that path segments are joined by
+     * extending their outside edges until they meet.
+     */
+    public static final int JOIN_MITER = 0;
+
+    /**
+     * The Constant JOIN_ROUND indicates that path segments are joined by
+     * rounding off the corner at a radius of half the line width.
+     */
+    public static final int JOIN_ROUND = 1;
+
+    /**
+     * The Constant JOIN_BEVEL indicates that path segments are joined by
+     * connecting the outer corners of their wide outlines with a straight
+     * segment.
+     */
+    public static final int JOIN_BEVEL = 2;
+
+    /**
+     * Constants for calculating.
+     */
+    static final int MAX_LEVEL = 20; // Maximal deepness of curve subdivision
+
+    /**
+     * The Constant CURVE_DELTA.
+     */
+    static final double CURVE_DELTA = 2.0; // Width tolerance
+
+    /**
+     * The Constant CORNER_ANGLE.
+     */
+    static final double CORNER_ANGLE = 4.0; // Minimum corner angle
+
+    /**
+     * The Constant CORNER_ZERO.
+     */
+    static final double CORNER_ZERO = 0.01; // Zero angle
+
+    /**
+     * The Constant CUBIC_ARC.
+     */
+    static final double CUBIC_ARC = 4.0 / 3.0 * (Math.sqrt(2.0) - 1);
+
+    /**
+     * Stroke width.
+     */
+    float width;
+
+    /**
+     * Stroke cap type.
+     */
+    int cap;
+
+    /**
+     * Stroke join type.
+     */
+    int join;
+
+    /**
+     * Stroke miter limit.
+     */
+    float miterLimit;
+
+    /**
+     * Stroke dashes array.
+     */
+    float dash[];
+
+    /**
+     * Stroke dash phase.
+     */
+    float dashPhase;
+
+    /**
+     * The temporary pre-calculated values.
+     */
+    double curveDelta;
+
+    /**
+     * The corner delta.
+     */
+    double cornerDelta;
+
+    /**
+     * The zero delta.
+     */
+    double zeroDelta;
+
+    /**
+     * The w2.
+     */
+    double w2;
+
+    /**
+     * The fmy.
+     */
+    double fmx, fmy;
+
+    /**
+     * The smy.
+     */
+    double scx, scy, smx, smy;
+
+    /**
+     * The cy.
+     */
+    double mx, my, cx, cy;
+
+    /**
+     * The temporary indicators.
+     */
+    boolean isMove;
+
+    /**
+     * The is first.
+     */
+    boolean isFirst;
+
+    /**
+     * The check move.
+     */
+    boolean checkMove;
+
+    /**
+     * The temporary and destination work paths.
+     */
+    BufferedPath dst, lp, rp, sp;
+
+    /**
+     * Stroke dasher class.
+     */
+    Dasher dasher;
+
+    /**
+     * Instantiates a new BasicStroke with default width, cap, join, limit, dash
+     * attributes parameters. The default parameters are a solid line of width
+     * 1.0, CAP_SQUARE, JOIN_MITER, a miter limit of 10.0, null dash attributes,
+     * and a dash phase of 0.0f.
+     */
+    public BasicStroke() {
+        this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
+    }
+
+    /**
+     * Instantiates a new BasicStroke with the specified width, caps, joins,
+     * limit, dash attributes, dash phase parameters.
+     * 
+     * @param width
+     *            the width of BasikStroke.
+     * @param cap
+     *            the end decoration of BasikStroke.
+     * @param join
+     *            the join segments decoration.
+     * @param miterLimit
+     *            the limit to trim the miter join.
+     * @param dash
+     *            the array with the dashing pattern.
+     * @param dashPhase
+     *            the offset to start the dashing pattern.
+     */
+    public BasicStroke(float width, int cap, int join, float miterLimit, float[] dash,
+            float dashPhase) {
+        if (width < 0.0f) {
+            // awt.133=Negative width
+            throw new IllegalArgumentException(Messages.getString("awt.133")); //$NON-NLS-1$
+        }
+        if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) {
+            // awt.134=Illegal cap
+            throw new IllegalArgumentException(Messages.getString("awt.134")); //$NON-NLS-1$
+        }
+        if (join != JOIN_MITER && join != JOIN_ROUND && join != JOIN_BEVEL) {
+            // awt.135=Illegal join
+            throw new IllegalArgumentException(Messages.getString("awt.135")); //$NON-NLS-1$
+        }
+        if (join == JOIN_MITER && miterLimit < 1.0f) {
+            // awt.136=miterLimit less than 1.0f
+            throw new IllegalArgumentException(Messages.getString("awt.136")); //$NON-NLS-1$
+        }
+        if (dash != null) {
+            if (dashPhase < 0.0f) {
+                // awt.137=Negative dashPhase
+                throw new IllegalArgumentException(Messages.getString("awt.137")); //$NON-NLS-1$
+            }
+            if (dash.length == 0) {
+                // awt.138=Zero dash length
+                throw new IllegalArgumentException(Messages.getString("awt.138")); //$NON-NLS-1$
+            }
+            ZERO: {
+                for (int i = 0; i < dash.length; i++) {
+                    if (dash[i] < 0.0) {
+                        // awt.139=Negative dash[{0}]
+                        throw new IllegalArgumentException(Messages.getString("awt.139", i)); //$NON-NLS-1$
+                    }
+                    if (dash[i] > 0.0) {
+                        break ZERO;
+                    }
+                }
+                // awt.13A=All dash lengths zero
+                throw new IllegalArgumentException(Messages.getString("awt.13A")); //$NON-NLS-1$
+            }
+        }
+        this.width = width;
+        this.cap = cap;
+        this.join = join;
+        this.miterLimit = miterLimit;
+        this.dash = dash;
+        this.dashPhase = dashPhase;
+    }
+
+    /**
+     * Instantiates a new BasicStroke with specified width, cap, join, limit and
+     * default dash attributes parameters.
+     * 
+     * @param width
+     *            the width of BasikStroke.
+     * @param cap
+     *            the end decoration of BasikStroke.
+     * @param join
+     *            the join segments decoration.
+     * @param miterLimit
+     *            the limit to trim the miter join.
+     */
+    public BasicStroke(float width, int cap, int join, float miterLimit) {
+        this(width, cap, join, miterLimit, null, 0.0f);
+    }
+
+    /**
+     * Instantiates a new BasicStroke with specified width, cap, join and
+     * default limit and dash attributes parameters.
+     * 
+     * @param width
+     *            the width of BasikStroke.
+     * @param cap
+     *            the end decoration of BasikStroke.
+     * @param join
+     *            the join segments decoration.
+     */
+    public BasicStroke(float width, int cap, int join) {
+        this(width, cap, join, 10.0f, null, 0.0f);
+    }
+
+    /**
+     * Instantiates a new BasicStroke with specified width and default cap,
+     * join, limit, dash attributes parameters.
+     * 
+     * @param width
+     *            the width of BasicStroke.
+     */
+    public BasicStroke(float width) {
+        this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
+    }
+
+    /**
+     * Gets the line width of the BasicStroke.
+     * 
+     * @return the line width of the BasicStroke.
+     */
+    public float getLineWidth() {
+        return width;
+    }
+
+    /**
+     * Gets the end cap style of the BasicStroke.
+     * 
+     * @return the end cap style of the BasicStroke.
+     */
+    public int getEndCap() {
+        return cap;
+    }
+
+    /**
+     * Gets the line join style of the BasicStroke.
+     * 
+     * @return the line join style of the BasicStroke.
+     */
+    public int getLineJoin() {
+        return join;
+    }
+
+    /**
+     * Gets the miter limit of the BasicStroke (the limit to trim the miter
+     * join).
+     * 
+     * @return the miter limit of the BasicStroke.
+     */
+    public float getMiterLimit() {
+        return miterLimit;
+    }
+
+    /**
+     * Gets the dash attributes array of the BasicStroke.
+     * 
+     * @return the dash attributes array of the BasicStroke.
+     */
+    public float[] getDashArray() {
+        return dash;
+    }
+
+    /**
+     * Gets the dash phase of the BasicStroke.
+     * 
+     * @return the dash phase of the BasicStroke.
+     */
+    public float getDashPhase() {
+        return dashPhase;
+    }
+
+    /**
+     * Returns hash code of this BasicStroke.
+     * 
+     * @return the hash code of this BasicStroke.
+     */
+    @Override
+    public int hashCode() {
+        HashCode hash = new HashCode();
+        hash.append(width);
+        hash.append(cap);
+        hash.append(join);
+        hash.append(miterLimit);
+        if (dash != null) {
+            hash.append(dashPhase);
+            for (float element : dash) {
+                hash.append(element);
+            }
+        }
+        return hash.hashCode();
+    }
+
+    /**
+     * Compares this BasicStroke object with the specified Object.
+     * 
+     * @param obj
+     *            the Object to be compared.
+     * @return true, if the Object is a BasicStroke with the same data values as
+     *         this BasicStroke; false otherwise.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof BasicStroke) {
+            BasicStroke bs = (BasicStroke)obj;
+            return bs.width == width && bs.cap == cap && bs.join == join
+                    && bs.miterLimit == miterLimit && bs.dashPhase == dashPhase
+                    && java.util.Arrays.equals(bs.dash, dash);
+        }
+        return false;
+    }
+
+    /**
+     * Calculates allowable curve derivation.
+     * 
+     * @param width
+     *            the width.
+     * @return the curve delta.
+     */
+    double getCurveDelta(double width) {
+        double a = width + CURVE_DELTA;
+        double cos = 1.0 - 2.0 * width * width / (a * a);
+        double sin = Math.sqrt(1.0 - cos * cos);
+        return Math.abs(sin / cos);
+    }
+
+    /**
+     * Calculates the value to detect a small angle.
+     * 
+     * @param width
+     *            the width.
+     * @return the corner delta.
+     */
+    double getCornerDelta(double width) {
+        return width * width * Math.sin(Math.PI * CORNER_ANGLE / 180.0);
+    }
+
+    /**
+     * Calculates value to detect a zero angle.
+     * 
+     * @param width
+     *            the width.
+     * @return the zero delta.
+     */
+    double getZeroDelta(double width) {
+        return width * width * Math.sin(Math.PI * CORNER_ZERO / 180.0);
+    }
+
+    /**
+     * Creates a Shape from the outline of the specified shape drawn with this
+     * BasicStroke.
+     * 
+     * @param s
+     *            the specified Shape to be stroked.
+     * @return the Shape of the stroked outline.
+     * @see java.awt.Stroke#createStrokedShape(java.awt.Shape)
+     */
+    public Shape createStrokedShape(Shape s) {
+        w2 = width / 2.0;
+        curveDelta = getCurveDelta(w2);
+        cornerDelta = getCornerDelta(w2);
+        zeroDelta = getZeroDelta(w2);
+
+        dst = new BufferedPath();
+        lp = new BufferedPath();
+        rp = new BufferedPath();
+
+        if (dash == null) {
+            createSolidShape(s.getPathIterator(null));
+        } else {
+            createDashedShape(s.getPathIterator(null));
+        }
+
+        return dst.createGeneralPath();
+    }
+
+    /**
+     * Generates a shape with a solid (not dashed) outline.
+     * 
+     * @param p
+     *            the PathIterator of source shape.
+     */
+    void createSolidShape(PathIterator p) {
+        double coords[] = new double[6];
+        mx = my = cx = cy = 0.0;
+        isMove = false;
+        isFirst = false;
+        checkMove = true;
+        boolean isClosed = true;
+
+        while (!p.isDone()) {
+            switch (p.currentSegment(coords)) {
+                case PathIterator.SEG_MOVETO:
+                    if (!isClosed) {
+                        closeSolidShape();
+                    }
+                    rp.clean();
+                    mx = cx = coords[0];
+                    my = cy = coords[1];
+                    isMove = true;
+                    isClosed = false;
+                    break;
+                case PathIterator.SEG_LINETO:
+                    addLine(cx, cy, cx = coords[0], cy = coords[1], true);
+                    break;
+                case PathIterator.SEG_QUADTO:
+                    addQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]);
+                    break;
+                case PathIterator.SEG_CUBICTO:
+                    addCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4],
+                            cy = coords[5]);
+                    break;
+                case PathIterator.SEG_CLOSE:
+                    addLine(cx, cy, mx, my, false);
+                    addJoin(lp, mx, my, lp.xMove, lp.yMove, true);
+                    addJoin(rp, mx, my, rp.xMove, rp.yMove, false);
+                    lp.closePath();
+                    rp.closePath();
+                    lp.appendReverse(rp);
+                    isClosed = true;
+                    break;
+            }
+            p.next();
+        }
+        if (!isClosed) {
+            closeSolidShape();
+        }
+
+        dst = lp;
+    }
+
+    /**
+     * Closes solid shape path.
+     */
+    void closeSolidShape() {
+        addCap(lp, cx, cy, rp.xLast, rp.yLast);
+        lp.combine(rp);
+        addCap(lp, mx, my, lp.xMove, lp.yMove);
+        lp.closePath();
+    }
+
+    /**
+     * Generates dashed stroked shape.
+     * 
+     * @param p
+     *            the PathIterator of source shape.
+     */
+    void createDashedShape(PathIterator p) {
+        double coords[] = new double[6];
+        mx = my = cx = cy = 0.0;
+        smx = smy = scx = scy = 0.0;
+        isMove = false;
+        checkMove = false;
+        boolean isClosed = true;
+
+        while (!p.isDone()) {
+            switch (p.currentSegment(coords)) {
+                case PathIterator.SEG_MOVETO:
+
+                    if (!isClosed) {
+                        closeDashedShape();
+                    }
+
+                    dasher = new Dasher(dash, dashPhase);
+                    lp.clean();
+                    rp.clean();
+                    sp = null;
+                    isFirst = true;
+                    isMove = true;
+                    isClosed = false;
+                    mx = cx = coords[0];
+                    my = cy = coords[1];
+                    break;
+                case PathIterator.SEG_LINETO:
+                    addDashLine(cx, cy, cx = coords[0], cy = coords[1]);
+                    break;
+                case PathIterator.SEG_QUADTO:
+                    addDashQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]);
+                    break;
+                case PathIterator.SEG_CUBICTO:
+                    addDashCubic(cx, cy, coords[0], coords[1], coords[2], coords[3],
+                            cx = coords[4], cy = coords[5]);
+                    break;
+                case PathIterator.SEG_CLOSE:
+                    addDashLine(cx, cy, cx = mx, cy = my);
+
+                    if (dasher.isConnected()) {
+                        // Connect current and head segments
+                        addJoin(lp, fmx, fmy, sp.xMove, sp.yMove, true);
+                        lp.join(sp);
+                        addJoin(lp, fmx, fmy, rp.xLast, rp.yLast, true);
+                        lp.combine(rp);
+                        addCap(lp, smx, smy, lp.xMove, lp.yMove);
+                        lp.closePath();
+                        dst.append(lp);
+                        sp = null;
+                    } else {
+                        closeDashedShape();
+                    }
+
+                    isClosed = true;
+                    break;
+            }
+            p.next();
+        }
+
+        if (!isClosed) {
+            closeDashedShape();
+        }
+
+    }
+
+    /**
+     * Closes dashed shape path.
+     */
+    void closeDashedShape() {
+        // Add head segment
+        if (sp != null) {
+            addCap(sp, fmx, fmy, sp.xMove, sp.yMove);
+            sp.closePath();
+            dst.append(sp);
+        }
+        if (lp.typeSize > 0) {
+            // Close current segment
+            if (!dasher.isClosed()) {
+                addCap(lp, scx, scy, rp.xLast, rp.yLast);
+                lp.combine(rp);
+                addCap(lp, smx, smy, lp.xMove, lp.yMove);
+                lp.closePath();
+            }
+            dst.append(lp);
+        }
+    }
+
+    /**
+     * Adds cap to the work path.
+     * 
+     * @param p
+     *            the BufferedPath object of work path.
+     * @param x0
+     *            the x coordinate of the source path.
+     * @param y0
+     *            the y coordinate on the source path.
+     * @param x2
+     *            the x coordinate of the next point on the work path.
+     * @param y2
+     *            the y coordinate of the next point on the work path.
+     */
+    void addCap(BufferedPath p, double x0, double y0, double x2, double y2) {
+        double x1 = p.xLast;
+        double y1 = p.yLast;
+        double x10 = x1 - x0;
+        double y10 = y1 - y0;
+        double x20 = x2 - x0;
+        double y20 = y2 - y0;
+
+        switch (cap) {
+            case CAP_BUTT:
+                p.lineTo(x2, y2);
+                break;
+            case CAP_ROUND:
+                double mx = x10 * CUBIC_ARC;
+                double my = y10 * CUBIC_ARC;
+
+                double x3 = x0 + y10;
+                double y3 = y0 - x10;
+
+                x10 *= CUBIC_ARC;
+                y10 *= CUBIC_ARC;
+                x20 *= CUBIC_ARC;
+                y20 *= CUBIC_ARC;
+
+                p.cubicTo(x1 + y10, y1 - x10, x3 + mx, y3 + my, x3, y3);
+                p.cubicTo(x3 - mx, y3 - my, x2 - y20, y2 + x20, x2, y2);
+                break;
+            case CAP_SQUARE:
+                p.lineTo(x1 + y10, y1 - x10);
+                p.lineTo(x2 - y20, y2 + x20);
+                p.lineTo(x2, y2);
+                break;
+        }
+    }
+
+    /**
+     * Adds bevel and miter join to the work path.
+     * 
+     * @param p
+     *            the BufferedPath object of work path.
+     * @param x0
+     *            the x coordinate of the source path.
+     * @param y0
+     *            the y coordinate on the source path.
+     * @param x2
+     *            the x coordinate of the next point on the work path.
+     * @param y2
+     *            the y coordinate of the next point on the work path.
+     * @param isLeft
+     *            the orientation of work path, true if work path lies to the
+     *            left from source path, false otherwise.
+     */
+    void addJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) {
+        double x1 = p.xLast;
+        double y1 = p.yLast;
+        double x10 = x1 - x0;
+        double y10 = y1 - y0;
+        double x20 = x2 - x0;
+        double y20 = y2 - y0;
+        double sin0 = x10 * y20 - y10 * x20;
+
+        // Small corner
+        if (-cornerDelta < sin0 && sin0 < cornerDelta) {
+            double cos0 = x10 * x20 + y10 * y20;
+            if (cos0 > 0.0) {
+                // if zero corner do nothing
+                if (-zeroDelta > sin0 || sin0 > zeroDelta) {
+                    double x3 = x0 + w2 * w2 * (y20 - y10) / sin0;
+                    double y3 = y0 + w2 * w2 * (x10 - x20) / sin0;
+                    p.setLast(x3, y3);
+                }
+                return;
+            }
+            // Zero corner
+            if (-zeroDelta < sin0 && sin0 < zeroDelta) {
+                p.lineTo(x2, y2);
+            }
+            return;
+        }
+
+        if (isLeft ^ (sin0 < 0.0)) {
+            // Twisted corner
+            p.lineTo(x0, y0);
+            p.lineTo(x2, y2);
+        } else {
+            switch (join) {
+                case JOIN_BEVEL:
+                    p.lineTo(x2, y2);
+                    break;
+                case JOIN_MITER:
+                    double s1 = x1 * x10 + y1 * y10;
+                    double s2 = x2 * x20 + y2 * y20;
+                    double x3 = (s1 * y20 - s2 * y10) / sin0;
+                    double y3 = (s2 * x10 - s1 * x20) / sin0;
+                    double x30 = x3 - x0;
+                    double y30 = y3 - y0;
+                    double miterLength = Math.sqrt(x30 * x30 + y30 * y30);
+                    if (miterLength < miterLimit * w2) {
+                        p.lineTo(x3, y3);
+                    }
+                    p.lineTo(x2, y2);
+                    break;
+                case JOIN_ROUND:
+                    addRoundJoin(p, x0, y0, x2, y2, isLeft);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Adds round join to the work path.
+     * 
+     * @param p
+     *            the BufferedPath object of work path.
+     * @param x0
+     *            the x coordinate of the source path.
+     * @param y0
+     *            the y coordinate on the source path.
+     * @param x2
+     *            the x coordinate of the next point on the work path.
+     * @param y2
+     *            the y coordinate of the next point on the work path.
+     * @param isLeft
+     *            the orientation of work path, true if work path lies to the
+     *            left from source path, false otherwise.
+     */
+    void addRoundJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) {
+        double x1 = p.xLast;
+        double y1 = p.yLast;
+        double x10 = x1 - x0;
+        double y10 = y1 - y0;
+        double x20 = x2 - x0;
+        double y20 = y2 - y0;
+
+        double x30 = x10 + x20;
+        double y30 = y10 + y20;
+
+        double l30 = Math.sqrt(x30 * x30 + y30 * y30);
+
+        if (l30 < 1E-5) {
+            p.lineTo(x2, y2);
+            return;
+        }
+
+        double w = w2 / l30;
+
+        x30 *= w;
+        y30 *= w;
+
+        double x3 = x0 + x30;
+        double y3 = y0 + y30;
+
+        double cos = x10 * x20 + y10 * y20;
+        double a = Math.acos(cos / (w2 * w2));
+        if (cos >= 0.0) {
+            double k = 4.0 / 3.0 * Math.tan(a / 4.0);
+            if (isLeft) {
+                k = -k;
+            }
+
+            x10 *= k;
+            y10 *= k;
+            x20 *= k;
+            y20 *= k;
+
+            p.cubicTo(x1 - y10, y1 + x10, x2 + y20, y2 - x20, x2, y2);
+        } else {
+            double k = 4.0 / 3.0 * Math.tan(a / 8.0);
+            if (isLeft) {
+                k = -k;
+            }
+
+            x10 *= k;
+            y10 *= k;
+            x20 *= k;
+            y20 *= k;
+            x30 *= k;
+            y30 *= k;
+
+            p.cubicTo(x1 - y10, y1 + x10, x3 + y30, y3 - x30, x3, y3);
+            p.cubicTo(x3 - y30, y3 + x30, x2 + y20, y2 - x20, x2, y2);
+        }
+
+    }
+
+    /**
+     * Adds solid line segment to the work path.
+     * 
+     * @param x1
+     *            the x coordinate of the start line point.
+     * @param y1
+     *            the y coordinate of the start line point.
+     * @param x2
+     *            the x coordinate of the end line point.
+     * @param y2
+     *            the y coordinate of the end line point.
+     * @param zero
+     *            if true it's allowable to add zero length line segment.
+     */
+    void addLine(double x1, double y1, double x2, double y2, boolean zero) {
+        double dx = x2 - x1;
+        double dy = y2 - y1;
+
+        if (dx == 0.0 && dy == 0.0) {
+            if (!zero) {
+                return;
+            }
+            dx = w2;
+            dy = 0;
+        } else {
+            double w = w2 / Math.sqrt(dx * dx + dy * dy);
+            dx *= w;
+            dy *= w;
+        }
+
+        double lx1 = x1 - dy;
+        double ly1 = y1 + dx;
+        double rx1 = x1 + dy;
+        double ry1 = y1 - dx;
+
+        if (checkMove) {
+            if (isMove) {
+                isMove = false;
+                lp.moveTo(lx1, ly1);
+                rp.moveTo(rx1, ry1);
+            } else {
+                addJoin(lp, x1, y1, lx1, ly1, true);
+                addJoin(rp, x1, y1, rx1, ry1, false);
+            }
+        }
+
+        lp.lineTo(x2 - dy, y2 + dx);
+        rp.lineTo(x2 + dy, y2 - dx);
+    }
+
+    /**
+     * Adds solid quad segment to the work path.
+     * 
+     * @param x1
+     *            the x coordinate of the first control point.
+     * @param y1
+     *            the y coordinate of the first control point.
+     * @param x2
+     *            the x coordinate of the second control point.
+     * @param y2
+     *            the y coordinate of the second control point.
+     * @param x3
+     *            the x coordinate of the third control point.
+     * @param y3
+     *            the y coordinate of the third control point.
+     */
+    void addQuad(double x1, double y1, double x2, double y2, double x3, double y3) {
+        double x21 = x2 - x1;
+        double y21 = y2 - y1;
+        double x23 = x2 - x3;
+        double y23 = y2 - y3;
+
+        double l21 = Math.sqrt(x21 * x21 + y21 * y21);
+        double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+
+        if (l21 == 0.0 && l23 == 0.0) {
+            addLine(x1, y1, x3, y3, false);
+            return;
+        }
+
+        if (l21 == 0.0) {
+            addLine(x2, y2, x3, y3, false);
+            return;
+        }
+
+        if (l23 == 0.0) {
+            addLine(x1, y1, x2, y2, false);
+            return;
+        }
+
+        double w;
+        w = w2 / l21;
+        double mx1 = -y21 * w;
+        double my1 = x21 * w;
+        w = w2 / l23;
+        double mx3 = y23 * w;
+        double my3 = -x23 * w;
+
+        double lx1 = x1 + mx1;
+        double ly1 = y1 + my1;
+        double rx1 = x1 - mx1;
+        double ry1 = y1 - my1;
+
+        if (checkMove) {
+            if (isMove) {
+                isMove = false;
+                lp.moveTo(lx1, ly1);
+                rp.moveTo(rx1, ry1);
+            } else {
+                addJoin(lp, x1, y1, lx1, ly1, true);
+                addJoin(rp, x1, y1, rx1, ry1, false);
+            }
+        }
+
+        if (x21 * y23 - y21 * x23 == 0.0) {
+            // On line curve
+            if (x21 * x23 + y21 * y23 > 0.0) {
+                // Twisted curve
+                if (l21 == l23) {
+                    double px = x1 + (x21 + x23) / 4.0;
+                    double py = y1 + (y21 + y23) / 4.0;
+                    lp.lineTo(px + mx1, py + my1);
+                    rp.lineTo(px - mx1, py - my1);
+                    lp.lineTo(px - mx1, py - my1);
+                    rp.lineTo(px + mx1, py + my1);
+                    lp.lineTo(x3 - mx1, y3 - my1);
+                    rp.lineTo(x3 + mx1, y3 + my1);
+                } else {
+                    double px1, py1;
+                    double k = l21 / (l21 + l23);
+                    double px = x1 + (x21 + x23) * k * k;
+                    double py = y1 + (y21 + y23) * k * k;
+                    px1 = (x1 + px) / 2.0;
+                    py1 = (y1 + py) / 2.0;
+                    lp.quadTo(px1 + mx1, py1 + my1, px + mx1, py + my1);
+                    rp.quadTo(px1 - mx1, py1 - my1, px - mx1, py - my1);
+                    lp.lineTo(px - mx1, py - my1);
+                    rp.lineTo(px + mx1, py + my1);
+                    px1 = (x3 + px) / 2.0;
+                    py1 = (y3 + py) / 2.0;
+                    lp.quadTo(px1 - mx1, py1 - my1, x3 - mx1, y3 - my1);
+                    rp.quadTo(px1 + mx1, py1 + my1, x3 + mx1, y3 + my1);
+                }
+            } else {
+                // Simple curve
+                lp.quadTo(x2 + mx1, y2 + my1, x3 + mx3, y3 + my3);
+                rp.quadTo(x2 - mx1, y2 - my1, x3 - mx3, y3 - my3);
+            }
+        } else {
+            addSubQuad(x1, y1, x2, y2, x3, y3, 0);
+        }
+    }
+
+    /**
+     * Subdivides solid quad curve to make outline for source quad segment and
+     * adds it to work path.
+     * 
+     * @param x1
+     *            the x coordinate of the first control point.
+     * @param y1
+     *            the y coordinate of the first control point.
+     * @param x2
+     *            the x coordinate of the second control point.
+     * @param y2
+     *            the y coordinate of the second control point.
+     * @param x3
+     *            the x coordinate of the third control point.
+     * @param y3
+     *            the y coordinate of the third control point.
+     * @param level
+     *            the maximum level of subdivision deepness.
+     */
+    void addSubQuad(double x1, double y1, double x2, double y2, double x3, double y3, int level) {
+        double x21 = x2 - x1;
+        double y21 = y2 - y1;
+        double x23 = x2 - x3;
+        double y23 = y2 - y3;
+
+        double cos = x21 * x23 + y21 * y23;
+        double sin = x21 * y23 - y21 * x23;
+
+        if (level < MAX_LEVEL && (cos >= 0.0 || (Math.abs(sin / cos) > curveDelta))) {
+            double c1x = (x2 + x1) / 2.0;
+            double c1y = (y2 + y1) / 2.0;
+            double c2x = (x2 + x3) / 2.0;
+            double c2y = (y2 + y3) / 2.0;
+            double c3x = (c1x + c2x) / 2.0;
+            double c3y = (c1y + c2y) / 2.0;
+            addSubQuad(x1, y1, c1x, c1y, c3x, c3y, level + 1);
+            addSubQuad(c3x, c3y, c2x, c2y, x3, y3, level + 1);
+        } else {
+            double w;
+            double l21 = Math.sqrt(x21 * x21 + y21 * y21);
+            double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+            w = w2 / sin;
+            double mx2 = (x21 * l23 + x23 * l21) * w;
+            double my2 = (y21 * l23 + y23 * l21) * w;
+            w = w2 / l23;
+            double mx3 = y23 * w;
+            double my3 = -x23 * w;
+            lp.quadTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3);
+            rp.quadTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3);
+        }
+    }
+
+    /**
+     * Adds solid cubic segment to the work path.
+     * 
+     * @param x1
+     *            the x coordinate of the first control point.
+     * @param y1
+     *            the y coordinate of the first control point.
+     * @param x2
+     *            the x coordinate of the second control point.
+     * @param y2
+     *            the y coordinate of the second control point.
+     * @param x3
+     *            the x coordinate of the third control point.
+     * @param y3
+     *            the y coordinate of the third control point.
+     * @param x4
+     *            the x coordinate of the fours control point.
+     * @param y4
+     *            the y coordinate of the fours control point.
+     */
+    void addCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4,
+            double y4) {
+        double x12 = x1 - x2;
+        double y12 = y1 - y2;
+        double x23 = x2 - x3;
+        double y23 = y2 - y3;
+        double x34 = x3 - x4;
+        double y34 = y3 - y4;
+
+        double l12 = Math.sqrt(x12 * x12 + y12 * y12);
+        double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+        double l34 = Math.sqrt(x34 * x34 + y34 * y34);
+
+        // All edges are zero
+        if (l12 == 0.0 && l23 == 0.0 && l34 == 0.0) {
+            addLine(x1, y1, x4, y4, false);
+            return;
+        }
+
+        // One zero edge
+        if (l12 == 0.0 && l23 == 0.0) {
+            addLine(x3, y3, x4, y4, false);
+            return;
+        }
+
+        if (l23 == 0.0 && l34 == 0.0) {
+            addLine(x1, y1, x2, y2, false);
+            return;
+        }
+
+        if (l12 == 0.0 && l34 == 0.0) {
+            addLine(x2, y2, x3, y3, false);
+            return;
+        }
+
+        double w, mx1, my1, mx4, my4;
+        boolean onLine;
+
+        if (l12 == 0.0) {
+            w = w2 / l23;
+            mx1 = y23 * w;
+            my1 = -x23 * w;
+            w = w2 / l34;
+            mx4 = y34 * w;
+            my4 = -x34 * w;
+            onLine = -x23 * y34 + y23 * x34 == 0.0; // sin3
+        } else if (l34 == 0.0) {
+            w = w2 / l12;
+            mx1 = y12 * w;
+            my1 = -x12 * w;
+            w = w2 / l23;
+            mx4 = y23 * w;
+            my4 = -x23 * w;
+            onLine = -x12 * y23 + y12 * x23 == 0.0; // sin2
+        } else {
+            w = w2 / l12;
+            mx1 = y12 * w;
+            my1 = -x12 * w;
+            w = w2 / l34;
+            mx4 = y34 * w;
+            my4 = -x34 * w;
+            if (l23 == 0.0) {
+                onLine = -x12 * y34 + y12 * x34 == 0.0;
+            } else {
+                onLine = -x12 * y34 + y12 * x34 == 0.0 && -x12 * y23 + y12 * x23 == 0.0 && // sin2
+                        -x23 * y34 + y23 * x34 == 0.0; // sin3
+            }
+        }
+
+        double lx1 = x1 + mx1;
+        double ly1 = y1 + my1;
+        double rx1 = x1 - mx1;
+        double ry1 = y1 - my1;
+
+        if (checkMove) {
+            if (isMove) {
+                isMove = false;
+                lp.moveTo(lx1, ly1);
+                rp.moveTo(rx1, ry1);
+            } else {
+                addJoin(lp, x1, y1, lx1, ly1, true);
+                addJoin(rp, x1, y1, rx1, ry1, false);
+            }
+        }
+
+        if (onLine) {
+            if ((x1 == x2 && y1 < y2) || x1 < x2) {
+                l12 = -l12;
+            }
+            if ((x2 == x3 && y2 < y3) || x2 < x3) {
+                l23 = -l23;
+            }
+            if ((x3 == x4 && y3 < y4) || x3 < x4) {
+                l34 = -l34;
+            }
+            double d = l23 * l23 - l12 * l34;
+            double roots[] = new double[3];
+            int rc = 0;
+            if (d == 0.0) {
+                double t = (l12 - l23) / (l12 + l34 - l23 - l23);
+                if (0.0 < t && t < 1.0) {
+                    roots[rc++] = t;
+                }
+            } else if (d > 0.0) {
+                d = Math.sqrt(d);
+                double z = l12 + l34 - l23 - l23;
+                double t;
+                t = (l12 - l23 + d) / z;
+                if (0.0 < t && t < 1.0) {
+                    roots[rc++] = t;
+                }
+                t = (l12 - l23 - d) / z;
+                if (0.0 < t && t < 1.0) {
+                    roots[rc++] = t;
+                }
+            }
+
+            if (rc > 0) {
+                // Sort roots
+                if (rc == 2 && roots[0] > roots[1]) {
+                    double tmp = roots[0];
+                    roots[0] = roots[1];
+                    roots[1] = tmp;
+                }
+                roots[rc++] = 1.0;
+
+                double ax = -x34 - x12 + x23 + x23;
+                double ay = -y34 - y12 + y23 + y23;
+                double bx = 3.0 * (-x23 + x12);
+                double by = 3.0 * (-y23 + y12);
+                double cx = 3.0 * (-x12);
+                double cy = 3.0 * (-y12);
+                double xPrev = x1;
+                double yPrev = y1;
+                for (int i = 0; i < rc; i++) {
+                    double t = roots[i];
+                    double px = t * (t * (t * ax + bx) + cx) + x1;
+                    double py = t * (t * (t * ay + by) + cy) + y1;
+                    double px1 = (xPrev + px) / 2.0;
+                    double py1 = (yPrev + py) / 2.0;
+                    lp.cubicTo(px1 + mx1, py1 + my1, px1 + mx1, py1 + my1, px + mx1, py + my1);
+                    rp.cubicTo(px1 - mx1, py1 - my1, px1 - mx1, py1 - my1, px - mx1, py - my1);
+                    if (i < rc - 1) {
+                        lp.lineTo(px - mx1, py - my1);
+                        rp.lineTo(px + mx1, py + my1);
+                    }
+                    xPrev = px;
+                    yPrev = py;
+                    mx1 = -mx1;
+                    my1 = -my1;
+                }
+            } else {
+                lp.cubicTo(x2 + mx1, y2 + my1, x3 + mx4, y3 + my4, x4 + mx4, y4 + my4);
+                rp.cubicTo(x2 - mx1, y2 - my1, x3 - mx4, y3 - my4, x4 - mx4, y4 - my4);
+            }
+        } else {
+            addSubCubic(x1, y1, x2, y2, x3, y3, x4, y4, 0);
+        }
+    }
+
+    /**
+     * Subdivides solid cubic curve to make outline for source quad segment and
+     * adds it to work path.
+     * 
+     * @param x1
+     *            the x coordinate of the first control point.
+     * @param y1
+     *            the y coordinate of the first control point.
+     * @param x2
+     *            the x coordinate of the second control point.
+     * @param y2
+     *            the y coordinate of the second control point.
+     * @param x3
+     *            the x coordinate of the third control point.
+     * @param y3
+     *            the y coordinate of the third control point.
+     * @param x4
+     *            the x coordinate of the fours control point.
+     * @param y4
+     *            the y coordinate of the fours control point.
+     * @param level
+     *            the maximum level of subdivision deepness.
+     */
+    void addSubCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4,
+            double y4, int level) {
+        double x12 = x1 - x2;
+        double y12 = y1 - y2;
+        double x23 = x2 - x3;
+        double y23 = y2 - y3;
+        double x34 = x3 - x4;
+        double y34 = y3 - y4;
+
+        double cos2 = -x12 * x23 - y12 * y23;
+        double cos3 = -x23 * x34 - y23 * y34;
+        double sin2 = -x12 * y23 + y12 * x23;
+        double sin3 = -x23 * y34 + y23 * x34;
+        double sin0 = -x12 * y34 + y12 * x34;
+        double cos0 = -x12 * x34 - y12 * y34;
+
+        if (level < MAX_LEVEL
+                && (sin2 != 0.0 || sin3 != 0.0 || sin0 != 0.0)
+                && (cos2 >= 0.0 || cos3 >= 0.0 || cos0 >= 0.0
+                        || (Math.abs(sin2 / cos2) > curveDelta)
+                        || (Math.abs(sin3 / cos3) > curveDelta) || (Math.abs(sin0 / cos0) > curveDelta))) {
+            double cx = (x2 + x3) / 2.0;
+            double cy = (y2 + y3) / 2.0;
+            double lx2 = (x2 + x1) / 2.0;
+            double ly2 = (y2 + y1) / 2.0;
+            double rx3 = (x3 + x4) / 2.0;
+            double ry3 = (y3 + y4) / 2.0;
+            double lx3 = (cx + lx2) / 2.0;
+            double ly3 = (cy + ly2) / 2.0;
+            double rx2 = (cx + rx3) / 2.0;
+            double ry2 = (cy + ry3) / 2.0;
+            cx = (lx3 + rx2) / 2.0;
+            cy = (ly3 + ry2) / 2.0;
+            addSubCubic(x1, y1, lx2, ly2, lx3, ly3, cx, cy, level + 1);
+            addSubCubic(cx, cy, rx2, ry2, rx3, ry3, x4, y4, level + 1);
+        } else {
+            double w, mx1, my1, mx2, my2, mx3, my3, mx4, my4;
+            double l12 = Math.sqrt(x12 * x12 + y12 * y12);
+            double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+            double l34 = Math.sqrt(x34 * x34 + y34 * y34);
+
+            if (l12 == 0.0) {
+                w = w2 / l23;
+                mx1 = y23 * w;
+                my1 = -x23 * w;
+                w = w2 / l34;
+                mx4 = y34 * w;
+                my4 = -x34 * w;
+            } else if (l34 == 0.0) {
+                w = w2 / l12;
+                mx1 = y12 * w;
+                my1 = -x12 * w;
+                w = w2 / l23;
+                mx4 = y23 * w;
+                my4 = -x23 * w;
+            } else {
+                // Common case
+                w = w2 / l12;
+                mx1 = y12 * w;
+                my1 = -x12 * w;
+                w = w2 / l34;
+                mx4 = y34 * w;
+                my4 = -x34 * w;
+            }
+
+            if (sin2 == 0.0) {
+                mx2 = mx1;
+                my2 = my1;
+            } else {
+                w = w2 / sin2;
+                mx2 = -(x12 * l23 - x23 * l12) * w;
+                my2 = -(y12 * l23 - y23 * l12) * w;
+            }
+            if (sin3 == 0.0) {
+                mx3 = mx4;
+                my3 = my4;
+            } else {
+                w = w2 / sin3;
+                mx3 = -(x23 * l34 - x34 * l23) * w;
+                my3 = -(y23 * l34 - y34 * l23) * w;
+            }
+
+            lp.cubicTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3, x4 + mx4, y4 + my4);
+            rp.cubicTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3, x4 - mx4, y4 - my4);
+        }
+    }
+
+    /**
+     * Adds dashed line segment to the work path.
+     * 
+     * @param x1
+     *            the x coordinate of the start line point.
+     * @param y1
+     *            the y coordinate of the start line point.
+     * @param x2
+     *            the x coordinate of the end line point.
+     * @param y2
+     *            the y coordinate of the end line point.
+     */
+    void addDashLine(double x1, double y1, double x2, double y2) {
+        double x21 = x2 - x1;
+        double y21 = y2 - y1;
+
+        double l21 = Math.sqrt(x21 * x21 + y21 * y21);
+
+        if (l21 == 0.0) {
+            return;
+        }
+
+        double px1, py1;
+        px1 = py1 = 0.0;
+        double w = w2 / l21;
+        double mx = -y21 * w;
+        double my = x21 * w;
+
+        dasher.init(new DashIterator.Line(l21));
+
+        while (!dasher.eof()) {
+            double t = dasher.getValue();
+            scx = x1 + t * x21;
+            scy = y1 + t * y21;
+
+            if (dasher.isOpen()) {
+                px1 = scx;
+                py1 = scy;
+                double lx1 = px1 + mx;
+                double ly1 = py1 + my;
+                double rx1 = px1 - mx;
+                double ry1 = py1 - my;
+                if (isMove) {
+                    isMove = false;
+                    smx = px1;
+                    smy = py1;
+                    rp.clean();
+                    lp.moveTo(lx1, ly1);
+                    rp.moveTo(rx1, ry1);
+                } else {
+                    addJoin(lp, x1, y1, lx1, ly1, true);
+                    addJoin(rp, x1, y1, rx1, ry1, false);
+                }
+            } else if (dasher.isContinue()) {
+                double px2 = scx;
+                double py2 = scy;
+                lp.lineTo(px2 + mx, py2 + my);
+                rp.lineTo(px2 - mx, py2 - my);
+                if (dasher.close) {
+                    addCap(lp, px2, py2, rp.xLast, rp.yLast);
+                    lp.combine(rp);
+                    if (isFirst) {
+                        isFirst = false;
+                        fmx = smx;
+                        fmy = smy;
+                        sp = lp;
+                        lp = new BufferedPath();
+                    } else {
+                        addCap(lp, smx, smy, lp.xMove, lp.yMove);
+                        lp.closePath();
+                    }
+                    isMove = true;
+                }
+            }
+
+            dasher.next();
+        }
+    }
+
+    /**
+     * Adds dashed quad segment to the work path.
+     * 
+     * @param x1
+     *            the x coordinate of the first control point.
+     * @param y1
+     *            the y coordinate of the first control point.
+     * @param x2
+     *            the x coordinate of the second control point.
+     * @param y2
+     *            the y coordinate of the second control point.
+     * @param x3
+     *            the x coordinate of the third control point.
+     * @param y3
+     *            the y coordinate of the third control point.
+     */
+    void addDashQuad(double x1, double y1, double x2, double y2, double x3, double y3) {
+
+        double x21 = x2 - x1;
+        double y21 = y2 - y1;
+        double x23 = x2 - x3;
+        double y23 = y2 - y3;
+
+        double l21 = Math.sqrt(x21 * x21 + y21 * y21);
+        double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+
+        if (l21 == 0.0 && l23 == 0.0) {
+            return;
+        }
+
+        if (l21 == 0.0) {
+            addDashLine(x2, y2, x3, y3);
+            return;
+        }
+
+        if (l23 == 0.0) {
+            addDashLine(x1, y1, x2, y2);
+            return;
+        }
+
+        double ax = x1 + x3 - x2 - x2;
+        double ay = y1 + y3 - y2 - y2;
+        double bx = x2 - x1;
+        double by = y2 - y1;
+        double cx = x1;
+        double cy = y1;
+
+        double px1, py1, dx1, dy1;
+        px1 = py1 = dx1 = dy1 = 0.0;
+        double prev = 0.0;
+
+        dasher.init(new DashIterator.Quad(x1, y1, x2, y2, x3, y3));
+
+        while (!dasher.eof()) {
+            double t = dasher.getValue();
+            double dx = t * ax + bx;
+            double dy = t * ay + by;
+            scx = t * (dx + bx) + cx; // t^2 * ax + 2.0 * t * bx + cx
+            scy = t * (dy + by) + cy; // t^2 * ay + 2.0 * t * by + cy
+            if (dasher.isOpen()) {
+                px1 = scx;
+                py1 = scy;
+                dx1 = dx;
+                dy1 = dy;
+                double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1);
+                double mx1 = -dy1 * w;
+                double my1 = dx1 * w;
+                double lx1 = px1 + mx1;
+                double ly1 = py1 + my1;
+                double rx1 = px1 - mx1;
+                double ry1 = py1 - my1;
+                if (isMove) {
+                    isMove = false;
+                    smx = px1;
+                    smy = py1;
+                    rp.clean();
+                    lp.moveTo(lx1, ly1);
+                    rp.moveTo(rx1, ry1);
+                } else {
+                    addJoin(lp, x1, y1, lx1, ly1, true);
+                    addJoin(rp, x1, y1, rx1, ry1, false);
+                }
+            } else if (dasher.isContinue()) {
+                double px3 = scx;
+                double py3 = scy;
+                double sx = x2 - x23 * prev;
+                double sy = y2 - y23 * prev;
+                double t2 = (t - prev) / (1 - prev);
+                double px2 = px1 + (sx - px1) * t2;
+                double py2 = py1 + (sy - py1) * t2;
+
+                addQuad(px1, py1, px2, py2, px3, py3);
+                if (dasher.isClosed()) {
+                    addCap(lp, px3, py3, rp.xLast, rp.yLast);
+                    lp.combine(rp);
+                    if (isFirst) {
+                        isFirst = false;
+                        fmx = smx;
+                        fmy = smy;
+                        sp = lp;
+                        lp = new BufferedPath();
+                    } else {
+                        addCap(lp, smx, smy, lp.xMove, lp.yMove);
+                        lp.closePath();
+                    }
+                    isMove = true;
+                }
+            }
+
+            prev = t;
+            dasher.next();
+        }
+    }
+
+    /**
+     * Adds dashed cubic segment to the work path.
+     * 
+     * @param x1
+     *            the x coordinate of the first control point.
+     * @param y1
+     *            the y coordinate of the first control point.
+     * @param x2
+     *            the x coordinate of the second control point.
+     * @param y2
+     *            the y coordinate of the second control point.
+     * @param x3
+     *            the x coordinate of the third control point.
+     * @param y3
+     *            the y coordinate of the third control point.
+     * @param x4
+     *            the x coordinate of the fours control point.
+     * @param y4
+     *            the y coordinate of the fours control point.
+     */
+    void addDashCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4,
+            double y4) {
+
+        double x12 = x1 - x2;
+        double y12 = y1 - y2;
+        double x23 = x2 - x3;
+        double y23 = y2 - y3;
+        double x34 = x3 - x4;
+        double y34 = y3 - y4;
+
+        double l12 = Math.sqrt(x12 * x12 + y12 * y12);
+        double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+        double l34 = Math.sqrt(x34 * x34 + y34 * y34);
+
+        // All edges are zero
+        if (l12 == 0.0 && l23 == 0.0 && l34 == 0.0) {
+            // NOTHING
+            return;
+        }
+
+        // One zero edge
+        if (l12 == 0.0 && l23 == 0.0) {
+            addDashLine(x3, y3, x4, y4);
+            return;
+        }
+
+        if (l23 == 0.0 && l34 == 0.0) {
+            addDashLine(x1, y1, x2, y2);
+            return;
+        }
+
+        if (l12 == 0.0 && l34 == 0.0) {
+            addDashLine(x2, y2, x3, y3);
+            return;
+        }
+
+        double ax = x4 - x1 + 3.0 * (x2 - x3);
+        double ay = y4 - y1 + 3.0 * (y2 - y3);
+        double bx = 3.0 * (x1 + x3 - x2 - x2);
+        double by = 3.0 * (y1 + y3 - y2 - y2);
+        double cx = 3.0 * (x2 - x1);
+        double cy = 3.0 * (y2 - y1);
+        double dx = x1;
+        double dy = y1;
+
+        double px1 = 0.0;
+        double py1 = 0.0;
+        double prev = 0.0;
+
+        dasher.init(new DashIterator.Cubic(x1, y1, x2, y2, x3, y3, x4, y4));
+
+        while (!dasher.eof()) {
+
+            double t = dasher.getValue();
+            scx = t * (t * (t * ax + bx) + cx) + dx;
+            scy = t * (t * (t * ay + by) + cy) + dy;
+            if (dasher.isOpen()) {
+                px1 = scx;
+                py1 = scy;
+                double dx1 = t * (t * (ax + ax + ax) + bx + bx) + cx;
+                double dy1 = t * (t * (ay + ay + ay) + by + by) + cy;
+                double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1);
+                double mx1 = -dy1 * w;
+                double my1 = dx1 * w;
+                double lx1 = px1 + mx1;
+                double ly1 = py1 + my1;
+                double rx1 = px1 - mx1;
+                double ry1 = py1 - my1;
+                if (isMove) {
+                    isMove = false;
+                    smx = px1;
+                    smy = py1;
+                    rp.clean();
+                    lp.moveTo(lx1, ly1);
+                    rp.moveTo(rx1, ry1);
+                } else {
+                    addJoin(lp, x1, y1, lx1, ly1, true);
+                    addJoin(rp, x1, y1, rx1, ry1, false);
+                }
+            } else if (dasher.isContinue()) {
+                double sx1 = x2 - x23 * prev;
+                double sy1 = y2 - y23 * prev;
+                double sx2 = x3 - x34 * prev;
+                double sy2 = y3 - y34 * prev;
+                double sx3 = sx1 + (sx2 - sx1) * prev;
+                double sy3 = sy1 + (sy2 - sy1) * prev;
+                double t2 = (t - prev) / (1 - prev);
+                double sx4 = sx3 + (sx2 - sx3) * t2;
+                double sy4 = sy3 + (sy2 - sy3) * t2;
+
+                double px4 = scx;
+                double py4 = scy;
+                double px2 = px1 + (sx3 - px1) * t2;
+                double py2 = py1 + (sy3 - py1) * t2;
+                double px3 = px2 + (sx4 - px2) * t2;
+                double py3 = py2 + (sy4 - py2) * t2;
+
+                addCubic(px1, py1, px2, py2, px3, py3, px4, py4);
+                if (dasher.isClosed()) {
+                    addCap(lp, px4, py4, rp.xLast, rp.yLast);
+                    lp.combine(rp);
+                    if (isFirst) {
+                        isFirst = false;
+                        fmx = smx;
+                        fmy = smy;
+                        sp = lp;
+                        lp = new BufferedPath();
+                    } else {
+                        addCap(lp, smx, smy, lp.xMove, lp.yMove);
+                        lp.closePath();
+                    }
+                    isMove = true;
+                }
+            }
+
+            prev = t;
+            dasher.next();
+        }
+    }
+
+    /**
+     * Dasher class provides dashing for particular dash style.
+     */
+    class Dasher {
+
+        /**
+         * The pos.
+         */
+        double pos;
+
+        /**
+         * The first.
+         */
+        boolean close, visible, first;
+
+        /**
+         * The dash.
+         */
+        float dash[];
+
+        /**
+         * The phase.
+         */
+        float phase;
+
+        /**
+         * The index.
+         */
+        int index;
+
+        /**
+         * The iter.
+         */
+        DashIterator iter;
+
+        /**
+         * Instantiates a new dasher.
+         * 
+         * @param dash
+         *            the dash.
+         * @param phase
+         *            the phase.
+         */
+        Dasher(float dash[], float phase) {
+            this.dash = dash;
+            this.phase = phase;
+            index = 0;
+            pos = phase;
+            visible = true;
+            while (pos >= dash[index]) {
+                visible = !visible;
+                pos -= dash[index];
+                index = (index + 1) % dash.length;
+            }
+            pos = -pos;
+            first = visible;
+        }
+
+        /**
+         * Inits the.
+         * 
+         * @param iter
+         *            the iter.
+         */
+        void init(DashIterator iter) {
+            this.iter = iter;
+            close = true;
+        }
+
+        /**
+         * Checks if is open.
+         * 
+         * @return true, if is open.
+         */
+        boolean isOpen() {
+            return visible && pos < iter.length;
+        }
+
+        /**
+         * Checks if is continue.
+         * 
+         * @return true, if is continue.
+         */
+        boolean isContinue() {
+            return !visible && pos > 0;
+        }
+
+        /**
+         * Checks if is closed.
+         * 
+         * @return true, if is closed.
+         */
+        boolean isClosed() {
+            return close;
+        }
+
+        /**
+         * Checks if is connected.
+         * 
+         * @return true, if is connected.
+         */
+        boolean isConnected() {
+            return first && !close;
+        }
+
+        /**
+         * Eof.
+         * 
+         * @return true, if successful.
+         */
+        boolean eof() {
+            if (!close) {
+                pos -= iter.length;
+                return true;
+            }
+            if (pos >= iter.length) {
+                if (visible) {
+                    pos -= iter.length;
+                    return true;
+                }
+                close = pos == iter.length;
+            }
+            return false;
+        }
+
+        /**
+         * Next.
+         */
+        void next() {
+            if (close) {
+                pos += dash[index];
+                index = (index + 1) % dash.length;
+            } else {
+                // Go back
+                index = (index + dash.length - 1) % dash.length;
+                pos -= dash[index];
+            }
+            visible = !visible;
+        }
+
+        /**
+         * Gets the value.
+         * 
+         * @return the value.
+         */
+        double getValue() {
+            double t = iter.getNext(pos);
+            return t < 0 ? 0 : (t > 1 ? 1 : t);
+        }
+
+    }
+
+    /**
+     * DashIterator class provides dashing for particular segment type.
+     */
+    static abstract class DashIterator {
+
+        /**
+         * The Constant FLATNESS.
+         */
+        static final double FLATNESS = 1.0;
+
+        /**
+         * The Class Line.
+         */
+        static class Line extends DashIterator {
+
+            /**
+             * Instantiates a new line.
+             * 
+             * @param len
+             *            the len.
+             */
+            Line(double len) {
+                length = len;
+            }
+
+            @Override
+            double getNext(double dashPos) {
+                return dashPos / length;
+            }
+
+        }
+
+        /**
+         * The Class Quad.
+         */
+        static class Quad extends DashIterator {
+
+            /**
+             * The val size.
+             */
+            int valSize;
+
+            /**
+             * The val pos.
+             */
+            int valPos;
+
+            /**
+             * The cur len.
+             */
+            double curLen;
+
+            /**
+             * The prev len.
+             */
+            double prevLen;
+
+            /**
+             * The last len.
+             */
+            double lastLen;
+
+            /**
+             * The values.
+             */
+            double[] values;
+
+            /**
+             * The step.
+             */
+            double step;
+
+            /**
+             * Instantiates a new quad.
+             * 
+             * @param x1
+             *            the x1.
+             * @param y1
+             *            the y1.
+             * @param x2
+             *            the x2.
+             * @param y2
+             *            the y2.
+             * @param x3
+             *            the x3.
+             * @param y3
+             *            the y3.
+             */
+            Quad(double x1, double y1, double x2, double y2, double x3, double y3) {
+
+                double nx = x1 + x3 - x2 - x2;
+                double ny = y1 + y3 - y2 - y2;
+
+                int n = (int)(1 + Math.sqrt(0.75 * (Math.abs(nx) + Math.abs(ny)) * FLATNESS));
+                step = 1.0 / n;
+
+                double ax = x1 + x3 - x2 - x2;
+                double ay = y1 + y3 - y2 - y2;
+                double bx = 2.0 * (x2 - x1);
+                double by = 2.0 * (y2 - y1);
+
+                double dx1 = step * (step * ax + bx);
+                double dy1 = step * (step * ay + by);
+                double dx2 = step * (step * ax * 2.0);
+                double dy2 = step * (step * ay * 2.0);
+                double vx = x1;
+                double vy = y1;
+
+                valSize = n;
+                values = new double[valSize];
+                double pvx = vx;
+                double pvy = vy;
+                length = 0.0;
+                for (int i = 0; i < n; i++) {
+                    vx += dx1;
+                    vy += dy1;
+                    dx1 += dx2;
+                    dy1 += dy2;
+                    double lx = vx - pvx;
+                    double ly = vy - pvy;
+                    values[i] = Math.sqrt(lx * lx + ly * ly);
+                    length += values[i];
+                    pvx = vx;
+                    pvy = vy;
+                }
+
+                valPos = 0;
+                curLen = 0.0;
+                prevLen = 0.0;
+            }
+
+            @Override
+            double getNext(double dashPos) {
+                double t = 2.0;
+                while (curLen <= dashPos && valPos < valSize) {
+                    prevLen = curLen;
+                    curLen += lastLen = values[valPos++];
+                }
+                if (curLen > dashPos) {
+                    t = (valPos - 1 + (dashPos - prevLen) / lastLen) * step;
+                }
+                return t;
+            }
+
+        }
+
+        /**
+         * The Class Cubic.
+         */
+        static class Cubic extends DashIterator {
+
+            /**
+             * The val size.
+             */
+            int valSize;
+
+            /**
+             * The val pos.
+             */
+            int valPos;
+
+            /**
+             * The cur len.
+             */
+            double curLen;
+
+            /**
+             * The prev len.
+             */
+            double prevLen;
+
+            /**
+             * The last len.
+             */
+            double lastLen;
+
+            /**
+             * The values.
+             */
+            double[] values;
+
+            /**
+             * The step.
+             */
+            double step;
+
+            /**
+             * Instantiates a new cubic.
+             * 
+             * @param x1
+             *            the x1.
+             * @param y1
+             *            the y1.
+             * @param x2
+             *            the x2.
+             * @param y2
+             *            the y2.
+             * @param x3
+             *            the x3.
+             * @param y3
+             *            the y3.
+             * @param x4
+             *            the x4.
+             * @param y4
+             *            the y4.
+             */
+            Cubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4,
+                    double y4) {
+
+                double nx1 = x1 + x3 - x2 - x2;
+                double ny1 = y1 + y3 - y2 - y2;
+                double nx2 = x2 + x4 - x3 - x3;
+                double ny2 = y2 + y4 - y3 - y3;
+
+                double max = Math.max(Math.abs(nx1) + Math.abs(ny1), Math.abs(nx2) + Math.abs(ny2));
+                int n = (int)(1 + Math.sqrt(0.75 * max) * FLATNESS);
+                step = 1.0 / n;
+
+                double ax = x4 - x1 + 3.0 * (x2 - x3);
+                double ay = y4 - y1 + 3.0 * (y2 - y3);
+                double bx = 3.0 * (x1 + x3 - x2 - x2);
+                double by = 3.0 * (y1 + y3 - y2 - y2);
+                double cx = 3.0 * (x2 - x1);
+                double cy = 3.0 * (y2 - y1);
+
+                double dx1 = step * (step * (step * ax + bx) + cx);
+                double dy1 = step * (step * (step * ay + by) + cy);
+                double dx2 = step * (step * (step * ax * 6.0 + bx * 2.0));
+                double dy2 = step * (step * (step * ay * 6.0 + by * 2.0));
+                double dx3 = step * (step * (step * ax * 6.0));
+                double dy3 = step * (step * (step * ay * 6.0));
+                double vx = x1;
+                double vy = y1;
+
+                valSize = n;
+                values = new double[valSize];
+                double pvx = vx;
+                double pvy = vy;
+                length = 0.0;
+                for (int i = 0; i < n; i++) {
+                    vx += dx1;
+                    vy += dy1;
+                    dx1 += dx2;
+                    dy1 += dy2;
+                    dx2 += dx3;
+                    dy2 += dy3;
+                    double lx = vx - pvx;
+                    double ly = vy - pvy;
+                    values[i] = Math.sqrt(lx * lx + ly * ly);
+                    length += values[i];
+                    pvx = vx;
+                    pvy = vy;
+                }
+
+                valPos = 0;
+                curLen = 0.0;
+                prevLen = 0.0;
+            }
+
+            @Override
+            double getNext(double dashPos) {
+                double t = 2.0;
+                while (curLen <= dashPos && valPos < valSize) {
+                    prevLen = curLen;
+                    curLen += lastLen = values[valPos++];
+                }
+                if (curLen > dashPos) {
+                    t = (valPos - 1 + (dashPos - prevLen) / lastLen) * step;
+                }
+                return t;
+            }
+
+        }
+
+        /**
+         * The length.
+         */
+        double length;
+
+        /**
+         * Gets the next.
+         * 
+         * @param dashPos
+         *            the dash pos.
+         * @return the next.
+         */
+        abstract double getNext(double dashPos);
+
+    }
+
+    /**
+     * BufferedPath class provides work path storing and processing.
+     */
+    static class BufferedPath {
+
+        /**
+         * The Constant bufCapacity.
+         */
+        private static final int bufCapacity = 10;
+
+        /**
+         * The point shift.
+         */
+        static int pointShift[] = {
+                2, // MOVETO
+                2, // LINETO
+                4, // QUADTO
+                6, // CUBICTO
+                0
+        }; // CLOSE
+
+        /**
+         * The types.
+         */
+        byte[] types;
+
+        /**
+         * The points.
+         */
+        float[] points;
+
+        /**
+         * The type size.
+         */
+        int typeSize;
+
+        /**
+         * The point size.
+         */
+        int pointSize;
+
+        /**
+         * The x last.
+         */
+        float xLast;
+
+        /**
+         * The y last.
+         */
+        float yLast;
+
+        /**
+         * The x move.
+         */
+        float xMove;
+
+        /**
+         * The y move.
+         */
+        float yMove;
+
+        /**
+         * Instantiates a new buffered path.
+         */
+        public BufferedPath() {
+            types = new byte[bufCapacity];
+            points = new float[bufCapacity * 2];
+        }
+
+        /**
+         * Check buf.
+         * 
+         * @param typeCount
+         *            the type count.
+         * @param pointCount
+         *            the point count.
+         */
+        void checkBuf(int typeCount, int pointCount) {
+            if (typeSize + typeCount > types.length) {
+                byte tmp[] = new byte[typeSize + Math.max(bufCapacity, typeCount)];
+                System.arraycopy(types, 0, tmp, 0, typeSize);
+                types = tmp;
+            }
+            if (pointSize + pointCount > points.length) {
+                float tmp[] = new float[pointSize + Math.max(bufCapacity * 2, pointCount)];
+                System.arraycopy(points, 0, tmp, 0, pointSize);
+                points = tmp;
+            }
+        }
+
+        /**
+         * Checks if is empty.
+         * 
+         * @return true, if is empty.
+         */
+        boolean isEmpty() {
+            return typeSize == 0;
+        }
+
+        /**
+         * Clean.
+         */
+        void clean() {
+            typeSize = 0;
+            pointSize = 0;
+        }
+
+        /**
+         * Move to.
+         * 
+         * @param x
+         *            the x.
+         * @param y
+         *            the y.
+         */
+        void moveTo(double x, double y) {
+            checkBuf(1, 2);
+            types[typeSize++] = PathIterator.SEG_MOVETO;
+            points[pointSize++] = xMove = (float)x;
+            points[pointSize++] = yMove = (float)y;
+        }
+
+        /**
+         * Line to.
+         * 
+         * @param x
+         *            the x.
+         * @param y
+         *            the y.
+         */
+        void lineTo(double x, double y) {
+            checkBuf(1, 2);
+            types[typeSize++] = PathIterator.SEG_LINETO;
+            points[pointSize++] = xLast = (float)x;
+            points[pointSize++] = yLast = (float)y;
+        }
+
+        /**
+         * Quad to.
+         * 
+         * @param x1
+         *            the x1.
+         * @param y1
+         *            the y1.
+         * @param x2
+         *            the x2.
+         * @param y2
+         *            the y2.
+         */
+        void quadTo(double x1, double y1, double x2, double y2) {
+            checkBuf(1, 4);
+            types[typeSize++] = PathIterator.SEG_QUADTO;
+            points[pointSize++] = (float)x1;
+            points[pointSize++] = (float)y1;
+            points[pointSize++] = xLast = (float)x2;
+            points[pointSize++] = yLast = (float)y2;
+        }
+
+        /**
+         * Cubic to.
+         * 
+         * @param x1
+         *            the x1.
+         * @param y1
+         *            the y1.
+         * @param x2
+         *            the x2.
+         * @param y2
+         *            the y2.
+         * @param x3
+         *            the x3.
+         * @param y3
+         *            the y3.
+         */
+        void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) {
+            checkBuf(1, 6);
+            types[typeSize++] = PathIterator.SEG_CUBICTO;
+            points[pointSize++] = (float)x1;
+            points[pointSize++] = (float)y1;
+            points[pointSize++] = (float)x2;
+            points[pointSize++] = (float)y2;
+            points[pointSize++] = xLast = (float)x3;
+            points[pointSize++] = yLast = (float)y3;
+        }
+
+        /**
+         * Close path.
+         */
+        void closePath() {
+            checkBuf(1, 0);
+            types[typeSize++] = PathIterator.SEG_CLOSE;
+        }
+
+        /**
+         * Sets the last.
+         * 
+         * @param x
+         *            the x.
+         * @param y
+         *            the y.
+         */
+        void setLast(double x, double y) {
+            points[pointSize - 2] = xLast = (float)x;
+            points[pointSize - 1] = yLast = (float)y;
+        }
+
+        /**
+         * Append.
+         * 
+         * @param p
+         *            the p.
+         */
+        void append(BufferedPath p) {
+            checkBuf(p.typeSize, p.pointSize);
+            System.arraycopy(p.points, 0, points, pointSize, p.pointSize);
+            System.arraycopy(p.types, 0, types, typeSize, p.typeSize);
+            pointSize += p.pointSize;
+            typeSize += p.typeSize;
+            xLast = points[pointSize - 2];
+            yLast = points[pointSize - 1];
+        }
+
+        /**
+         * Append reverse.
+         * 
+         * @param p
+         *            the p.
+         */
+        void appendReverse(BufferedPath p) {
+            checkBuf(p.typeSize, p.pointSize);
+            // Skip last point, beacause it's the first point of the second path
+            for (int i = p.pointSize - 2; i >= 0; i -= 2) {
+                points[pointSize++] = p.points[i + 0];
+                points[pointSize++] = p.points[i + 1];
+            }
+            // Skip first type, beacuse it's always MOVETO
+            int closeIndex = 0;
+            for (int i = p.typeSize - 1; i >= 0; i--) {
+                byte type = p.types[i];
+                if (type == PathIterator.SEG_MOVETO) {
+                    types[closeIndex] = PathIterator.SEG_MOVETO;
+                    types[typeSize++] = PathIterator.SEG_CLOSE;
+                } else {
+                    if (type == PathIterator.SEG_CLOSE) {
+                        closeIndex = typeSize;
+                    }
+                    types[typeSize++] = type;
+                }
+            }
+            xLast = points[pointSize - 2];
+            yLast = points[pointSize - 1];
+        }
+
+        /**
+         * Join.
+         * 
+         * @param p
+         *            the p.
+         */
+        void join(BufferedPath p) {
+            // Skip MOVETO
+            checkBuf(p.typeSize - 1, p.pointSize - 2);
+            System.arraycopy(p.points, 2, points, pointSize, p.pointSize - 2);
+            System.arraycopy(p.types, 1, types, typeSize, p.typeSize - 1);
+            pointSize += p.pointSize - 2;
+            typeSize += p.typeSize - 1;
+            xLast = points[pointSize - 2];
+            yLast = points[pointSize - 1];
+        }
+
+        /**
+         * Combine.
+         * 
+         * @param p
+         *            the p.
+         */
+        void combine(BufferedPath p) {
+            checkBuf(p.typeSize - 1, p.pointSize - 2);
+            // Skip last point, beacause it's the first point of the second path
+            for (int i = p.pointSize - 4; i >= 0; i -= 2) {
+                points[pointSize++] = p.points[i + 0];
+                points[pointSize++] = p.points[i + 1];
+            }
+            // Skip first type, beacuse it's always MOVETO
+            for (int i = p.typeSize - 1; i >= 1; i--) {
+                types[typeSize++] = p.types[i];
+            }
+            xLast = points[pointSize - 2];
+            yLast = points[pointSize - 1];
+        }
+
+        /**
+         * Creates the general path.
+         * 
+         * @return the general path.
+         */
+        GeneralPath createGeneralPath() {
+            GeneralPath p = new GeneralPath();
+            int j = 0;
+            for (int i = 0; i < typeSize; i++) {
+                int type = types[i];
+                switch (type) {
+                    case PathIterator.SEG_MOVETO:
+                        p.moveTo(points[j], points[j + 1]);
+                        break;
+                    case PathIterator.SEG_LINETO:
+                        p.lineTo(points[j], points[j + 1]);
+                        break;
+                    case PathIterator.SEG_QUADTO:
+                        p.quadTo(points[j], points[j + 1], points[j + 2], points[j + 3]);
+                        break;
+                    case PathIterator.SEG_CUBICTO:
+                        p.curveTo(points[j], points[j + 1], points[j + 2], points[j + 3],
+                                points[j + 4], points[j + 5]);
+                        break;
+                    case PathIterator.SEG_CLOSE:
+                        p.closePath();
+                        break;
+                }
+                j += pointShift[type];
+            }
+            return p;
+        }
+
+    }
+
+}
diff --git a/awt/java/awt/BufferCapabilities.java b/awt/java/awt/BufferCapabilities.java
new file mode 100644
index 0000000..cd5fe7b
--- /dev/null
+++ b/awt/java/awt/BufferCapabilities.java
@@ -0,0 +1,195 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+/**
+ * The BufferCapabilities class represents the capabilities and other properties
+ * of the image buffers.
+ * 
+ * @since Android 1.0
+ */
+public class BufferCapabilities implements Cloneable {
+
+    /**
+     * The front buffer capabilities.
+     */
+    private final ImageCapabilities frontBufferCapabilities;
+
+    /**
+     * The back buffer capabilities.
+     */
+    private final ImageCapabilities backBufferCapabilities;
+
+    /**
+     * The flip contents.
+     */
+    private final FlipContents flipContents;
+
+    /**
+     * Instantiates a new BufferCapabilities object.
+     * 
+     * @param frontBufferCapabilities
+     *            the front buffer capabilities, can not be null.
+     * @param backBufferCapabilities
+     *            the the back and intermediate buffers capabilities, can not be
+     *            null.
+     * @param flipContents
+     *            the back buffer contents after page flipping, null if page
+     *            flipping is not used.
+     */
+    public BufferCapabilities(ImageCapabilities frontBufferCapabilities,
+            ImageCapabilities backBufferCapabilities, FlipContents flipContents) {
+        if (frontBufferCapabilities == null || backBufferCapabilities == null) {
+            throw new IllegalArgumentException();
+        }
+
+        this.frontBufferCapabilities = frontBufferCapabilities;
+        this.backBufferCapabilities = backBufferCapabilities;
+        this.flipContents = flipContents;
+    }
+
+    /**
+     * Returns a copy of the BufferCapabilities object.
+     * 
+     * @return a copy of the BufferCapabilities object.
+     */
+    @Override
+    public Object clone() {
+        return new BufferCapabilities(frontBufferCapabilities, backBufferCapabilities, flipContents);
+    }
+
+    /**
+     * Gets the image capabilities of the front buffer.
+     * 
+     * @return the ImageCapabilities object represented capabilities of the
+     *         front buffer.
+     */
+    public ImageCapabilities getFrontBufferCapabilities() {
+        return frontBufferCapabilities;
+    }
+
+    /**
+     * Gets the image capabilities of the back buffer.
+     * 
+     * @return the ImageCapabilities object represented capabilities of the back
+     *         buffer.
+     */
+    public ImageCapabilities getBackBufferCapabilities() {
+        return backBufferCapabilities;
+    }
+
+    /**
+     * Gets the flip contents of the back buffer after page-flipping.
+     * 
+     * @return the FlipContents of the back buffer after page-flipping.
+     */
+    public FlipContents getFlipContents() {
+        return flipContents;
+    }
+
+    /**
+     * Checks if the buffer strategy uses page flipping.
+     * 
+     * @return true, if the buffer strategy uses page flipping, false otherwise.
+     */
+    public boolean isPageFlipping() {
+        return flipContents != null;
+    }
+
+    /**
+     * Checks if page flipping is only available in full-screen mode.
+     * 
+     * @return true, if page flipping is only available in full-screen mode,
+     *         false otherwise.
+     */
+    public boolean isFullScreenRequired() {
+        return false;
+    }
+
+    /**
+     * Checks if page flipping can be performed using more than two buffers.
+     * 
+     * @return true, if page flipping can be performed using more than two
+     *         buffers, false otherwise.
+     */
+    public boolean isMultiBufferAvailable() {
+        return false;
+    }
+
+    /**
+     * The FlipContents class represents a set of possible back buffer contents
+     * after page-flipping.
+     * 
+     * @since Android 1.0
+     */
+    public static final class FlipContents {
+
+        /**
+         * The back buffered contents are cleared with the background color
+         * after flipping.
+         */
+        public static final FlipContents BACKGROUND = new FlipContents();
+
+        /**
+         * The back buffered contents are copied to the front buffer before
+         * flipping.
+         */
+        public static final FlipContents COPIED = new FlipContents();
+
+        /**
+         * The back buffer contents are the prior contents of the front buffer.
+         */
+        public static final FlipContents PRIOR = new FlipContents();
+
+        /**
+         * The back buffer contents are undefined after flipping
+         */
+        public static final FlipContents UNDEFINED = new FlipContents();
+
+        /**
+         * Instantiates a new flip contents.
+         */
+        private FlipContents() {
+
+        }
+
+        /**
+         * Returns the hash code of the FlipContents object.
+         * 
+         * @return the hash code of the FlipContents object.
+         */
+        @Override
+        public int hashCode() {
+            return super.hashCode();
+        }
+
+        /**
+         * Returns the String representation of the FlipContents object.
+         * 
+         * @return the string
+         */
+        @Override
+        public String toString() {
+            return super.toString();
+        }
+    }
+}
diff --git a/awt/java/awt/Color.java b/awt/java/awt/Color.java
new file mode 100644
index 0000000..93c532d
--- /dev/null
+++ b/awt/java/awt/Color.java
@@ -0,0 +1,990 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferInt;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.io.Serializable;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Color class defines colors in the default sRGB color space or in the
+ * specified ColorSpace. Every Color contains alpha value. The alpha value
+ * defines the transparency of a color and can be represented by a float value
+ * in the range 0.0 - 1.0 or 0 - 255.
+ * 
+ * @since Android 1.0
+ */
+public class Color implements Paint, Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 118526816881161077L;
+
+    /*
+     * The values of the following colors are based on 1.5 release behavior
+     * which can be revealed using the following or similar code: Color c =
+     * Color.white; System.out.println(c);
+     */
+
+    /**
+     * The color white.
+     */
+    public static final Color white = new Color(255, 255, 255);
+
+    /**
+     * The color white.
+     */
+    public static final Color WHITE = white;
+
+    /**
+     * The color light gray.
+     */
+    public static final Color lightGray = new Color(192, 192, 192);
+
+    /**
+     * The color light gray.
+     */
+    public static final Color LIGHT_GRAY = lightGray;
+
+    /**
+     * The color gray.
+     */
+    public static final Color gray = new Color(128, 128, 128);
+
+    /**
+     * The color gray.
+     */
+    public static final Color GRAY = gray;
+
+    /**
+     * The color dark gray.
+     */
+    public static final Color darkGray = new Color(64, 64, 64);
+
+    /**
+     * The color dark gray.
+     */
+    public static final Color DARK_GRAY = darkGray;
+
+    /**
+     * The color black.
+     */
+    public static final Color black = new Color(0, 0, 0);
+
+    /**
+     * The color black.
+     */
+    public static final Color BLACK = black;
+
+    /**
+     * The color red.
+     */
+    public static final Color red = new Color(255, 0, 0);
+
+    /**
+     * The color red.
+     */
+    public static final Color RED = red;
+
+    /**
+     * The color pink.
+     */
+    public static final Color pink = new Color(255, 175, 175);
+
+    /**
+     * The color pink.
+     */
+    public static final Color PINK = pink;
+
+    /**
+     * The color orange.
+     */
+    public static final Color orange = new Color(255, 200, 0);
+
+    /**
+     * The color orange.
+     */
+    public static final Color ORANGE = orange;
+
+    /**
+     * The color yellow.
+     */
+    public static final Color yellow = new Color(255, 255, 0);
+
+    /**
+     * The color yellow.
+     */
+    public static final Color YELLOW = yellow;
+
+    /**
+     * The color green.
+     */
+    public static final Color green = new Color(0, 255, 0);
+
+    /**
+     * The color green.
+     */
+    public static final Color GREEN = green;
+
+    /**
+     * The color magenta.
+     */
+    public static final Color magenta = new Color(255, 0, 255);
+
+    /**
+     * The color magenta.
+     */
+    public static final Color MAGENTA = magenta;
+
+    /**
+     * The color cyan.
+     */
+    public static final Color cyan = new Color(0, 255, 255);
+
+    /**
+     * The color cyan.
+     */
+    public static final Color CYAN = cyan;
+
+    /**
+     * The color blue.
+     */
+    public static final Color blue = new Color(0, 0, 255);
+
+    /**
+     * The color blue.
+     */
+    public static final Color BLUE = blue;
+
+    /**
+     * integer RGB value.
+     */
+    int value;
+
+    /**
+     * Float sRGB value.
+     */
+    private float[] frgbvalue;
+
+    /**
+     * Color in an arbitrary color space with <code>float</code> components. If
+     * null, other value should be used.
+     */
+    private float fvalue[];
+
+    /**
+     * Float alpha value. If frgbvalue is null, this is not valid data.
+     */
+    private float falpha;
+
+    /**
+     * The color's color space if applicable.
+     */
+    private ColorSpace cs;
+
+    /*
+     * The value of the SCALE_FACTOR is based on 1.5 release behavior which can
+     * be revealed using the following code: Color c = new Color(100, 100, 100);
+     * Color bc = c.brighter(); System.out.println("Brighter factor: " +
+     * ((float)c.getRed())/((float)bc.getRed())); Color dc = c.darker();
+     * System.out.println("Darker factor: " +
+     * ((float)dc.getRed())/((float)c.getRed())); The result is the same for
+     * brighter and darker methods, so we need only one scale factor for both.
+     */
+    /**
+     * The Constant SCALE_FACTOR.
+     */
+    private static final double SCALE_FACTOR = 0.7;
+
+    /**
+     * The Constant MIN_SCALABLE.
+     */
+    private static final int MIN_SCALABLE = 3; // should increase when
+
+    // multiplied by SCALE_FACTOR
+
+    /**
+     * The current paint context.
+     */
+    transient private PaintContext currentPaintContext;
+
+    /**
+     * Creates a color in the specified ColorSpace, the specified color
+     * components and the specified alpha.
+     * 
+     * @param cspace
+     *            the ColorSpace to be used to define the components.
+     * @param components
+     *            the components.
+     * @param alpha
+     *            the alpha.
+     */
+    public Color(ColorSpace cspace, float[] components, float alpha) {
+        int nComps = cspace.getNumComponents();
+        float comp;
+        fvalue = new float[nComps];
+
+        for (int i = 0; i < nComps; i++) {
+            comp = components[i];
+            if (comp < 0.0f || comp > 1.0f) {
+                // awt.107=Color parameter outside of expected range: component
+                // {0}.
+                throw new IllegalArgumentException(Messages.getString("awt.107", i)); //$NON-NLS-1$
+            }
+            fvalue[i] = components[i];
+        }
+
+        if (alpha < 0.0f || alpha > 1.0f) {
+            // awt.108=Alpha value outside of expected range.
+            throw new IllegalArgumentException(Messages.getString("awt.108")); //$NON-NLS-1$
+        }
+        falpha = alpha;
+
+        cs = cspace;
+
+        frgbvalue = cs.toRGB(fvalue);
+
+        value = ((int)(frgbvalue[2] * 255 + 0.5)) | (((int)(frgbvalue[1] * 255 + 0.5)) << 8)
+                | (((int)(frgbvalue[0] * 255 + 0.5)) << 16) | (((int)(falpha * 255 + 0.5)) << 24);
+    }
+
+    /**
+     * Instantiates a new sRGB color with the specified combined RGBA value
+     * consisting of the alpha component in bits 24-31, the red component in
+     * bits 16-23, the green component in bits 8-15, and the blue component in
+     * bits 0-7. If the hasalpha argument is false, the alpha has default value
+     * - 255.
+     * 
+     * @param rgba
+     *            the RGBA components.
+     * @param hasAlpha
+     *            the alpha parameter is true if alpha bits are valid, false
+     *            otherwise.
+     */
+    public Color(int rgba, boolean hasAlpha) {
+        if (!hasAlpha) {
+            value = rgba | 0xFF000000;
+        } else {
+            value = rgba;
+        }
+    }
+
+    /**
+     * Instantiates a new color with the specified red, green, blue and alpha
+     * components.
+     * 
+     * @param r
+     *            the red component.
+     * @param g
+     *            the green component.
+     * @param b
+     *            the blue component.
+     * @param a
+     *            the alpha component.
+     */
+    public Color(int r, int g, int b, int a) {
+        if ((r & 0xFF) != r || (g & 0xFF) != g || (b & 0xFF) != b || (a & 0xFF) != a) {
+            // awt.109=Color parameter outside of expected range.
+            throw new IllegalArgumentException(Messages.getString("awt.109")); //$NON-NLS-1$
+        }
+        value = b | (g << 8) | (r << 16) | (a << 24);
+    }
+
+    /**
+     * Instantiates a new opaque sRGB color with the specified red, green, and
+     * blue values. The Alpha component is set to the default - 1.0.
+     * 
+     * @param r
+     *            the red component.
+     * @param g
+     *            the green component.
+     * @param b
+     *            the blue component.
+     */
+    public Color(int r, int g, int b) {
+        if ((r & 0xFF) != r || (g & 0xFF) != g || (b & 0xFF) != b) {
+            // awt.109=Color parameter outside of expected range.
+            throw new IllegalArgumentException(Messages.getString("awt.109")); //$NON-NLS-1$
+        }
+        // 0xFF for alpha channel
+        value = b | (g << 8) | (r << 16) | 0xFF000000;
+    }
+
+    /**
+     * Instantiates a new sRGB color with the specified RGB value consisting of
+     * the red component in bits 16-23, the green component in bits 8-15, and
+     * the blue component in bits 0-7. Alpha has default value - 255.
+     * 
+     * @param rgb
+     *            the RGB components.
+     */
+    public Color(int rgb) {
+        value = rgb | 0xFF000000;
+    }
+
+    /**
+     * Instantiates a new color with the specified red, green, blue and alpha
+     * components.
+     * 
+     * @param r
+     *            the red component.
+     * @param g
+     *            the green component.
+     * @param b
+     *            the blue component.
+     * @param a
+     *            the alpha component.
+     */
+    public Color(float r, float g, float b, float a) {
+        this((int)(r * 255 + 0.5), (int)(g * 255 + 0.5), (int)(b * 255 + 0.5), (int)(a * 255 + 0.5));
+        falpha = a;
+        fvalue = new float[3];
+        fvalue[0] = r;
+        fvalue[1] = g;
+        fvalue[2] = b;
+        frgbvalue = fvalue;
+    }
+
+    /**
+     * Instantiates a new color with the specified red, green, and blue
+     * components and default alpha value - 1.0.
+     * 
+     * @param r
+     *            the red component.
+     * @param g
+     *            the green component.
+     * @param b
+     *            the blue component.
+     */
+    public Color(float r, float g, float b) {
+        this(r, g, b, 1.0f);
+    }
+
+    public PaintContext createContext(ColorModel cm, Rectangle r, Rectangle2D r2d,
+            AffineTransform xform, RenderingHints rhs) {
+        if (currentPaintContext != null) {
+            return currentPaintContext;
+        }
+        currentPaintContext = new Color.ColorPaintContext(value);
+        return currentPaintContext;
+    }
+
+    /**
+     * Returns a string representation of the Color object.
+     * 
+     * @return the string representation of the Color object.
+     */
+    @Override
+    public String toString() {
+        /*
+         * The format of the string is based on 1.5 release behavior which can
+         * be revealed using the following code: Color c = new Color(1, 2, 3);
+         * System.out.println(c);
+         */
+
+        return getClass().getName() + "[r=" + getRed() + //$NON-NLS-1$
+                ",g=" + getGreen() + //$NON-NLS-1$
+                ",b=" + getBlue() + //$NON-NLS-1$
+                "]"; //$NON-NLS-1$
+    }
+
+    /**
+     * Compares the specified Object to the Color.
+     * 
+     * @param obj
+     *            the Object to be compared.
+     * @return true, if the specified Object is a Color whose value is equal to
+     *         this Color, false otherwise.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof Color) {
+            return ((Color)obj).value == this.value;
+        }
+        return false;
+    }
+
+    /**
+     * Returns a float array containing the color and alpha components of the
+     * Color in the specified ColorSpace.
+     * 
+     * @param colorSpace
+     *            the specified ColorSpace.
+     * @param components
+     *            the results of this method will be written to this float
+     *            array. If null, a float array will be created.
+     * @return the color and alpha components in a float array.
+     */
+    public float[] getComponents(ColorSpace colorSpace, float[] components) {
+        int nComps = colorSpace.getNumComponents();
+        if (components == null) {
+            components = new float[nComps + 1];
+        }
+
+        getColorComponents(colorSpace, components);
+
+        if (frgbvalue != null) {
+            components[nComps] = falpha;
+        } else {
+            components[nComps] = getAlpha() / 255f;
+        }
+
+        return components;
+    }
+
+    /**
+     * Returns a float array containing the color components of the Color in the
+     * specified ColorSpace.
+     * 
+     * @param colorSpace
+     *            the specified ColorSpace.
+     * @param components
+     *            the results of this method will be written to this float
+     *            array. If null, a float array will be created.
+     * @return the color components in a float array.
+     */
+    public float[] getColorComponents(ColorSpace colorSpace, float[] components) {
+        float[] cieXYZComponents = getColorSpace().toCIEXYZ(getColorComponents(null));
+        float[] csComponents = colorSpace.fromCIEXYZ(cieXYZComponents);
+
+        if (components == null) {
+            return csComponents;
+        }
+
+        for (int i = 0; i < csComponents.length; i++) {
+            components[i] = csComponents[i];
+        }
+
+        return components;
+    }
+
+    /**
+     * Gets the ColorSpace of this Color.
+     * 
+     * @return the ColorSpace object.
+     */
+    public ColorSpace getColorSpace() {
+        if (cs == null) {
+            cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+        }
+
+        return cs;
+    }
+
+    /**
+     * Creates a new Color which is a darker than this Color according to a
+     * fixed scale factor.
+     * 
+     * @return the darker Color.
+     */
+    public Color darker() {
+        return new Color((int)(getRed() * SCALE_FACTOR), (int)(getGreen() * SCALE_FACTOR),
+                (int)(getBlue() * SCALE_FACTOR));
+    }
+
+    /**
+     * Creates a new Color which is a brighter than this Color.
+     * 
+     * @return the brighter Color.
+     */
+    public Color brighter() {
+
+        int r = getRed();
+        int b = getBlue();
+        int g = getGreen();
+
+        if (r == 0 && b == 0 && g == 0) {
+            return new Color(MIN_SCALABLE, MIN_SCALABLE, MIN_SCALABLE);
+        }
+
+        if (r < MIN_SCALABLE && r != 0) {
+            r = MIN_SCALABLE;
+        } else {
+            r = (int)(r / SCALE_FACTOR);
+            r = (r > 255) ? 255 : r;
+        }
+
+        if (b < MIN_SCALABLE && b != 0) {
+            b = MIN_SCALABLE;
+        } else {
+            b = (int)(b / SCALE_FACTOR);
+            b = (b > 255) ? 255 : b;
+        }
+
+        if (g < MIN_SCALABLE && g != 0) {
+            g = MIN_SCALABLE;
+        } else {
+            g = (int)(g / SCALE_FACTOR);
+            g = (g > 255) ? 255 : g;
+        }
+
+        return new Color(r, g, b);
+    }
+
+    /**
+     * Returns a float array containing the color and alpha components of the
+     * Color in the default sRGB color space.
+     * 
+     * @param components
+     *            the results of this method will be written to this float
+     *            array. A new float array will be created if this argument is
+     *            null.
+     * @return the RGB color and alpha components in a float array.
+     */
+    public float[] getRGBComponents(float[] components) {
+        if (components == null) {
+            components = new float[4];
+        }
+
+        if (frgbvalue != null) {
+            components[3] = falpha;
+        } else {
+            components[3] = getAlpha() / 255f;
+        }
+
+        getRGBColorComponents(components);
+
+        return components;
+    }
+
+    /**
+     * Returns a float array containing the color components of the Color in the
+     * default sRGB color space.
+     * 
+     * @param components
+     *            the results of this method will be written to this float
+     *            array. A new float array will be created if this argument is
+     *            null.
+     * @return the RGB color components in a float array.
+     */
+    public float[] getRGBColorComponents(float[] components) {
+        if (components == null) {
+            components = new float[3];
+        }
+
+        if (frgbvalue != null) {
+            components[2] = frgbvalue[2];
+            components[1] = frgbvalue[1];
+            components[0] = frgbvalue[0];
+        } else {
+            components[2] = getBlue() / 255f;
+            components[1] = getGreen() / 255f;
+            components[0] = getRed() / 255f;
+        }
+
+        return components;
+    }
+
+    /**
+     * Returns a float array which contains the color and alpha components of
+     * the Color in the ColorSpace of the Color.
+     * 
+     * @param components
+     *            the results of this method will be written to this float
+     *            array. A new float array will be created if this argument is
+     *            null.
+     * @return the color and alpha components in a float array.
+     */
+    public float[] getComponents(float[] components) {
+        if (fvalue == null) {
+            return getRGBComponents(components);
+        }
+
+        int nColorComps = fvalue.length;
+
+        if (components == null) {
+            components = new float[nColorComps + 1];
+        }
+
+        getColorComponents(components);
+
+        components[nColorComps] = falpha;
+
+        return components;
+    }
+
+    /**
+     * Returns a float array which contains the color components of the Color in
+     * the ColorSpace of the Color.
+     * 
+     * @param components
+     *            the results of this method will be written to this float
+     *            array. A new float array will be created if this argument is
+     *            null.
+     * @return the color components in a float array.
+     */
+    public float[] getColorComponents(float[] components) {
+        if (fvalue == null) {
+            return getRGBColorComponents(components);
+        }
+
+        if (components == null) {
+            components = new float[fvalue.length];
+        }
+
+        for (int i = 0; i < fvalue.length; i++) {
+            components[i] = fvalue[i];
+        }
+
+        return components;
+    }
+
+    /**
+     * Returns a hash code of this Color object.
+     * 
+     * @return a hash code of this Color object.
+     */
+    @Override
+    public int hashCode() {
+        return value;
+    }
+
+    public int getTransparency() {
+        switch (getAlpha()) {
+            case 0xff:
+                return Transparency.OPAQUE;
+            case 0:
+                return Transparency.BITMASK;
+            default:
+                return Transparency.TRANSLUCENT;
+        }
+    }
+
+    /**
+     * Gets the red component of the Color in the range 0-255.
+     * 
+     * @return the red component of the Color.
+     */
+    public int getRed() {
+        return (value >> 16) & 0xFF;
+    }
+
+    /**
+     * Gets the RGB value that represents the color in the default sRGB
+     * ColorModel.
+     * 
+     * @return the RGB color value in the default sRGB ColorModel.
+     */
+    public int getRGB() {
+        return value;
+    }
+
+    /**
+     * Gets the green component of the Color in the range 0-255.
+     * 
+     * @return the green component of the Color.
+     */
+    public int getGreen() {
+        return (value >> 8) & 0xFF;
+    }
+
+    /**
+     * Gets the blue component of the Color in the range 0-255.
+     * 
+     * @return the blue component of the Color.
+     */
+    public int getBlue() {
+        return value & 0xFF;
+    }
+
+    /**
+     * Gets the alpha component of the Color in the range 0-255.
+     * 
+     * @return the alpha component of the Color.
+     */
+    public int getAlpha() {
+        return (value >> 24) & 0xFF;
+    }
+
+    /**
+     * Gets the Color from the specified string, or returns the Color specified
+     * by the second parameter.
+     * 
+     * @param nm
+     *            the specified string.
+     * @param def
+     *            the default Color.
+     * @return the color from the specified string, or the Color specified by
+     *         the second parameter.
+     */
+    public static Color getColor(String nm, Color def) {
+        Integer integer = Integer.getInteger(nm);
+
+        if (integer == null) {
+            return def;
+        }
+
+        return new Color(integer.intValue());
+    }
+
+    /**
+     * Gets the Color from the specified string, or returns the Color converted
+     * from the second parameter.
+     * 
+     * @param nm
+     *            the specified string.
+     * @param def
+     *            the default Color.
+     * @return the color from the specified string, or the Color converted from
+     *         the second parameter.
+     */
+    public static Color getColor(String nm, int def) {
+        Integer integer = Integer.getInteger(nm);
+
+        if (integer == null) {
+            return new Color(def);
+        }
+
+        return new Color(integer.intValue());
+    }
+
+    /**
+     * Gets the Color from the specified String.
+     * 
+     * @param nm
+     *            the specified string.
+     * @return the Color object, or null.
+     */
+    public static Color getColor(String nm) {
+        Integer integer = Integer.getInteger(nm);
+
+        if (integer == null) {
+            return null;
+        }
+
+        return new Color(integer.intValue());
+    }
+
+    /**
+     * Decodes a String to an integer and returns the specified opaque Color.
+     * 
+     * @param nm
+     *            the String which represents an opaque color as a 24-bit
+     *            integer.
+     * @return the Color object from the given String.
+     * @throws NumberFormatException
+     *             if the specified string can not be converted to an integer.
+     */
+    public static Color decode(String nm) throws NumberFormatException {
+        Integer integer = Integer.decode(nm);
+        return new Color(integer.intValue());
+    }
+
+    /**
+     * Gets a Color object using the specified values of the HSB color model.
+     * 
+     * @param h
+     *            the hue component of the Color.
+     * @param s
+     *            the saturation of the Color.
+     * @param b
+     *            the brightness of the Color.
+     * @return a color object with the specified hue, saturation and brightness
+     *         values.
+     */
+    public static Color getHSBColor(float h, float s, float b) {
+        return new Color(HSBtoRGB(h, s, b));
+    }
+
+    /**
+     * Converts the Color specified by the RGB model to an equivalent color in
+     * the HSB model.
+     * 
+     * @param r
+     *            the red component.
+     * @param g
+     *            the green component.
+     * @param b
+     *            the blue component.
+     * @param hsbvals
+     *            the array of result hue, saturation, brightness values or
+     *            null.
+     * @return the float array of hue, saturation, brightness values.
+     */
+    public static float[] RGBtoHSB(int r, int g, int b, float[] hsbvals) {
+        if (hsbvals == null) {
+            hsbvals = new float[3];
+        }
+
+        int V = Math.max(b, Math.max(r, g));
+        int temp = Math.min(b, Math.min(r, g));
+
+        float H, S, B;
+
+        B = V / 255.f;
+
+        if (V == temp) {
+            H = S = 0;
+        } else {
+            S = (V - temp) / ((float)V);
+
+            float Cr = (V - r) / (float)(V - temp);
+            float Cg = (V - g) / (float)(V - temp);
+            float Cb = (V - b) / (float)(V - temp);
+
+            if (r == V) {
+                H = Cb - Cg;
+            } else if (g == V) {
+                H = 2 + Cr - Cb;
+            } else {
+                H = 4 + Cg - Cr;
+            }
+
+            H /= 6.f;
+            if (H < 0) {
+                H++;
+            }
+        }
+
+        hsbvals[0] = H;
+        hsbvals[1] = S;
+        hsbvals[2] = B;
+
+        return hsbvals;
+    }
+
+    /**
+     * Converts the Color specified by the HSB model to an equivalent color in
+     * the default RGB model.
+     * 
+     * @param hue
+     *            the hue component of the Color.
+     * @param saturation
+     *            the saturation of the Color.
+     * @param brightness
+     *            the brightness of the Color.
+     * @return the RGB value of the color with the specified hue, saturation and
+     *         brightness.
+     */
+    public static int HSBtoRGB(float hue, float saturation, float brightness) {
+        float fr, fg, fb;
+
+        if (saturation == 0) {
+            fr = fg = fb = brightness;
+        } else {
+            float H = (hue - (float)Math.floor(hue)) * 6;
+            int I = (int)Math.floor(H);
+            float F = H - I;
+            float M = brightness * (1 - saturation);
+            float N = brightness * (1 - saturation * F);
+            float K = brightness * (1 - saturation * (1 - F));
+
+            switch (I) {
+                case 0:
+                    fr = brightness;
+                    fg = K;
+                    fb = M;
+                    break;
+                case 1:
+                    fr = N;
+                    fg = brightness;
+                    fb = M;
+                    break;
+                case 2:
+                    fr = M;
+                    fg = brightness;
+                    fb = K;
+                    break;
+                case 3:
+                    fr = M;
+                    fg = N;
+                    fb = brightness;
+                    break;
+                case 4:
+                    fr = K;
+                    fg = M;
+                    fb = brightness;
+                    break;
+                case 5:
+                    fr = brightness;
+                    fg = M;
+                    fb = N;
+                    break;
+                default:
+                    fr = fb = fg = 0; // impossible, to supress compiler error
+            }
+        }
+
+        int r = (int)(fr * 255. + 0.5);
+        int g = (int)(fg * 255. + 0.5);
+        int b = (int)(fb * 255. + 0.5);
+
+        return (r << 16) | (g << 8) | b | 0xFF000000;
+    }
+
+    /**
+     * The Class ColorPaintContext.
+     */
+    class ColorPaintContext implements PaintContext {
+
+        /**
+         * The RGB value.
+         */
+        int rgbValue;
+
+        /**
+         * The saved raster.
+         */
+        WritableRaster savedRaster = null;
+
+        /**
+         * Instantiates a new color paint context.
+         * 
+         * @param rgb
+         *            the RGB value.
+         */
+        protected ColorPaintContext(int rgb) {
+            rgbValue = rgb;
+        }
+
+        public void dispose() {
+            savedRaster = null;
+        }
+
+        public ColorModel getColorModel() {
+            return ColorModel.getRGBdefault();
+        }
+
+        public Raster getRaster(int x, int y, int w, int h) {
+            if (savedRaster == null || w != savedRaster.getWidth() || h != savedRaster.getHeight()) {
+                savedRaster = getColorModel().createCompatibleWritableRaster(w, h);
+
+                // Suppose we have here simple INT/RGB color/sample model
+                DataBufferInt intBuffer = (DataBufferInt)savedRaster.getDataBuffer();
+                int rgbValues[] = intBuffer.getData();
+                int rgbFillValue = rgbValue;
+                Arrays.fill(rgbValues, rgbFillValue);
+            }
+
+            return savedRaster;
+        }
+    }
+}
diff --git a/awt/java/awt/Component.java b/awt/java/awt/Component.java
new file mode 100644
index 0000000..c52a9f4
--- /dev/null
+++ b/awt/java/awt/Component.java
@@ -0,0 +1,6020 @@
+/*
+ *  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.
+ */
+
+package java.awt;
+
+//import java.awt.dnd.DropTarget;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.HierarchyBoundsListener;
+import java.awt.event.HierarchyEvent;
+import java.awt.event.HierarchyListener;
+import java.awt.event.InputMethodEvent;
+import java.awt.event.InputMethodListener;
+import java.awt.event.InvocationEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.awt.event.PaintEvent;
+import java.awt.event.WindowEvent;
+import java.awt.im.InputContext;
+import java.awt.im.InputMethodRequests;
+import java.awt.image.BufferStrategy;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.VolatileImage;
+import java.awt.image.WritableRaster;
+import java.awt.peer.ComponentPeer;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+//???AWT
+//import javax.accessibility.Accessible;
+//import javax.accessibility.AccessibleComponent;
+//import javax.accessibility.AccessibleContext;
+//import javax.accessibility.AccessibleRole;
+//import javax.accessibility.AccessibleState;
+//import javax.accessibility.AccessibleStateSet;
+
+import org.apache.harmony.awt.ClipRegion; //import org.apache.harmony.awt.FieldsAccessor;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.state.State; //import org.apache.harmony.awt.text.TextFieldKit;
+//import org.apache.harmony.awt.text.TextKit;
+import org.apache.harmony.awt.wtk.NativeWindow;
+import org.apache.harmony.luni.util.NotImplementedException;
+
+/**
+ * The abstract Component class specifies an object with a graphical
+ * representation that can be displayed on the screen and that can interact with
+ * the user (for example: scrollbars, buttons, checkboxes).
+ * 
+ * @since Android 1.0
+ */
+public abstract class Component implements ImageObserver, MenuContainer, Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -7644114512714619750L;
+
+    /**
+     * The Constant TOP_ALIGNMENT indicates the top alignment of the component.
+     */
+    public static final float TOP_ALIGNMENT = 0.0f;
+
+    /**
+     * The Constant CENTER_ALIGNMENT indicates the center alignment of the
+     * component.
+     */
+    public static final float CENTER_ALIGNMENT = 0.5f;
+
+    /**
+     * The Constant BOTTOM_ALIGNMENT indicates the bottom alignment of the
+     * component.
+     */
+    public static final float BOTTOM_ALIGNMENT = 1.0f;
+
+    /**
+     * The Constant LEFT_ALIGNMENT indicates the left alignment of the
+     * component.
+     */
+    public static final float LEFT_ALIGNMENT = 0.0f;
+
+    /**
+     * The Constant RIGHT_ALIGNMENT indicates the right alignment of the
+     * component.
+     */
+    public static final float RIGHT_ALIGNMENT = 1.0f;
+
+    /**
+     * The Constant childClassesFlags.
+     */
+    private static final Hashtable<Class<?>, Boolean> childClassesFlags = new Hashtable<Class<?>, Boolean>();
+
+    /**
+     * The Constant peer.
+     */
+    private static final ComponentPeer peer = new ComponentPeer() {
+    };
+
+    /**
+     * The Constant incrementalImageUpdate.
+     */
+    private static final boolean incrementalImageUpdate;
+
+    /**
+     * The toolkit.
+     */
+    final transient Toolkit toolkit = Toolkit.getDefaultToolkit();
+
+    // ???AWT
+    /*
+     * protected abstract class AccessibleAWTComponent extends AccessibleContext
+     * implements Serializable, AccessibleComponent { private static final long
+     * serialVersionUID = 642321655757800191L; protected class
+     * AccessibleAWTComponentHandler implements ComponentListener { protected
+     * AccessibleAWTComponentHandler() { } public void
+     * componentHidden(ComponentEvent e) { if (behaviour.isLightweight()) {
+     * return; } firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
+     * AccessibleState.VISIBLE, null); } public void
+     * componentMoved(ComponentEvent e) { } public void
+     * componentResized(ComponentEvent e) { } public void
+     * componentShown(ComponentEvent e) { if (behaviour.isLightweight()) {
+     * return; } firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
+     * null, AccessibleState.VISIBLE); } } protected class
+     * AccessibleAWTFocusHandler implements FocusListener { public void
+     * focusGained(FocusEvent e) { if (behaviour.isLightweight()) { return; }
+     * firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null,
+     * AccessibleState.FOCUSED); } public void focusLost(FocusEvent e) { if
+     * (behaviour.isLightweight()) { return; }
+     * firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
+     * AccessibleState.FOCUSED, null); } } protected ComponentListener
+     * accessibleAWTComponentHandler; protected FocusListener
+     * accessibleAWTFocusHandler;
+     */
+    /*
+     * Number of registered property change listeners.
+     */
+    /*
+     * int listenersCount; public void addFocusListener(FocusListener l) {
+     * Component.this.addFocusListener(l); }
+     * @Override public void addPropertyChangeListener(PropertyChangeListener
+     * listener) { toolkit.lockAWT(); try {
+     * super.addPropertyChangeListener(listener); listenersCount++; if
+     * (accessibleAWTComponentHandler == null) { accessibleAWTComponentHandler =
+     * new AccessibleAWTComponentHandler();
+     * Component.this.addComponentListener(accessibleAWTComponentHandler); } if
+     * (accessibleAWTFocusHandler == null) { accessibleAWTFocusHandler = new
+     * AccessibleAWTFocusHandler();
+     * Component.this.addFocusListener(accessibleAWTFocusHandler); } } finally {
+     * toolkit.unlockAWT(); } } public boolean contains(Point p) {
+     * toolkit.lockAWT(); try { return Component.this.contains(p); } finally {
+     * toolkit.unlockAWT(); } } public Accessible getAccessibleAt(Point arg0) {
+     * toolkit.lockAWT(); try { return null; } finally { toolkit.unlockAWT(); }
+     * } public Color getBackground() { toolkit.lockAWT(); try { return
+     * Component.this.getBackground(); } finally { toolkit.unlockAWT(); } }
+     * public Rectangle getBounds() { toolkit.lockAWT(); try { return
+     * Component.this.getBounds(); } finally { toolkit.unlockAWT(); } } public
+     * Cursor getCursor() { toolkit.lockAWT(); try { return
+     * Component.this.getCursor(); } finally { toolkit.unlockAWT(); } } public
+     * Font getFont() { toolkit.lockAWT(); try { return
+     * Component.this.getFont(); } finally { toolkit.unlockAWT(); } } public
+     * FontMetrics getFontMetrics(Font f) { toolkit.lockAWT(); try { return
+     * Component.this.getFontMetrics(f); } finally { toolkit.unlockAWT(); } }
+     * public Color getForeground() { toolkit.lockAWT(); try { return
+     * Component.this.getForeground(); } finally { toolkit.unlockAWT(); } }
+     * public Point getLocation() { toolkit.lockAWT(); try { return
+     * Component.this.getLocation(); } finally { toolkit.unlockAWT(); } } public
+     * Point getLocationOnScreen() { toolkit.lockAWT(); try { return
+     * Component.this.getLocationOnScreen(); } finally { toolkit.unlockAWT(); }
+     * } public Dimension getSize() { toolkit.lockAWT(); try { return
+     * Component.this.getSize(); } finally { toolkit.unlockAWT(); } } public
+     * boolean isEnabled() { toolkit.lockAWT(); try { return
+     * Component.this.isEnabled(); } finally { toolkit.unlockAWT(); } } public
+     * boolean isFocusTraversable() { toolkit.lockAWT(); try { return
+     * Component.this.isFocusTraversable(); } finally { toolkit.unlockAWT(); } }
+     * public boolean isShowing() { toolkit.lockAWT(); try { return
+     * Component.this.isShowing(); } finally { toolkit.unlockAWT(); } } public
+     * boolean isVisible() { toolkit.lockAWT(); try { return
+     * Component.this.isVisible(); } finally { toolkit.unlockAWT(); } } public
+     * void removeFocusListener(FocusListener l) {
+     * Component.this.removeFocusListener(l); }
+     * @Override public void removePropertyChangeListener(PropertyChangeListener
+     * listener) { toolkit.lockAWT(); try {
+     * super.removePropertyChangeListener(listener); listenersCount--; if
+     * (listenersCount > 0) { return; } // if there are no more listeners,
+     * remove handlers:
+     * Component.this.removeFocusListener(accessibleAWTFocusHandler);
+     * Component.this.removeComponentListener(accessibleAWTComponentHandler);
+     * accessibleAWTComponentHandler = null; accessibleAWTFocusHandler = null; }
+     * finally { toolkit.unlockAWT(); } } public void requestFocus() {
+     * toolkit.lockAWT(); try { Component.this.requestFocus(); } finally {
+     * toolkit.unlockAWT(); } } public void setBackground(Color color) {
+     * toolkit.lockAWT(); try { Component.this.setBackground(color); } finally {
+     * toolkit.unlockAWT(); } } public void setBounds(Rectangle r) {
+     * toolkit.lockAWT(); try { Component.this.setBounds(r); } finally {
+     * toolkit.unlockAWT(); } } public void setCursor(Cursor cursor) {
+     * toolkit.lockAWT(); try { Component.this.setCursor(cursor); } finally {
+     * toolkit.unlockAWT(); } } public void setEnabled(boolean enabled) {
+     * toolkit.lockAWT(); try { Component.this.setEnabled(enabled); } finally {
+     * toolkit.unlockAWT(); } } public void setFont(Font f) { toolkit.lockAWT();
+     * try { Component.this.setFont(f); } finally { toolkit.unlockAWT(); } }
+     * public void setForeground(Color color) { toolkit.lockAWT(); try {
+     * Component.this.setForeground(color); } finally { toolkit.unlockAWT(); } }
+     * public void setLocation(Point p) { toolkit.lockAWT(); try {
+     * Component.this.setLocation(p); } finally { toolkit.unlockAWT(); } }
+     * public void setSize(Dimension size) { toolkit.lockAWT(); try {
+     * Component.this.setSize(size); } finally { toolkit.unlockAWT(); } } public
+     * void setVisible(boolean visible) { toolkit.lockAWT(); try {
+     * Component.this.setVisible(visible); } finally { toolkit.unlockAWT(); } }
+     * @Override public Accessible getAccessibleParent() { toolkit.lockAWT();
+     * try { Accessible aParent = super.getAccessibleParent(); if (aParent !=
+     * null) { return aParent; } Container parent = getParent(); return (parent
+     * instanceof Accessible ? (Accessible) parent : null); } finally {
+     * toolkit.unlockAWT(); } }
+     * @Override public Accessible getAccessibleChild(int i) {
+     * toolkit.lockAWT(); try { return null; } finally { toolkit.unlockAWT(); }
+     * }
+     * @Override public int getAccessibleChildrenCount() { toolkit.lockAWT();
+     * try { return 0; } finally { toolkit.unlockAWT(); } }
+     * @Override public AccessibleComponent getAccessibleComponent() { return
+     * this; }
+     * @Override public String getAccessibleDescription() { return
+     * super.getAccessibleDescription(); // why override? }
+     * @Override public int getAccessibleIndexInParent() { toolkit.lockAWT();
+     * try { if (getAccessibleParent() == null) { return -1; } int count = 0;
+     * Container parent = getParent(); for (int i = 0; i <
+     * parent.getComponentCount(); i++) { Component aComp =
+     * parent.getComponent(i); if (aComp instanceof Accessible) { if (aComp ==
+     * Component.this) { return count; } ++count; } } return -1; } finally {
+     * toolkit.unlockAWT(); } }
+     * @Override public AccessibleRole getAccessibleRole() { toolkit.lockAWT();
+     * try { return AccessibleRole.AWT_COMPONENT; } finally {
+     * toolkit.unlockAWT(); } }
+     * @Override public AccessibleStateSet getAccessibleStateSet() {
+     * toolkit.lockAWT(); try { AccessibleStateSet set = new
+     * AccessibleStateSet(); if (isEnabled()) {
+     * set.add(AccessibleState.ENABLED); } if (isFocusable()) {
+     * set.add(AccessibleState.FOCUSABLE); } if (hasFocus()) {
+     * set.add(AccessibleState.FOCUSED); } if (isOpaque()) {
+     * set.add(AccessibleState.OPAQUE); } if (isShowing()) {
+     * set.add(AccessibleState.SHOWING); } if (isVisible()) {
+     * set.add(AccessibleState.VISIBLE); } return set; } finally {
+     * toolkit.unlockAWT(); } }
+     * @Override public Locale getLocale() throws IllegalComponentStateException
+     * { toolkit.lockAWT(); try { return Component.this.getLocale(); } finally {
+     * toolkit.unlockAWT(); } } }
+     */
+    /**
+     * The BltBufferStrategy class provides opportunity of blitting offscreen
+     * surfaces to a component. For more information on blitting, see <a
+     * href="http://en.wikipedia.org/wiki/Bit_blit">Bit blit</a>.
+     * 
+     * @since Android 1.0
+     */
+    protected class BltBufferStrategy extends BufferStrategy {
+
+        /**
+         * The back buffers.
+         */
+        protected VolatileImage[] backBuffers;
+
+        /**
+         * The caps.
+         */
+        protected BufferCapabilities caps;
+
+        /**
+         * The width.
+         */
+        protected int width;
+
+        /**
+         * The height.
+         */
+        protected int height;
+
+        /**
+         * The validated contents.
+         */
+        protected boolean validatedContents;
+
+        /**
+         * Instantiates a new BltBufferStrategy buffer strategy.
+         * 
+         * @param numBuffers
+         *            the number of buffers.
+         * @param caps
+         *            the BufferCapabilities.
+         * @throws NotImplementedException
+         *             the not implemented exception.
+         */
+        protected BltBufferStrategy(int numBuffers, BufferCapabilities caps)
+                throws org.apache.harmony.luni.util.NotImplementedException {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+        }
+
+        /**
+         * Returns true if the drawing buffer has been lost since the last call
+         * to getDrawGraphics.
+         * 
+         * @return true if the drawing buffer has been lost since the last call
+         *         to getDrawGraphics, false otherwise.
+         * @see java.awt.image.BufferStrategy#contentsLost()
+         */
+        @Override
+        public boolean contentsLost() {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+            return false;
+        }
+
+        /**
+         * Returns true if the drawing buffer has been restored from a lost
+         * state and reinitialized to the default background color.
+         * 
+         * @return true if the drawing buffer has been restored from a lost
+         *         state and reinitialized to the default background color,
+         *         false otherwise.
+         * @see java.awt.image.BufferStrategy#contentsRestored()
+         */
+        @Override
+        public boolean contentsRestored() {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+            return false;
+        }
+
+        /**
+         * Creates the back buffers.
+         * 
+         * @param numBuffers
+         *            the number of buffers.
+         */
+        protected void createBackBuffers(int numBuffers) {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+        }
+
+        /**
+         * Returns the BufferCapabilities of the buffer strategy.
+         * 
+         * @return the BufferCapabilities.
+         * @see java.awt.image.BufferStrategy#getCapabilities()
+         */
+        @Override
+        public BufferCapabilities getCapabilities() {
+            return (BufferCapabilities)caps.clone();
+        }
+
+        /**
+         * Gets Graphics of current buffer strategy.
+         * 
+         * @return the Graphics of current buffer strategy.
+         * @see java.awt.image.BufferStrategy#getDrawGraphics()
+         */
+        @Override
+        public Graphics getDrawGraphics() {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+            return null;
+        }
+
+        /**
+         * Revalidates the lost drawing buffer.
+         */
+        protected void revalidate() {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+        }
+
+        /**
+         * Shows the next available buffer.
+         * 
+         * @see java.awt.image.BufferStrategy#show()
+         */
+        @Override
+        public void show() {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * The FlipBufferStrategy class is for flipping buffers on a component.
+     * 
+     * @since Android 1.0
+     */
+    protected class FlipBufferStrategy extends BufferStrategy {
+
+        /**
+         * The Buffer Capabilities.
+         */
+        protected BufferCapabilities caps;
+
+        /**
+         * The drawing buffer.
+         */
+        protected Image drawBuffer;
+
+        /**
+         * The drawing VolatileImage buffer.
+         */
+        protected VolatileImage drawVBuffer;
+
+        /**
+         * The number of buffers.
+         */
+        protected int numBuffers;
+
+        /**
+         * The validated contents indicates if the drawing buffer is restored
+         * from lost state.
+         */
+        protected boolean validatedContents;
+
+        /**
+         * Instantiates a new flip buffer strategy.
+         * 
+         * @param numBuffers
+         *            the number of buffers.
+         * @param caps
+         *            the BufferCapabilities.
+         * @throws AWTException
+         *             if the capabilities supplied could not be supported or
+         *             met.
+         */
+        protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps) throws AWTException {
+            // ???AWT
+            /*
+             * if (!(Component.this instanceof Window) && !(Component.this
+             * instanceof Canvas)) { // awt.14B=Only Canvas or Window is allowed
+             * throw new ClassCastException(Messages.getString("awt.14B"));
+             * //$NON-NLS-1$ }
+             */
+            // TODO: throw new AWTException("Capabilities are not supported");
+            this.numBuffers = numBuffers;
+            this.caps = (BufferCapabilities)caps.clone();
+        }
+
+        /**
+         * Returns true if the drawing buffer has been lost since the last call
+         * to getDrawGraphics.
+         * 
+         * @return true if the drawing buffer has been lost since the last call
+         *         to getDrawGraphics, false otherwise.
+         * @see java.awt.image.BufferStrategy#contentsLost()
+         */
+        @Override
+        public boolean contentsLost() {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+            return false;
+        }
+
+        /**
+         * Returns true if the drawing buffer has been restored from a lost
+         * state and reinitialized to the default background color.
+         * 
+         * @return true if the drawing buffer has been restored from a lost
+         *         state and reinitialized to the default background color,
+         *         false otherwise.
+         * @see java.awt.image.BufferStrategy#contentsRestored()
+         */
+        @Override
+        public boolean contentsRestored() {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+            return false;
+        }
+
+        /**
+         * Creates flipping buffers with the specified buffer capabilities.
+         * 
+         * @param numBuffers
+         *            the number of buffers.
+         * @param caps
+         *            the BufferCapabilities.
+         * @throws AWTException
+         *             if the capabilities could not be supported or met.
+         */
+        protected void createBuffers(int numBuffers, BufferCapabilities caps) throws AWTException {
+            if (numBuffers < 2) {
+                // awt.14C=Number of buffers must be greater than one
+                throw new IllegalArgumentException(Messages.getString("awt.14C")); //$NON-NLS-1$
+            }
+            if (!caps.isPageFlipping()) {
+                // awt.14D=Buffer capabilities should support flipping
+                throw new IllegalArgumentException(Messages.getString("awt.14D")); //$NON-NLS-1$
+            }
+            if (!Component.this.behaviour.isDisplayable()) {
+                // awt.14E=Component should be displayable
+                throw new IllegalStateException(Messages.getString("awt.14E")); //$NON-NLS-1$
+            }
+            // TODO: throw new AWTException("Capabilities are not supported");
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+        }
+
+        /**
+         * Destroy buffers.
+         */
+        protected void destroyBuffers() {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+        }
+
+        /**
+         * Flips the contents of the back buffer to the front buffer.
+         * 
+         * @param flipAction
+         *            the flip action.
+         */
+        protected void flip(BufferCapabilities.FlipContents flipAction) {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+        }
+
+        /**
+         * Gets the back buffer as Image.
+         * 
+         * @return the back buffer as Image.
+         */
+        protected Image getBackBuffer() {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+            return null;
+        }
+
+        /**
+         * Returns the BufferCapabilities of the buffer strategy.
+         * 
+         * @return the BufferCapabilities.
+         * @see java.awt.image.BufferStrategy#getCapabilities()
+         */
+        @Override
+        public BufferCapabilities getCapabilities() {
+            return (BufferCapabilities)caps.clone();
+        }
+
+        /**
+         * Gets Graphics of current buffer strategy.
+         * 
+         * @return the Graphics of current buffer strategy.
+         * @see java.awt.image.BufferStrategy#getDrawGraphics()
+         */
+        @Override
+        public Graphics getDrawGraphics() {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+            return null;
+        }
+
+        /**
+         * Revalidates the lost drawing buffer.
+         */
+        protected void revalidate() {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+        }
+
+        /**
+         * Shows the next available buffer.
+         * 
+         * @see java.awt.image.BufferStrategy#show()
+         */
+        @Override
+        public void show() {
+            if (true) {
+                throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * The internal component's state utilized by the visual theme.
+     */
+    class ComponentState implements State {
+
+        /**
+         * The default minimum size.
+         */
+        private Dimension defaultMinimumSize = new Dimension();
+
+        /**
+         * Checks if the component is enabled.
+         * 
+         * @return true, if the component is enabled.
+         */
+        public boolean isEnabled() {
+            return enabled;
+        }
+
+        /**
+         * Checks if the component is visible.
+         * 
+         * @return true, if the component is visible.
+         */
+        public boolean isVisible() {
+            return visible;
+        }
+
+        /**
+         * Checks if is focused.
+         * 
+         * @return true, if is focused.
+         */
+        public boolean isFocused() {
+            // ???AWT: return isFocusOwner();
+            return false;
+        }
+
+        /**
+         * Gets the font.
+         * 
+         * @return the font.
+         */
+        public Font getFont() {
+            return Component.this.getFont();
+        }
+
+        /**
+         * Checks if the font has been set.
+         * 
+         * @return true, if the font has been set.
+         */
+        public boolean isFontSet() {
+            return font != null;
+        }
+
+        /**
+         * Gets the background color.
+         * 
+         * @return the background color.
+         */
+        public Color getBackground() {
+            Color c = Component.this.getBackground();
+            return (c != null) ? c : getDefaultBackground();
+        }
+
+        /**
+         * Checks if the background is set.
+         * 
+         * @return true, if the background is set.
+         */
+        public boolean isBackgroundSet() {
+            return backColor != null;
+        }
+
+        /**
+         * Gets the text color.
+         * 
+         * @return the text color.
+         */
+        public Color getTextColor() {
+            Color c = getForeground();
+            return (c != null) ? c : getDefaultForeground();
+        }
+
+        /**
+         * Checks if the text color is set.
+         * 
+         * @return true, if the text color is set.
+         */
+        public boolean isTextColorSet() {
+            return foreColor != null;
+        }
+
+        /**
+         * Gets the font metrics.
+         * 
+         * @return the font metrics.
+         */
+        @SuppressWarnings("deprecation")
+        public FontMetrics getFontMetrics() {
+            return toolkit.getFontMetrics(Component.this.getFont());
+        }
+
+        /**
+         * Gets the bounding rectangle.
+         * 
+         * @return the bounding rectangle.
+         */
+        public Rectangle getBounds() {
+            return new Rectangle(x, y, w, h);
+        }
+
+        /**
+         * Gets the size of the bounding rectangle.
+         * 
+         * @return the size of the bounding rectangle.
+         */
+        public Dimension getSize() {
+            return new Dimension(w, h);
+        }
+
+        /**
+         * Gets the window id.
+         * 
+         * @return the window id.
+         */
+        public long getWindowId() {
+            NativeWindow win = getNativeWindow();
+            return (win != null) ? win.getId() : 0;
+        }
+
+        /**
+         * Gets the default minimum size.
+         * 
+         * @return the default minimum size.
+         */
+        public Dimension getDefaultMinimumSize() {
+            if (defaultMinimumSize == null) {
+                calculate();
+            }
+            return defaultMinimumSize;
+        }
+
+        /**
+         * Sets the default minimum size.
+         * 
+         * @param size
+         *            the new default minimum size.
+         */
+        public void setDefaultMinimumSize(Dimension size) {
+            defaultMinimumSize = size;
+        }
+
+        /**
+         * Reset the default minimum size to null.
+         */
+        public void reset() {
+            defaultMinimumSize = null;
+        }
+
+        /**
+         * Calculate the default minimum size: to be overridden.
+         */
+        public void calculate() {
+            // to be overridden
+        }
+    }
+
+    // ???AWT: private transient AccessibleContext accessibleContext;
+
+    /**
+     * The behaviour.
+     */
+    final transient ComponentBehavior behaviour;
+
+    // ???AWT: Container parent;
+
+    /**
+     * The name.
+     */
+    private String name;
+
+    /**
+     * The auto name.
+     */
+    private boolean autoName = true;
+
+    /**
+     * The font.
+     */
+    private Font font;
+
+    /**
+     * The back color.
+     */
+    private Color backColor;
+
+    /**
+     * The fore color.
+     */
+    private Color foreColor;
+
+    /**
+     * The deprecated event handler.
+     */
+    boolean deprecatedEventHandler = true;
+
+    /**
+     * The enabled events.
+     */
+    private long enabledEvents;
+
+    /**
+     * The enabled AWT events.
+     */
+    private long enabledAWTEvents;
+
+    /**
+     * The component listeners.
+     */
+    private final AWTListenerList<ComponentListener> componentListeners = new AWTListenerList<ComponentListener>(
+            this);
+
+    /**
+     * The focus listeners.
+     */
+    private final AWTListenerList<FocusListener> focusListeners = new AWTListenerList<FocusListener>(
+            this);
+
+    /**
+     * The hierarchy listeners.
+     */
+    private final AWTListenerList<HierarchyListener> hierarchyListeners = new AWTListenerList<HierarchyListener>(
+            this);
+
+    /**
+     * The hierarchy bounds listeners.
+     */
+    private final AWTListenerList<HierarchyBoundsListener> hierarchyBoundsListeners = new AWTListenerList<HierarchyBoundsListener>(
+            this);
+
+    /**
+     * The key listeners.
+     */
+    private final AWTListenerList<KeyListener> keyListeners = new AWTListenerList<KeyListener>(this);
+
+    /**
+     * The mouse listeners.
+     */
+    private final AWTListenerList<MouseListener> mouseListeners = new AWTListenerList<MouseListener>(
+            this);
+
+    /**
+     * The mouse motion listeners.
+     */
+    private final AWTListenerList<MouseMotionListener> mouseMotionListeners = new AWTListenerList<MouseMotionListener>(
+            this);
+
+    /**
+     * The mouse wheel listeners.
+     */
+    private final AWTListenerList<MouseWheelListener> mouseWheelListeners = new AWTListenerList<MouseWheelListener>(
+            this);
+
+    /**
+     * The input method listeners.
+     */
+    private final AWTListenerList<InputMethodListener> inputMethodListeners = new AWTListenerList<InputMethodListener>(
+            this);
+
+    /**
+     * The x.
+     */
+    int x;
+
+    /**
+     * The y.
+     */
+    int y;
+
+    /**
+     * The w.
+     */
+    int w;
+
+    /**
+     * The h.
+     */
+    int h;
+
+    /**
+     * The maximum size.
+     */
+    private Dimension maximumSize;
+
+    /**
+     * The minimum size.
+     */
+    private Dimension minimumSize;
+
+    /**
+     * The preferred size.
+     */
+    private Dimension preferredSize;
+
+    /**
+     * The bounds mask param.
+     */
+    private int boundsMaskParam;
+
+    /**
+     * The ignore repaint.
+     */
+    private boolean ignoreRepaint;
+
+    /**
+     * The enabled.
+     */
+    private boolean enabled = true;
+
+    /**
+     * The input methods enabled.
+     */
+    private boolean inputMethodsEnabled = true;
+
+    /**
+     * The dispatch to im.
+     */
+    transient boolean dispatchToIM = true;
+
+    /**
+     * The focusable.
+     */
+    private boolean focusable = true; // By default, all Components return
+
+    // true from isFocusable() method
+    /**
+     * The visible.
+     */
+    boolean visible = true;
+
+    /**
+     * The called set focusable.
+     */
+    private boolean calledSetFocusable;
+
+    /**
+     * The overridden is focusable.
+     */
+    private boolean overridenIsFocusable = true;
+
+    /**
+     * The focus traversal keys enabled.
+     */
+    private boolean focusTraversalKeysEnabled = true;
+
+    /**
+     * Possible keys are: FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS,
+     * UP_CYCLE_TRAVERSAL_KEYS.
+     */
+    private final Map<Integer, Set<? extends AWTKeyStroke>> traversalKeys = new HashMap<Integer, Set<? extends AWTKeyStroke>>();
+
+    /**
+     * The traversal i ds.
+     */
+    int[] traversalIDs;
+
+    /**
+     * The locale.
+     */
+    private Locale locale;
+
+    /**
+     * The orientation.
+     */
+    private ComponentOrientation orientation;
+
+    /**
+     * The property change support.
+     */
+    private PropertyChangeSupport propertyChangeSupport;
+
+    // ???AWT: private ArrayList<PopupMenu> popups;
+
+    /**
+     * The coalescer.
+     */
+    private boolean coalescer;
+
+    /**
+     * The events table.
+     */
+    private Hashtable<Integer, LinkedList<AWTEvent>> eventsTable;
+
+    /**
+     * Cashed reference used during EventQueue.postEvent()
+     */
+    private LinkedList<AWTEvent> eventsList;
+
+    /**
+     * The hierarchy changing counter.
+     */
+    private int hierarchyChangingCounter;
+
+    /**
+     * The was showing.
+     */
+    private boolean wasShowing;
+
+    /**
+     * The was displayable.
+     */
+    private boolean wasDisplayable;
+
+    /**
+     * The cursor.
+     */
+    Cursor cursor;
+
+    // ???AWT: DropTarget dropTarget;
+
+    /**
+     * The mouse exited expected.
+     */
+    private boolean mouseExitedExpected;
+
+    /**
+     * The repaint region.
+     */
+    transient MultiRectArea repaintRegion;
+
+    // ???AWT: transient RedrawManager redrawManager;
+    /**
+     * The redraw manager.
+     */
+    transient Object redrawManager;
+
+    /**
+     * The valid.
+     */
+    private boolean valid;
+
+    /**
+     * The updated images.
+     */
+    private HashMap<Image, ImageParameters> updatedImages;
+
+    /**
+     * The lock object for private component's data which don't affect the
+     * component hierarchy.
+     */
+    private class ComponentLock {
+    }
+
+    /**
+     * The component lock.
+     */
+    private final transient Object componentLock = new ComponentLock();
+    static {
+        PrivilegedAction<String[]> action = new PrivilegedAction<String[]>() {
+            public String[] run() {
+                String properties[] = new String[2];
+                properties[0] = System.getProperty("awt.image.redrawrate", "100"); //$NON-NLS-1$ //$NON-NLS-2$
+                properties[1] = System.getProperty("awt.image.incrementaldraw", "true"); //$NON-NLS-1$ //$NON-NLS-2$
+                return properties;
+            }
+        };
+        String properties[] = AccessController.doPrivileged(action);
+        // FIXME: rate is never used, can this code and the get property above
+        // be removed?
+        // int rate;
+        //
+        // try {
+        // rate = Integer.decode(properties[0]).intValue();
+        // } catch (NumberFormatException e) {
+        // rate = 100;
+        // }
+        incrementalImageUpdate = properties[1].equals("true"); //$NON-NLS-1$
+    }
+
+    /**
+     * Instantiates a new component.
+     */
+    protected Component() {
+        toolkit.lockAWT();
+        try {
+            orientation = ComponentOrientation.UNKNOWN;
+            redrawManager = null;
+            // ???AWT
+            /*
+             * traversalIDs = this instanceof Container ?
+             * KeyboardFocusManager.contTraversalIDs :
+             * KeyboardFocusManager.compTraversalIDs; for (int element :
+             * traversalIDs) { traversalKeys.put(new Integer(element), null); }
+             * behaviour = createBehavior();
+             */
+            behaviour = null;
+
+            deriveCoalescerFlag();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Determine that the class inherited from Component declares the method
+     * coalesceEvents(), and put the results to the childClassesFlags map.
+     */
+    private void deriveCoalescerFlag() {
+        Class<?> thisClass = getClass();
+        boolean flag = true;
+        synchronized (childClassesFlags) {
+            Boolean flagWrapper = childClassesFlags.get(thisClass);
+            if (flagWrapper == null) {
+                Method coalesceMethod = null;
+                for (Class<?> c = thisClass; c != Component.class; c = c.getSuperclass()) {
+                    try {
+                        coalesceMethod = c.getDeclaredMethod("coalesceEvents", new Class[] { //$NON-NLS-1$
+                                        Class.forName("java.awt.AWTEvent"), //$NON-NLS-1$
+                                        Class.forName("java.awt.AWTEvent")}); //$NON-NLS-1$
+                    } catch (Exception e) {
+                    }
+                    if (coalesceMethod != null) {
+                        break;
+                    }
+                }
+                flag = (coalesceMethod != null);
+                childClassesFlags.put(thisClass, Boolean.valueOf(flag));
+            } else {
+                flag = flagWrapper.booleanValue();
+            }
+        }
+        coalescer = flag;
+        if (flag) {
+            eventsTable = new Hashtable<Integer, LinkedList<AWTEvent>>();
+        } else {
+            eventsTable = null;
+        }
+    }
+
+    /**
+     * Sets the name of the Component.
+     * 
+     * @param name
+     *            the new name of the Component.
+     */
+    public void setName(String name) {
+        String oldName;
+        toolkit.lockAWT();
+        try {
+            autoName = false;
+            oldName = this.name;
+            this.name = name;
+        } finally {
+            toolkit.unlockAWT();
+        }
+        firePropertyChange("name", oldName, name); //$NON-NLS-1$
+    }
+
+    /**
+     * Gets the name of this Component.
+     * 
+     * @return the name of this Component.
+     */
+    public String getName() {
+        toolkit.lockAWT();
+        try {
+            if ((name == null) && autoName) {
+                name = autoName();
+            }
+            return name;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Auto name.
+     * 
+     * @return the string.
+     */
+    String autoName() {
+        String name = getClass().getName();
+        if (name.indexOf("$") != -1) { //$NON-NLS-1$
+            return null;
+        }
+        // ???AWT
+        // int number = toolkit.autoNumber.nextComponent++;
+        int number = 0;
+        name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$
+        return name;
+    }
+
+    /**
+     * Returns the string representation of the Component.
+     * 
+     * @return the string representation of the Component.
+     */
+    @Override
+    public String toString() {
+        /*
+         * The format is based on 1.5 release behavior which can be revealed by
+         * the following code: Component c = new Component(){};
+         * c.setVisible(false); System.out.println(c);
+         */
+        toolkit.lockAWT();
+        try {
+            return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    // ???AWT
+    /*
+     * public void add(PopupMenu popup) { toolkit.lockAWT(); try { if
+     * (popup.getParent() == this) { return; } if (popups == null) { popups =
+     * new ArrayList<PopupMenu>(); } popup.setParent(this); popups.add(popup); }
+     * finally { toolkit.unlockAWT(); } }
+     */
+
+    /**
+     * Returns true, if the component contains the specified Point.
+     * 
+     * @param p
+     *            the Point.
+     * @return true, if the component contains the specified Point, false
+     *         otherwise.
+     */
+    public boolean contains(Point p) {
+        toolkit.lockAWT();
+        try {
+            return contains(p.x, p.y);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Returns true, if the component contains the point with the specified
+     * coordinates.
+     * 
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     * @return true, if the component contains the point with the specified
+     *         coordinates, false otherwise.
+     */
+    public boolean contains(int x, int y) {
+        toolkit.lockAWT();
+        try {
+            return inside(x, y);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Deprecated: replaced by replaced by getSize() method.
+     * 
+     * @return the dimension.
+     * @deprecated Replaced by getSize() method.
+     */
+    @Deprecated
+    public Dimension size() {
+        toolkit.lockAWT();
+        try {
+            return new Dimension(w, h);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    // ???AWT
+    /*
+     * public Container getParent() { toolkit.lockAWT(); try { return parent; }
+     * finally { toolkit.unlockAWT(); } }
+     */
+
+    /**
+     * List.
+     * 
+     * @param out
+     *            the out.
+     * @param indent
+     *            the indent
+     * @return the nearest heavyweight ancestor in hierarchy or
+     *         <code>null</code> if not found.
+     */
+    // ???AWT
+    /*
+     * Component getHWAncestor() { return (parent != null ?
+     * parent.getHWSurface() : null); }
+     */
+
+    /**
+     * @return heavyweight component that is equal to or is a nearest
+     *         heavyweight container of the current component, or
+     *         <code>null</code> if not found.
+     */
+    // ???AWT
+    /*
+     * Component getHWSurface() { Component parent; for (parent = this; (parent
+     * != null) && (parent.isLightweight()); parent = parent .getParent()) { ; }
+     * return parent; } Window getWindowAncestor() { Component par; for (par =
+     * this; par != null && !(par instanceof Window); par = par.getParent()) { ;
+     * } return (Window) par; }
+     */
+
+    /**
+     * To be called by container
+     */
+    // ???AWT
+    /*
+     * void setParent(Container parent) { this.parent = parent;
+     * setRedrawManager(); } void setRedrawManager() { redrawManager =
+     * getRedrawManager(); } public void remove(MenuComponent menu) {
+     * toolkit.lockAWT(); try { if (menu.getParent() == this) {
+     * menu.setParent(null); popups.remove(menu); } } finally {
+     * toolkit.unlockAWT(); } }
+     */
+    /**
+     * Prints a list of this component with the specified number of leading
+     * whitespace characters to the specified PrintStream.
+     * 
+     * @param out
+     *            the output PrintStream object.
+     * @param indent
+     *            how many leading whitespace characters to prepend.
+     */
+    public void list(PrintStream out, int indent) {
+        toolkit.lockAWT();
+        try {
+            out.println(getIndentStr(indent) + this);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Prints a list of this component to the specified PrintWriter.
+     * 
+     * @param out
+     *            the output PrintWriter object.
+     */
+    public void list(PrintWriter out) {
+        toolkit.lockAWT();
+        try {
+            list(out, 1);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Prints a list of this component with the specified number of leading
+     * whitespace characters to the specified PrintWriter.
+     * 
+     * @param out
+     *            the output PrintWriter object.
+     * @param indent
+     *            how many leading whitespace characters to prepend.
+     */
+    public void list(PrintWriter out, int indent) {
+        toolkit.lockAWT();
+        try {
+            out.println(getIndentStr(indent) + this);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets a string composed of the desired number of whitespace characters.
+     * 
+     * @param indent
+     *            the length of the String to return.
+     * @return the string composed of the desired number of whitespace
+     *         characters.
+     */
+    String getIndentStr(int indent) {
+        char[] ind = new char[indent];
+        for (int i = 0; i < indent; ind[i++] = ' ') {
+            ;
+        }
+        return new String(ind);
+    }
+
+    /**
+     * Prints a list of this component to the specified PrintStream.
+     * 
+     * @param out
+     *            the output PrintStream object.
+     */
+    public void list(PrintStream out) {
+        toolkit.lockAWT();
+        try {
+            // default indent = 1
+            list(out, 1);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Prints a list of this component to the standard system output stream.
+     */
+    public void list() {
+        toolkit.lockAWT();
+        try {
+            list(System.out);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Prints this component.
+     * 
+     * @param g
+     *            the Graphics to be used for painting.
+     */
+    public void print(Graphics g) {
+        toolkit.lockAWT();
+        try {
+            paint(g);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Prints the component and all of its subcomponents.
+     * 
+     * @param g
+     *            the Graphics to be used for painting.
+     */
+    public void printAll(Graphics g) {
+        toolkit.lockAWT();
+        try {
+            paintAll(g);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the size of the Component specified by width and height parameters.
+     * 
+     * @param width
+     *            the width of the Component.
+     * @param height
+     *            the height of the Component.
+     */
+    public void setSize(int width, int height) {
+        toolkit.lockAWT();
+        try {
+            resize(width, height);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the size of the Component specified by Dimension object.
+     * 
+     * @param d
+     *            the new size of the Component.
+     */
+    public void setSize(Dimension d) {
+        toolkit.lockAWT();
+        try {
+            resize(d);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Deprecated: replaced by setSize(int, int) method.
+     * 
+     * @param width
+     *            the width.
+     * @param height
+     *            the height.
+     * @deprecated Replaced by setSize(int, int) method.
+     */
+    @Deprecated
+    public void resize(int width, int height) {
+        toolkit.lockAWT();
+        try {
+            boundsMaskParam = NativeWindow.BOUNDS_NOMOVE;
+            setBounds(x, y, width, height);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Deprecated: replaced by setSize(int, int) method.
+     * 
+     * @param size
+     *            the size.
+     * @deprecated Replaced by setSize(int, int) method.
+     */
+    @Deprecated
+    public void resize(Dimension size) {
+        toolkit.lockAWT();
+        try {
+            setSize(size.width, size.height);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks whether or not this component is completely opaque.
+     * 
+     * @return true, if this component is completely opaque, false by default.
+     */
+    public boolean isOpaque() {
+        toolkit.lockAWT();
+        try {
+            return behaviour.isOpaque();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Disables.
+     * 
+     * @deprecated Replaced by setEnabled(boolean) method.
+     */
+    @Deprecated
+    public void disable() {
+        toolkit.lockAWT();
+        try {
+            setEnabledImpl(false);
+        } finally {
+            toolkit.unlockAWT();
+        }
+        // ???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, false);
+    }
+
+    /**
+     * Enables this component.
+     * 
+     * @deprecated Replaced by setEnabled(boolean) method.
+     */
+    @Deprecated
+    public void enable() {
+        toolkit.lockAWT();
+        try {
+            setEnabledImpl(true);
+        } finally {
+            toolkit.unlockAWT();
+        }
+        // ???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, true);
+    }
+
+    /**
+     * Enables or disable this component.
+     * 
+     * @param b
+     *            the boolean parameter.
+     * @deprecated Replaced by setEnabled(boolean) method.
+     */
+    @Deprecated
+    public void enable(boolean b) {
+        toolkit.lockAWT();
+        try {
+            if (b) {
+                enable();
+            } else {
+                disable();
+            }
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Stores the location of this component to the specified Point object;
+     * returns the point of the component's top-left corner.
+     * 
+     * @param rv
+     *            the Point object where the component's top-left corner
+     *            position will be stored.
+     * @return the Point which specifies the component's top-left corner.
+     */
+    public Point getLocation(Point rv) {
+        toolkit.lockAWT();
+        try {
+            if (rv == null) {
+                rv = new Point();
+            }
+            rv.setLocation(getX(), getY());
+            return rv;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the location of this component on the form; returns the point of the
+     * component's top-left corner.
+     * 
+     * @return the Point which specifies the component's top-left corner.
+     */
+    public Point getLocation() {
+        toolkit.lockAWT();
+        try {
+            return location();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the size of this Component.
+     * 
+     * @return the size of this Component.
+     */
+    public Dimension getSize() {
+        toolkit.lockAWT();
+        try {
+            return size();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Stores the size of this Component to the specified Dimension object.
+     * 
+     * @param rv
+     *            the Dimension object where the size of the Component will be
+     *            stored.
+     * @return the Dimension of this Component.
+     */
+    public Dimension getSize(Dimension rv) {
+        toolkit.lockAWT();
+        try {
+            if (rv == null) {
+                rv = new Dimension();
+            }
+            rv.setSize(getWidth(), getHeight());
+            return rv;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks whether or not this Component is valid. A component is valid if it
+     * is correctly sized and positioned within its parent container and all its
+     * children are also valid.
+     * 
+     * @return true, if the Component is valid, false otherwise.
+     */
+    public boolean isValid() {
+        toolkit.lockAWT();
+        try {
+            return valid && behaviour.isDisplayable();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Deprecated: replaced by getComponentAt(int, int) method.
+     * 
+     * @return the Point.
+     * @deprecated Replaced by getComponentAt(int, int) method.
+     */
+    @Deprecated
+    public Point location() {
+        toolkit.lockAWT();
+        try {
+            return new Point(x, y);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Connects this Component to a native screen resource and makes it
+     * displayable. This method not be called directly by user applications.
+     */
+    public void addNotify() {
+        toolkit.lockAWT();
+        try {
+            prepare4HierarchyChange();
+            behaviour.addNotify();
+            // ???AWT
+            // finishHierarchyChange(this, parent, 0);
+            // if (dropTarget != null) {
+            // dropTarget.addNotify(peer);
+            // }
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Map to display.
+     * 
+     * @param b
+     *            the b.
+     */
+    void mapToDisplay(boolean b) {
+        // ???AWT
+        /*
+         * if (b && !isDisplayable()) { if ((this instanceof Window) || ((parent
+         * != null) && parent.isDisplayable())) { addNotify(); } } else if (!b
+         * && isDisplayable()) { removeNotify(); }
+         */
+    }
+
+    /**
+     * Gets the toolkit.
+     * 
+     * @return accessible context specific for particular component.
+     */
+    // ???AWT
+    /*
+     * AccessibleContext createAccessibleContext() { return null; } public
+     * AccessibleContext getAccessibleContext() { toolkit.lockAWT(); try { if
+     * (accessibleContext == null) { accessibleContext =
+     * createAccessibleContext(); } return accessibleContext; } finally {
+     * toolkit.unlockAWT(); } }
+     */
+
+    /**
+     * Gets Toolkit for the current Component.
+     * 
+     * @return the Toolkit of this Component.
+     */
+    public Toolkit getToolkit() {
+        return toolkit;
+    }
+
+    /**
+     * Gets this component's locking object for AWT component tree and layout
+     * operations.
+     * 
+     * @return the tree locking object.
+     */
+    public final Object getTreeLock() {
+        return toolkit.awtTreeLock;
+    }
+
+    /**
+     * Handles the event. Use ActionListener instead of this.
+     * 
+     * @param evt
+     *            the Event.
+     * @param what
+     *            the event's key.
+     * @return true, if successful.
+     * @deprecated Use ActionListener class for registering event listener.
+     */
+    @Deprecated
+    public boolean action(Event evt, Object what) {
+        // to be overridden: do nothing,
+        // just return false to propagate event up to the parent container
+        return false;
+    }
+
+    /**
+     * Gets the property change support.
+     * 
+     * @return the property change support.
+     */
+    private PropertyChangeSupport getPropertyChangeSupport() {
+        synchronized (componentLock) {
+            if (propertyChangeSupport == null) {
+                propertyChangeSupport = new PropertyChangeSupport(this);
+            }
+            return propertyChangeSupport;
+        }
+    }
+
+    // ???AWT
+    /*
+     * public void addPropertyChangeListener(PropertyChangeListener listener) {
+     * getPropertyChangeSupport().addPropertyChangeListener(listener); } public
+     * void addPropertyChangeListener(String propertyName,
+     * PropertyChangeListener listener) {
+     * getPropertyChangeSupport().addPropertyChangeListener(propertyName,
+     * listener); } public void applyComponentOrientation(ComponentOrientation
+     * orientation) { toolkit.lockAWT(); try {
+     * setComponentOrientation(orientation); } finally { toolkit.unlockAWT(); }
+     * }
+     */
+
+    /**
+     * Returns true if the set of focus traversal keys for the given focus
+     * traversal operation has been explicitly defined for this Component.
+     * 
+     * @param id
+     *            the ID of traversal key.
+     * @return true, if the set of focus traversal keys for the given focus.
+     *         traversal operation has been explicitly defined for this
+     *         Component, false otherwise.
+     */
+    public boolean areFocusTraversalKeysSet(int id) {
+        toolkit.lockAWT();
+        try {
+            Integer Id = new Integer(id);
+            if (traversalKeys.containsKey(Id)) {
+                return traversalKeys.get(Id) != null;
+            }
+            // awt.14F=invalid focus traversal key identifier
+            throw new IllegalArgumentException(Messages.getString("awt.14F")); //$NON-NLS-1$
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the bounds of the Component.
+     * 
+     * @return the rectangle bounds of the Component.
+     * @deprecated Use getBounds() methood.
+     */
+    @Deprecated
+    public Rectangle bounds() {
+        toolkit.lockAWT();
+        try {
+            return new Rectangle(x, y, w, h);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Returns the construction status of a specified image with the specified
+     * width and height that is being created.
+     * 
+     * @param image
+     *            the image to be checked.
+     * @param width
+     *            the width of scaled image which status is being checked, or
+     *            -1.
+     * @param height
+     *            the height of scaled image which status is being checked, or
+     *            -1.
+     * @param observer
+     *            the ImageObserver object to be notified while the image is
+     *            being prepared.
+     * @return the ImageObserver flags of the current state of the image data.
+     */
+    public int checkImage(Image image, int width, int height, ImageObserver observer) {
+        toolkit.lockAWT();
+        try {
+            return toolkit.checkImage(image, width, height, observer);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Returns the construction status of a specified image that is being
+     * created.
+     * 
+     * @param image
+     *            the image to be checked.
+     * @param observer
+     *            the ImageObserver object to be notified while the image is
+     *            being prepared.
+     * @return the ImageObserver flags of the current state of the image data.
+     */
+    public int checkImage(Image image, ImageObserver observer) {
+        toolkit.lockAWT();
+        try {
+            return toolkit.checkImage(image, -1, -1, observer);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Coalesces the existed event with new event.
+     * 
+     * @param existingEvent
+     *            the existing event in the EventQueue.
+     * @param newEvent
+     *            the new event to be posted to the EventQueue.
+     * @return the coalesced AWTEvent, or null if there is no coalescing done.
+     */
+    protected AWTEvent coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent) {
+        toolkit.lockAWT();
+        try {
+            // Nothing to do:
+            // 1. Mouse events coalesced at WTK level
+            // 2. Paint events handled by RedrawManager
+            // This method is for overriding only
+            return null;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks if this Component is a coalescer.
+     * 
+     * @return true, if is coalescer.
+     */
+    boolean isCoalescer() {
+        return coalescer;
+    }
+
+    /**
+     * Gets the relative event.
+     * 
+     * @param id
+     *            the id.
+     * @return the relative event.
+     */
+    AWTEvent getRelativeEvent(int id) {
+        Integer idWrapper = new Integer(id);
+        eventsList = eventsTable.get(idWrapper);
+        if (eventsList == null) {
+            eventsList = new LinkedList<AWTEvent>();
+            eventsTable.put(idWrapper, eventsList);
+            return null;
+        }
+        if (eventsList.isEmpty()) {
+            return null;
+        }
+        return eventsList.getLast();
+    }
+
+    /**
+     * Adds the new event.
+     * 
+     * @param event
+     *            the event.
+     */
+    void addNewEvent(AWTEvent event) {
+        eventsList.addLast(event);
+    }
+
+    /**
+     * Removes the relative event.
+     */
+    void removeRelativeEvent() {
+        eventsList.removeLast();
+    }
+
+    /**
+     * Removes the next event.
+     * 
+     * @param id
+     *            the id.
+     */
+    void removeNextEvent(int id) {
+        eventsTable.get(new Integer(id)).removeFirst();
+    }
+
+    /**
+     * Creates the image with the specified ImageProducer.
+     * 
+     * @param producer
+     *            the ImageProducer to be used for image creation.
+     * @return the image with the specified ImageProducer.
+     */
+    public Image createImage(ImageProducer producer) {
+        toolkit.lockAWT();
+        try {
+            return toolkit.createImage(producer);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Creates an off-screen drawable image to be used for double buffering.
+     * 
+     * @param width
+     *            the width of the image.
+     * @param height
+     *            the height of the image.
+     * @return the off-screen drawable image or null if the component is not
+     *         displayable or GraphicsEnvironment.isHeadless() method returns
+     *         true.
+     */
+    public Image createImage(int width, int height) {
+        toolkit.lockAWT();
+        try {
+            if (!isDisplayable()) {
+                return null;
+            }
+            GraphicsConfiguration gc = getGraphicsConfiguration();
+            if (gc == null) {
+                return null;
+            }
+            ColorModel cm = gc.getColorModel(Transparency.OPAQUE);
+            WritableRaster wr = cm.createCompatibleWritableRaster(width, height);
+            Image image = new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), null);
+            fillImageBackground(image, width, height);
+            return image;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Creates an off-screen drawable image with the specified width, height and
+     * ImageCapabilities.
+     * 
+     * @param width
+     *            the width.
+     * @param height
+     *            the height.
+     * @param caps
+     *            the ImageCapabilities.
+     * @return the volatile image.
+     * @throws AWTException
+     *             if an image with the specified capabilities cannot be
+     *             created.
+     */
+    public VolatileImage createVolatileImage(int width, int height, ImageCapabilities caps)
+            throws AWTException {
+        toolkit.lockAWT();
+        try {
+            if (!isDisplayable()) {
+                return null;
+            }
+            GraphicsConfiguration gc = getGraphicsConfiguration();
+            if (gc == null) {
+                return null;
+            }
+            VolatileImage image = gc.createCompatibleVolatileImage(width, height, caps);
+            fillImageBackground(image, width, height);
+            return image;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Creates a volatile off-screen drawable image which is used for double
+     * buffering.
+     * 
+     * @param width
+     *            the width of image.
+     * @param height
+     *            the height of image.
+     * @return the volatile image a volatile off-screen drawable image which is
+     *         used for double buffering or null if the component is not
+     *         displayable, or GraphicsEnvironment.isHeadless() method returns
+     *         true.
+     */
+    public VolatileImage createVolatileImage(int width, int height) {
+        toolkit.lockAWT();
+        try {
+            if (!isDisplayable()) {
+                return null;
+            }
+            GraphicsConfiguration gc = getGraphicsConfiguration();
+            if (gc == null) {
+                return null;
+            }
+            VolatileImage image = gc.createCompatibleVolatileImage(width, height);
+            fillImageBackground(image, width, height);
+            return image;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Fill the image being created by createImage() or createVolatileImage()
+     * with the component's background color to prepare it for double-buffered
+     * painting.
+     * 
+     * @param image
+     *            the image.
+     * @param width
+     *            the width.
+     * @param height
+     *            the height.
+     */
+    private void fillImageBackground(Image image, int width, int height) {
+        Graphics gr = image.getGraphics();
+        gr.setColor(getBackground());
+        gr.fillRect(0, 0, width, height);
+        gr.dispose();
+    }
+
+    /**
+     * Delivers event.
+     * 
+     * @param evt
+     *            the event.
+     * @deprecated Replaced by dispatchEvent(AWTEvent e) method.
+     */
+    @Deprecated
+    public void deliverEvent(Event evt) {
+        postEvent(evt);
+    }
+
+    /**
+     * Prompts the layout manager to lay out this component.
+     */
+    public void doLayout() {
+        toolkit.lockAWT();
+        try {
+            layout();
+        } finally {
+            toolkit.unlockAWT();
+        }
+        // Implemented in Container
+    }
+
+    /**
+     * Fire property change impl.
+     * 
+     * @param propertyName
+     *            the property name.
+     * @param oldValue
+     *            the old value.
+     * @param newValue
+     *            the new value.
+     */
+    private void firePropertyChangeImpl(String propertyName, Object oldValue, Object newValue) {
+        PropertyChangeSupport pcs;
+        synchronized (componentLock) {
+            if (propertyChangeSupport == null) {
+                return;
+            }
+            pcs = propertyChangeSupport;
+        }
+        pcs.firePropertyChange(propertyName, oldValue, newValue);
+    }
+
+    /**
+     * Reports a bound property changes for int properties.
+     * 
+     * @param propertyName
+     *            the property name.
+     * @param oldValue
+     *            the old property's value.
+     * @param newValue
+     *            the new property's value.
+     */
+    protected void firePropertyChange(String propertyName, int oldValue, int newValue) {
+        firePropertyChangeImpl(propertyName, new Integer(oldValue), new Integer(newValue));
+    }
+
+    /**
+     * Report a bound property change for a boolean-valued property.
+     * 
+     * @param propertyName
+     *            the property name.
+     * @param oldValue
+     *            the property's old value.
+     * @param newValue
+     *            the property's new value.
+     */
+    protected void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
+        firePropertyChangeImpl(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
+    }
+
+    /**
+     * Reports a bound property change for an Object-valued property.
+     * 
+     * @param propertyName
+     *            the property name.
+     * @param oldValue
+     *            the property's old value.
+     * @param newValue
+     *            the property's new value.
+     */
+    protected void firePropertyChange(final String propertyName, final Object oldValue,
+            final Object newValue) {
+        firePropertyChangeImpl(propertyName, oldValue, newValue);
+    }
+
+    /**
+     * Report a bound property change for a byte-valued property.
+     * 
+     * @param propertyName
+     *            the property name.
+     * @param oldValue
+     *            the property's old value.
+     * @param newValue
+     *            the property's new value.
+     */
+    public void firePropertyChange(String propertyName, byte oldValue, byte newValue) {
+        firePropertyChangeImpl(propertyName, new Byte(oldValue), new Byte(newValue));
+    }
+
+    /**
+     * Report a bound property change for a char-valued property.
+     * 
+     * @param propertyName
+     *            the property name.
+     * @param oldValue
+     *            the old property's value.
+     * @param newValue
+     *            the new property's value.
+     */
+    public void firePropertyChange(String propertyName, char oldValue, char newValue) {
+        firePropertyChangeImpl(propertyName, new Character(oldValue), new Character(newValue));
+    }
+
+    /**
+     * Report a bound property change for a short-valued property.
+     * 
+     * @param propertyName
+     *            the property name.
+     * @param oldValue
+     *            the old property's value.
+     * @param newValue
+     *            the new property's value.
+     */
+    public void firePropertyChange(String propertyName, short oldValue, short newValue) {
+        firePropertyChangeImpl(propertyName, new Short(oldValue), new Short(newValue));
+    }
+
+    /**
+     * Report a bound property change for a long-valued property.
+     * 
+     * @param propertyName
+     *            the property name.
+     * @param oldValue
+     *            the old property's value.
+     * @param newValue
+     *            the new property's value.
+     */
+    public void firePropertyChange(String propertyName, long oldValue, long newValue) {
+        firePropertyChangeImpl(propertyName, new Long(oldValue), new Long(newValue));
+    }
+
+    /**
+     * Report a bound property change for a float-valued property.
+     * 
+     * @param propertyName
+     *            the property name.
+     * @param oldValue
+     *            the old property's value.
+     * @param newValue
+     *            the new property's value.
+     */
+    public void firePropertyChange(String propertyName, float oldValue, float newValue) {
+        firePropertyChangeImpl(propertyName, new Float(oldValue), new Float(newValue));
+    }
+
+    /**
+     * Report a bound property change for a double-valued property.
+     * 
+     * @param propertyName
+     *            the property name.
+     * @param oldValue
+     *            the old property's value.
+     * @param newValue
+     *            the new property's value.
+     */
+    public void firePropertyChange(String propertyName, double oldValue, double newValue) {
+        firePropertyChangeImpl(propertyName, new Double(oldValue), new Double(newValue));
+    }
+
+    /**
+     * Gets the alignment along the x axis.
+     * 
+     * @return the alignment along the x axis.
+     */
+    public float getAlignmentX() {
+        toolkit.lockAWT();
+        try {
+            return CENTER_ALIGNMENT;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the alignment along the y axis.
+     * 
+     * @return the alignment along y axis.
+     */
+    public float getAlignmentY() {
+        toolkit.lockAWT();
+        try {
+            return CENTER_ALIGNMENT;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the background color for this component.
+     * 
+     * @return the background color for this component.
+     */
+    public Color getBackground() {
+        toolkit.lockAWT();
+        try {
+            // ???AWT
+            /*
+             * if ((backColor == null) && (parent != null)) { return
+             * parent.getBackground(); }
+             */
+            return backColor;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the bounding rectangle of this component.
+     * 
+     * @return the bounding rectangle of this component.
+     */
+    public Rectangle getBounds() {
+        toolkit.lockAWT();
+        try {
+            return bounds();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Writes the data of the bounding rectangle to the specified Rectangle
+     * object.
+     * 
+     * @param rv
+     *            the Rectangle object where the bounding rectangle's data is
+     *            stored.
+     * @return the bounding rectangle.
+     */
+    public Rectangle getBounds(Rectangle rv) {
+        toolkit.lockAWT();
+        try {
+            if (rv == null) {
+                rv = new Rectangle();
+            }
+            rv.setBounds(x, y, w, h);
+            return rv;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the color model of the Component.
+     * 
+     * @return the color model of the Component.
+     */
+    public ColorModel getColorModel() {
+        toolkit.lockAWT();
+        try {
+            return getToolkit().getColorModel();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the Component which contains the specified Point.
+     * 
+     * @param p
+     *            the Point.
+     * @return the Component which contains the specified Point.
+     */
+    public Component getComponentAt(Point p) {
+        toolkit.lockAWT();
+        try {
+            return getComponentAt(p.x, p.y);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the Component which contains the point with the specified
+     * coordinates.
+     * 
+     * @param x
+     *            the x coordinate of the point.
+     * @param y
+     *            the y coordinate of the point.
+     * @return the Component which contains the point with the specified
+     *         coordinates.
+     */
+    public Component getComponentAt(int x, int y) {
+        toolkit.lockAWT();
+        try {
+            return locate(x, y);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the component's orientation.
+     * 
+     * @return the component's orientation.
+     */
+    public ComponentOrientation getComponentOrientation() {
+        toolkit.lockAWT();
+        try {
+            return orientation;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the cursor of the Component.
+     * 
+     * @return the Cursor.
+     */
+    public Cursor getCursor() {
+        toolkit.lockAWT();
+        try {
+            if (cursor != null) {
+                return cursor;
+                // ???AWT
+                /*
+                 * } else if (parent != null) { return parent.getCursor();
+                 */
+            }
+            return Cursor.getDefaultCursor();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    // ???AWT
+    /*
+     * public DropTarget getDropTarget() { toolkit.lockAWT(); try { return
+     * dropTarget; } finally { toolkit.unlockAWT(); } } public Container
+     * getFocusCycleRootAncestor() { toolkit.lockAWT(); try { for (Container c =
+     * parent; c != null; c = c.getParent()) { if (c.isFocusCycleRoot()) {
+     * return c; } } return null; } finally { toolkit.unlockAWT(); } }
+     * @SuppressWarnings("unchecked") public Set<AWTKeyStroke>
+     * getFocusTraversalKeys(int id) { toolkit.lockAWT(); try { Integer kId =
+     * new Integer(id); KeyboardFocusManager.checkTraversalKeysID(traversalKeys,
+     * kId); Set<? extends AWTKeyStroke> keys = traversalKeys.get(kId); if (keys
+     * == null && parent != null) { keys = parent.getFocusTraversalKeys(id); }
+     * if (keys == null) { keys =
+     * KeyboardFocusManager.getCurrentKeyboardFocusManager()
+     * .getDefaultFocusTraversalKeys(id); } return (Set<AWTKeyStroke>) keys; }
+     * finally { toolkit.unlockAWT(); } }
+     */
+
+    /**
+     * Checks if the the focus traversal keys are enabled for this component.
+     * 
+     * @return true, if the the focus traversal keys are enabled for this
+     *         component, false otherwise.
+     */
+    public boolean getFocusTraversalKeysEnabled() {
+        toolkit.lockAWT();
+        try {
+            return focusTraversalKeysEnabled;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the font metrics of the specified Font.
+     * 
+     * @param f
+     *            the Font.
+     * @return the FontMetrics of the specified Font.
+     */
+    @SuppressWarnings("deprecation")
+    public FontMetrics getFontMetrics(Font f) {
+        return toolkit.getFontMetrics(f);
+    }
+
+    /**
+     * Gets the foreground color of the Component.
+     * 
+     * @return the foreground color of the Component.
+     */
+    public Color getForeground() {
+        toolkit.lockAWT();
+        try {
+            // ???AWT
+            /*
+             * if (foreColor == null && parent != null) { return
+             * parent.getForeground(); }
+             */
+            return foreColor;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the Graphics of the Component or null if this Component is not
+     * displayable.
+     * 
+     * @return the Graphics of the Component or null if this Component is not
+     *         displayable.
+     */
+    public Graphics getGraphics() {
+        toolkit.lockAWT();
+        try {
+            if (!isDisplayable()) {
+                return null;
+            }
+            Graphics g = behaviour.getGraphics(0, 0, w, h);
+            g.setColor(foreColor);
+            g.setFont(font);
+            return g;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the GraphicsConfiguration associated with this Component.
+     * 
+     * @return the GraphicsConfiguration associated with this Component.
+     */
+    public GraphicsConfiguration getGraphicsConfiguration() {
+        // ???AWT
+        /*
+         * toolkit.lockAWT(); try { Window win = getWindowAncestor(); if (win ==
+         * null) { return null; } return win.getGraphicsConfiguration(); }
+         * finally { toolkit.unlockAWT(); }
+         */
+        return null;
+    }
+
+    /**
+     * Gets the height of the Component.
+     * 
+     * @return the height of the Component.
+     */
+    public int getHeight() {
+        toolkit.lockAWT();
+        try {
+            return h;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Returns true if paint messages received from the operating system should
+     * be ignored.
+     * 
+     * @return true if paint messages received from the operating system should
+     *         be ignored, false otherwise.
+     */
+    public boolean getIgnoreRepaint() {
+        toolkit.lockAWT();
+        try {
+            return ignoreRepaint;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the input context of this component for handling the communication
+     * with input methods when text is entered in this component.
+     * 
+     * @return the InputContext used by this Component or null if no context is
+     *         specifined.
+     */
+    public InputContext getInputContext() {
+        toolkit.lockAWT();
+        try {
+            // ???AWT
+            /*
+             * Container parent = getParent(); if (parent != null) { return
+             * parent.getInputContext(); }
+             */
+            return null;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the input method request handler which supports requests from input
+     * methods for this component, or null for default.
+     * 
+     * @return the input method request handler which supports requests from
+     *         input methods for this component, or null for default.
+     */
+    public InputMethodRequests getInputMethodRequests() {
+        return null;
+    }
+
+    /**
+     * Gets the locale of this Component.
+     * 
+     * @return the locale of this Component.
+     */
+    public Locale getLocale() {
+        toolkit.lockAWT();
+        try {
+            // ???AWT
+            /*
+             * if (locale == null) { if (parent == null) { if (this instanceof
+             * Window) { return Locale.getDefault(); } // awt.150=no parent
+             * throw new
+             * IllegalComponentStateException(Messages.getString("awt.150"));
+             * //$NON-NLS-1$ } return getParent().getLocale(); }
+             */
+            return locale;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the location of this component in the form of a point specifying the
+     * component's top-left corner in the screen's coordinate space.
+     * 
+     * @return the Point giving the component's location in the screen's
+     *         coordinate space.
+     * @throws IllegalComponentStateException
+     *             if the component is not shown on the screen.
+     */
+    public Point getLocationOnScreen() throws IllegalComponentStateException {
+        toolkit.lockAWT();
+        try {
+            Point p = new Point();
+            if (isShowing()) {
+                // ???AWT
+                /*
+                 * Component comp; for (comp = this; comp != null && !(comp
+                 * instanceof Window); comp = comp .getParent()) {
+                 * p.translate(comp.getX(), comp.getY()); } if (comp instanceof
+                 * Window) { p.translate(comp.getX(), comp.getY()); }
+                 */
+                return p;
+            }
+            // awt.151=component must be showing on the screen to determine its
+            // location
+            throw new IllegalComponentStateException(Messages.getString("awt.151")); //$NON-NLS-1$
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the peer. This method should not be called directly by user
+     * applications.
+     * 
+     * @return the ComponentPeer.
+     * @deprecated Replaced by isDisplayable().
+     */
+    @Deprecated
+    public ComponentPeer getPeer() {
+        toolkit.lockAWT();
+        try {
+            if (behaviour.isDisplayable()) {
+                return peer;
+            }
+            return null;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets an array of the property change listeners registered to this
+     * Component.
+     * 
+     * @return an array of the PropertyChangeListeners registered to this
+     *         Component.
+     */
+    public PropertyChangeListener[] getPropertyChangeListeners() {
+        return getPropertyChangeSupport().getPropertyChangeListeners();
+    }
+
+    /**
+     * Gets an array of PropertyChangeListener objects registered to this
+     * Component for the specified property.
+     * 
+     * @param propertyName
+     *            the property name.
+     * @return an array of PropertyChangeListener objects registered to this
+     *         Component for the specified property.
+     */
+    public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
+        return getPropertyChangeSupport().getPropertyChangeListeners(propertyName);
+    }
+
+    /**
+     * Gets the width of the Component.
+     * 
+     * @return the width of the Component.
+     */
+    public int getWidth() {
+        toolkit.lockAWT();
+        try {
+            return w;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the x coordinate of the component's top-left corner.
+     * 
+     * @return the x coordinate of the component's top-left corner.
+     */
+    public int getX() {
+        toolkit.lockAWT();
+        try {
+            return x;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the y coordinate of the component's top-left corner.
+     * 
+     * @return the y coordinate of the component's top-left corner.
+     */
+    public int getY() {
+        toolkit.lockAWT();
+        try {
+            return y;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Got the focus.
+     * 
+     * @param evt
+     *            the Event.
+     * @param what
+     *            the Object.
+     * @return true, if successful.
+     * @deprecated Replaced by processFocusEvent(FocusEvent) method.
+     */
+    @Deprecated
+    public boolean gotFocus(Event evt, Object what) {
+        // to be overridden: do nothing,
+        // just return false to propagate event up to the parent container
+        return false;
+    }
+
+    /**
+     * Handles event.
+     * 
+     * @param evt
+     *            the Event.
+     * @return true, if successful.
+     * @deprecated Replaced by processEvent(AWTEvent) method.
+     */
+    @Deprecated
+    public boolean handleEvent(Event evt) {
+        switch (evt.id) {
+            case Event.ACTION_EVENT:
+                return action(evt, evt.arg);
+            case Event.GOT_FOCUS:
+                return gotFocus(evt, null);
+            case Event.LOST_FOCUS:
+                return lostFocus(evt, null);
+            case Event.MOUSE_DOWN:
+                return mouseDown(evt, evt.x, evt.y);
+            case Event.MOUSE_DRAG:
+                return mouseDrag(evt, evt.x, evt.y);
+            case Event.MOUSE_ENTER:
+                return mouseEnter(evt, evt.x, evt.y);
+            case Event.MOUSE_EXIT:
+                return mouseExit(evt, evt.x, evt.y);
+            case Event.MOUSE_MOVE:
+                return mouseMove(evt, evt.x, evt.y);
+            case Event.MOUSE_UP:
+                return mouseUp(evt, evt.x, evt.y);
+            case Event.KEY_ACTION:
+            case Event.KEY_PRESS:
+                return keyDown(evt, evt.key);
+            case Event.KEY_ACTION_RELEASE:
+            case Event.KEY_RELEASE:
+                return keyUp(evt, evt.key);
+        }
+        return false;// event not handled
+    }
+
+    /**
+     * Checks whether the Component is the focus owner or not.
+     * 
+     * @return true, if the Component is the focus owner, false otherwise.
+     */
+    public boolean hasFocus() {
+        toolkit.lockAWT();
+        try {
+            // ???AWT: return isFocusOwner();
+            return false;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Hides the Component.
+     * 
+     * @deprecated Replaced by setVisible(boolean) method.
+     */
+    @Deprecated
+    public void hide() {
+        toolkit.lockAWT();
+        try {
+            if (!visible) {
+                return;
+            }
+            prepare4HierarchyChange();
+            visible = false;
+            moveFocusOnHide();
+            behaviour.setVisible(false);
+            postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_HIDDEN));
+            // ???AWT: finishHierarchyChange(this, parent, 0);
+            notifyInputMethod(null);
+            // ???AWT: invalidateRealParent();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks whether or not the point with the specified coordinates belongs to
+     * the Commponent.
+     * 
+     * @param x
+     *            the x coordinate of the Point.
+     * @param y
+     *            the y coordinate of the Point.
+     * @return true, if the point with the specified coordinates belongs to the
+     *         Commponent, false otherwise.
+     * @deprecated Replaced by contains(int, int) method.
+     */
+    @Deprecated
+    public boolean inside(int x, int y) {
+        toolkit.lockAWT();
+        try {
+            return x >= 0 && x < getWidth() && y >= 0 && y < getHeight();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Invalidates the component, this component and all parents above it are
+     * marked as needing to be laid out.
+     */
+    public void invalidate() {
+        toolkit.lockAWT();
+        try {
+            valid = false;
+            resetDefaultSize();
+            // ???AWT: invalidateRealParent();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks whether or not the background color is set to this Component.
+     * 
+     * @return true, if the background color is set to this Component, false
+     *         otherwise.
+     */
+    public boolean isBackgroundSet() {
+        toolkit.lockAWT();
+        try {
+            return backColor != null;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks whether or not a cursor is set for the Component.
+     * 
+     * @return true, if a cursor is set for the Component, false otherwise.
+     */
+    public boolean isCursorSet() {
+        toolkit.lockAWT();
+        try {
+            return cursor != null;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks whether or not this Component is displayable.
+     * 
+     * @return true, if this Component is displayable, false otherwise.
+     */
+    public boolean isDisplayable() {
+        toolkit.lockAWT();
+        try {
+            return behaviour.isDisplayable();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks whether or not this component is painted to an buffer which is
+     * copied to the screen later.
+     * 
+     * @return true, if this component is painted to an buffer which is copied
+     *         to the screen later, false otherwise.
+     */
+    public boolean isDoubleBuffered() {
+        toolkit.lockAWT();
+        try {
+            // false by default
+            return false;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks whether or not this Component is enabled.
+     * 
+     * @return true, if this Component is enabled, false otherwise.
+     */
+    public boolean isEnabled() {
+        toolkit.lockAWT();
+        try {
+            return enabled;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * "Recursive" isEnabled().
+     * 
+     * @return true if not only component itself is enabled but its heavyweight
+     *         parent is also "indirectly" enabled.
+     */
+    boolean isIndirectlyEnabled() {
+        Component comp = this;
+        while (comp != null) {
+            if (!comp.isLightweight() && !comp.isEnabled()) {
+                return false;
+            }
+            // ???AWT: comp = comp.getRealParent();
+        }
+        return true;
+    }
+
+    /**
+     * Checks if the component is key enabled.
+     * 
+     * @return true, if the component is enabled and indirectly enabled.
+     */
+    boolean isKeyEnabled() {
+        if (!isEnabled()) {
+            return false;
+        }
+        return isIndirectlyEnabled();
+    }
+
+    /**
+     * Gets only parent of a child component, but not owner of a window.
+     * 
+     * @return parent of child component, null if component is a top-level
+     *         (Window instance).
+     */
+    // ???AWT
+    /*
+     * Container getRealParent() { return (!(this instanceof Window) ?
+     * getParent() : null); } public boolean isFocusCycleRoot(Container
+     * container) { toolkit.lockAWT(); try { return getFocusCycleRootAncestor()
+     * == container; } finally { toolkit.unlockAWT(); } } public boolean
+     * isFocusOwner() { toolkit.lockAWT(); try { return
+     * KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() ==
+     * this; } finally { toolkit.unlockAWT(); } }
+     */
+
+    /**
+     * Checks whether or not this Component can be focusable.
+     * 
+     * @return true, if this Component can be focusable, false otherwise.
+     * @deprecated Replaced by isFocusable().
+     */
+    @Deprecated
+    public boolean isFocusTraversable() {
+        toolkit.lockAWT();
+        try {
+            overridenIsFocusable = false;
+            return focusable; // a Component must either be both focusable and
+            // focus traversable, or neither
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks if this Component can be focusable or not.
+     * 
+     * @return true, if this Component can be focusable, false otherwise.
+     */
+    public boolean isFocusable() {
+        toolkit.lockAWT();
+        try {
+            return isFocusTraversable();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks if the Font is set for this Component or not.
+     * 
+     * @return true, if the Font is set, false otherwise.
+     */
+    public boolean isFontSet() {
+        toolkit.lockAWT();
+        try {
+            return font != null;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks if foreground color is set for the Component or not.
+     * 
+     * @return true, if is foreground color is set for the Component, false
+     *         otherwise.
+     */
+    public boolean isForegroundSet() {
+        toolkit.lockAWT();
+        try {
+            return foreColor != null;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Returns true if this component has a lightweight peer.
+     * 
+     * @return true, if this component has a lightweight peer, false if it has a
+     *         native peer or no peer.
+     */
+    public boolean isLightweight() {
+        toolkit.lockAWT();
+        try {
+            return behaviour.isLightweight();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks whether or not this Component is shown.
+     * 
+     * @return true, if this Component is shown, false otherwise.
+     */
+    public boolean isShowing() {
+        // ???AWT
+        /*
+         * toolkit.lockAWT(); try { return (isVisible() && isDisplayable() &&
+         * (parent != null) && parent.isShowing()); } finally {
+         * toolkit.unlockAWT(); }
+         */
+        return false;
+    }
+
+    /**
+     * Checks whether or not this Component is visible.
+     * 
+     * @return true, if the Component is visible, false otherwise.
+     */
+    public boolean isVisible() {
+        toolkit.lockAWT();
+        try {
+            return visible;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Deprecated: replaced by processKeyEvent(KeyEvent) method.
+     * 
+     * @param evt
+     *            the Event.
+     * @param key
+     *            the key code.
+     * @return true, if successful.
+     * @deprecated Replaced by replaced by processKeyEvent(KeyEvent) method.
+     */
+    @Deprecated
+    public boolean keyDown(Event evt, int key) {
+        // to be overridden: do nothing,
+        // just return false to propagate event up to the parent container
+        return false;
+    }
+
+    /**
+     * Deprecated: replaced by processKeyEvent(KeyEvent) method.
+     * 
+     * @param evt
+     *            the Event.
+     * @param key
+     *            the key code.
+     * @return true, if successful.
+     * @deprecated Replaced by processKeyEvent(KeyEvent) method.
+     */
+    @Deprecated
+    public boolean keyUp(Event evt, int key) {
+        // to be overridden: do nothing,
+        // just return false to propagate event up to the parent container
+        return false;
+    }
+
+    /**
+     * Deprecated: Replaced by doLayout() method.
+     * 
+     * @deprecated Replaced by doLayout() method.
+     */
+    @Deprecated
+    public void layout() {
+        toolkit.lockAWT();
+        try {
+            // Implemented in Container
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Deprecated: replaced by getComponentAt(int, int) method.
+     * 
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     * @return The component.
+     * @deprecated Replaced by getComponentAt(int, int) method.
+     */
+    @Deprecated
+    public Component locate(int x, int y) {
+        toolkit.lockAWT();
+        try {
+            if (contains(x, y)) {
+                return this;
+            }
+            return null;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Deprecated: replaced by processFocusEvent(FocusEvent).
+     * 
+     * @param evt
+     *            the Event.
+     * @param what
+     *            the Object.
+     * @return true, if successful.
+     * @deprecated Replaced by processFocusEvent(FocusEvent).
+     */
+    @Deprecated
+    public boolean lostFocus(Event evt, Object what) {
+        // to be overridden: do nothing,
+        // just return false to propagate event up to the parent container
+        return false;
+    }
+
+    /**
+     * Deprecated: replaced by processMouseEvent(MouseEvent) method.
+     * 
+     * @param evt
+     *            the MouseEvent.
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     * @return true, if successful.
+     * @deprecated Replaced by processMouseEvent(MouseEvent) method.
+     */
+    @Deprecated
+    public boolean mouseDown(Event evt, int x, int y) {
+        // to be overridden: do nothing,
+        // just return false to propagate event up to the parent container
+        return false;
+    }
+
+    /**
+     * Deprecated: replaced by getMinimumSize() method.
+     * 
+     * @param evt
+     *            the Event.
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     * @return true, if successful.
+     * @deprecated Replaced by getMinimumSize() method.
+     */
+    @Deprecated
+    public boolean mouseDrag(Event evt, int x, int y) {
+        // to be overridden: do nothing,
+        // just return false to propagate event up to the parent container
+        return false;
+    }
+
+    /**
+     * Replaced by processMouseEvent(MouseEvent) method.
+     * 
+     * @param evt
+     *            the Event.
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     * @return true, if successful.
+     * @deprecated replaced by processMouseEvent(MouseEvent) method.
+     */
+    @Deprecated
+    public boolean mouseEnter(Event evt, int x, int y) {
+        // to be overridden: do nothing,
+        // just return false to propagate event up to the parent container
+        return false;
+    }
+
+    /**
+     * Replaced by processMouseEvent(MouseEvent) method.
+     * 
+     * @param evt
+     *            the Event.
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     * @return true, if successful.
+     * @deprecated Replaced by processMouseEvent(MouseEvent) method.
+     */
+    @Deprecated
+    public boolean mouseExit(Event evt, int x, int y) {
+        // to be overridden: do nothing,
+        // just return false to propagate event up to the parent container
+        return false;
+    }
+
+    /**
+     * Replaced by processMouseEvent(MouseEvent) method.
+     * 
+     * @param evt
+     *            the Event.
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     * @deprecated Replaced by processMouseEvent(MouseEvent) method.
+     * @return true, if successful.
+     */
+    @Deprecated
+    public boolean mouseMove(Event evt, int x, int y) {
+        // to be overridden: do nothing,
+        // just return false to propagate event up to the parent container
+        return false;
+    }
+
+    /**
+     * Replaced by processMouseEvent(MouseEvent) method.
+     * 
+     * @param evt
+     *            the Event.
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     * @return true, if successful.
+     * @deprecated Replaced by processMouseEvent(MouseEvent) method.
+     */
+    @Deprecated
+    public boolean mouseUp(Event evt, int x, int y) {
+        // to be overridden: do nothing,
+        // just return false to propagate event up to the parent container
+        return false;
+    }
+
+    /**
+     * Deprecated: replaced by setLocation(int, int) method.
+     * 
+     * @param x
+     *            the x coordinates.
+     * @param y
+     *            the y coordinates.
+     * @deprecated Replaced by setLocation(int, int) method.
+     */
+    @Deprecated
+    public void move(int x, int y) {
+        toolkit.lockAWT();
+        try {
+            boundsMaskParam = NativeWindow.BOUNDS_NOSIZE;
+            setBounds(x, y, w, h);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    // ???AWT
+    /*
+     * @Deprecated public void nextFocus() { toolkit.lockAWT(); try {
+     * transferFocus(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); } finally {
+     * toolkit.unlockAWT(); } }
+     */
+
+    /**
+     * Returns a string representation of the component's state.
+     * 
+     * @return the string representation of the component's state.
+     */
+    protected String paramString() {
+        /*
+         * The format is based on 1.5 release behavior which can be revealed by
+         * the following code: Component c = new Component(){};
+         * c.setVisible(false); System.out.println(c);
+         */
+        toolkit.lockAWT();
+        try {
+            return getName() + "," + getX() + "," + getY() + "," + getWidth() + "x" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+                    + getHeight() + (!isVisible() ? ",hidden" : ""); //$NON-NLS-1$ //$NON-NLS-2$
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    @Deprecated
+    @SuppressWarnings("deprecation")
+    public boolean postEvent(Event evt) {
+        boolean handled = handleEvent(evt);
+        if (handled) {
+            return true;
+        }
+        // ???AWT
+        /*
+         * // propagate non-handled events up to parent Component par = parent;
+         * // try to call postEvent only on components which // override any of
+         * deprecated method handlers // while (par != null &&
+         * !par.deprecatedEventHandler) { // par = par.parent; // } // translate
+         * event coordinates before posting it to parent if (par != null) {
+         * evt.translate(x, y); par.postEvent(evt); }
+         */
+        return false;
+    }
+
+    /**
+     * Prepares an image for rendering on the Component.
+     * 
+     * @param image
+     *            the Image to be prepared.
+     * @param observer
+     *            the ImageObserver object to be notified as soon as the image
+     *            is prepared.
+     * @return true if the image has been fully prepared, false otherwise.
+     */
+    public boolean prepareImage(Image image, ImageObserver observer) {
+        toolkit.lockAWT();
+        try {
+            return toolkit.prepareImage(image, -1, -1, observer);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Prepares an image for rendering on the Component with the specified
+     * width, height, and ImageObserver.
+     * 
+     * @param image
+     *            the Image to be prepared.
+     * @param width
+     *            the width of scaled image.
+     * @param height
+     *            the height of scaled height.
+     * @param observer
+     *            the ImageObserver object to be notified as soon as the image
+     *            is prepared.
+     * @return true if the image is been fully prepared, false otherwise.
+     */
+    public boolean prepareImage(Image image, int width, int height, ImageObserver observer) {
+        toolkit.lockAWT();
+        try {
+            return toolkit.prepareImage(image, width, height, observer);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Makes this Component undisplayable.
+     */
+    public void removeNotify() {
+        toolkit.lockAWT();
+        try {
+            // ???AWT
+            /*
+             * if (dropTarget != null) { dropTarget.removeNotify(peer); }
+             */
+            prepare4HierarchyChange();
+            // /???AWT: moveFocus();
+            behaviour.removeNotify();
+            // ???AWT: finishHierarchyChange(this, parent, 0);
+            removeNotifyInputContext();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Calls InputContext.removeNotify.
+     */
+    private void removeNotifyInputContext() {
+        if (!inputMethodsEnabled) {
+            return;
+        }
+        InputContext ic = getInputContext();
+        if (ic != null) {
+            // ???AWT: ic.removeNotify(this);
+        }
+    }
+
+    /**
+     * This method is called when some property of a component changes, making
+     * it unfocusable, e. g. hide(), removeNotify(), setEnabled(false),
+     * setFocusable(false) is called, and therefore automatic forward focus
+     * traversal is necessary
+     */
+    // ???AWT
+    /*
+     * void moveFocus() { // don't use transferFocus(), but query focus
+     * traversal policy directly // and if it returns null, transfer focus up
+     * cycle // and find next focusable component there KeyboardFocusManager kfm
+     * = KeyboardFocusManager.getCurrentKeyboardFocusManager(); Container root =
+     * kfm.getCurrentFocusCycleRoot(); Component nextComp = this; boolean
+     * success = !isFocusOwner(); while (!success) { if (root !=
+     * nextComp.getFocusCycleRootAncestor()) { // component was probably removed
+     * from container // so focus will be lost in some time return; } nextComp =
+     * root.getFocusTraversalPolicy().getComponentAfter(root, nextComp); if
+     * (nextComp == this) { nextComp = null; // avoid looping } if (nextComp !=
+     * null) { success = nextComp.requestFocusInWindow(); } else { nextComp =
+     * root; root = root.getFocusCycleRootAncestor(); // if no acceptable
+     * component is found at all - clear global // focus owner if (root == null)
+     * { if (nextComp instanceof Window) { Window wnd = (Window) nextComp;
+     * wnd.setFocusOwner(null); wnd.setRequestedFocus(null); }
+     * kfm.clearGlobalFocusOwner(); return; } } } }
+     */
+
+    /**
+     * For Container there's a difference between moving focus when being made
+     * invisible or made unfocusable in some other way, because when container
+     * is made invisible, component still remains visible, i. e. its hide() or
+     * setVisible() is not called.
+     */
+    void moveFocusOnHide() {
+        // ???AWT: moveFocus();
+    }
+
+    /**
+     * Removes the property change listener registered for this component.
+     * 
+     * @param listener
+     *            the PropertyChangeListener.
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        getPropertyChangeSupport().removePropertyChangeListener(listener);
+    }
+
+    /**
+     * Removes the property change listener registered fot this component for
+     * the specified propertyy.
+     * 
+     * @param propertyName
+     *            the property name.
+     * @param listener
+     *            the PropertyChangeListener.
+     */
+    public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+        getPropertyChangeSupport().removePropertyChangeListener(propertyName, listener);
+    }
+
+    /**
+     * Repaints the specified rectangle of this component within tm
+     * milliseconds.
+     * 
+     * @param tm
+     *            the time in milliseconds before updating.
+     * @param x
+     *            the x coordinate of Rectangle.
+     * @param y
+     *            the y coordinate of Rectangle.
+     * @param width
+     *            the width of Rectangle.
+     * @param height
+     *            the height of Rectangle.
+     */
+    public void repaint(long tm, int x, int y, int width, int height) {
+        // ???AWT
+        /*
+         * toolkit.lockAWT(); try { if (width <= 0 || height <= 0 ||
+         * (redrawManager == null) || !isShowing()) { return; } if (behaviour
+         * instanceof LWBehavior) { if (parent == null || !parent.visible ||
+         * !parent.behaviour.isDisplayable()) { return; } if (repaintRegion ==
+         * null) { repaintRegion = new MultiRectArea(new Rectangle(x, y, width,
+         * height)); } repaintRegion.intersect(new Rectangle(0, 0, this.w,
+         * this.h)); repaintRegion.translate(this.x, this.y);
+         * parent.repaintRegion = repaintRegion; repaintRegion = null;
+         * parent.repaint(tm, x + this.x, y + this.y, width, height); } else {
+         * if (repaintRegion != null) { redrawManager.addUpdateRegion(this,
+         * repaintRegion); repaintRegion = null; } else {
+         * redrawManager.addUpdateRegion(this, new Rectangle(x, y, width,
+         * height)); }
+         * toolkit.getSystemEventQueueCore().notifyEventMonitor(toolkit); } }
+         * finally { toolkit.unlockAWT(); }
+         */
+    }
+
+    /**
+     * Post event.
+     * 
+     * @param e
+     *            the e.
+     */
+    void postEvent(AWTEvent e) {
+        getToolkit().getSystemEventQueueImpl().postEvent(e);
+    }
+
+    /**
+     * Repaints the specified Rectangle of this Component.
+     * 
+     * @param x
+     *            the x coordinate of Rectangle.
+     * @param y
+     *            the y coordinate of Rectangle.
+     * @param width
+     *            the width of Rectangle.
+     * @param height
+     *            the height of Rectangle.
+     */
+    public void repaint(int x, int y, int width, int height) {
+        toolkit.lockAWT();
+        try {
+            repaint(0, x, y, width, height);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Repaints this component.
+     */
+    public void repaint() {
+        toolkit.lockAWT();
+        try {
+            if (w > 0 && h > 0) {
+                repaint(0, 0, 0, w, h);
+            }
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Repaints the component within tm milliseconds.
+     * 
+     * @param tm
+     *            the time in milliseconds before updating.
+     */
+    public void repaint(long tm) {
+        toolkit.lockAWT();
+        try {
+            repaint(tm, 0, 0, w, h);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Requests that this Component get the input focus temporarily. This
+     * component must be displayable, visible, and focusable.
+     * 
+     * @param temporary
+     *            this parameter is true if the focus change is temporary, when
+     *            the window loses the focus.
+     * @return true if the focus change request is succeeded, false otherwise.
+     */
+    protected boolean requestFocus(boolean temporary) {
+        toolkit.lockAWT();
+        try {
+            // ???AWT: return requestFocusImpl(temporary, true, false);
+        } finally {
+            toolkit.unlockAWT();
+        }
+        // ???AWT
+        return false;
+    }
+
+    /**
+     * Requests that this Component get the input focus. This component must be
+     * displayable, visible, and focusable.
+     */
+    public void requestFocus() {
+        toolkit.lockAWT();
+        try {
+            requestFocus(false);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    // ???AWT
+    /*
+     * protected boolean requestFocusInWindow(boolean temporary) {
+     * toolkit.lockAWT(); try { Window wnd = getWindowAncestor(); if ((wnd ==
+     * null) || !wnd.isFocused()) { return false; } return
+     * requestFocusImpl(temporary, false, false); } finally {
+     * toolkit.unlockAWT(); } } boolean requestFocusImpl(boolean temporary,
+     * boolean crossWindow, boolean rejectionRecovery) { if (!rejectionRecovery
+     * && isFocusOwner()) { return true; } Window wnd = getWindowAncestor();
+     * Container par = getRealParent(); if ((par != null) && par.isRemoved) {
+     * return false; } if (!isShowing() || !isFocusable() ||
+     * !wnd.isFocusableWindow()) { return false; } return
+     * KeyboardFocusManager.getCurrentKeyboardFocusManager().requestFocus(this,
+     * temporary, crossWindow, true); } public boolean requestFocusInWindow() {
+     * toolkit.lockAWT(); try { return requestFocusInWindow(false); } finally {
+     * toolkit.unlockAWT(); } }
+     */
+
+    /**
+     * Deprecated: replaced by setBounds(int, int, int, int) method.
+     * 
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     * @param w
+     *            the width.
+     * @param h
+     *            the height.
+     * @deprecated Replaced by setBounds(int, int, int, int) method.
+     */
+    @Deprecated
+    public void reshape(int x, int y, int w, int h) {
+        toolkit.lockAWT();
+        try {
+            setBounds(x, y, w, h, boundsMaskParam, true);
+            boundsMaskParam = 0;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets rectangle for this Component to be the rectangle with the specified
+     * x,y coordinates of the top-left corner and the width and height.
+     * 
+     * @param x
+     *            the x coordinate of the rectangle's top-left corner.
+     * @param y
+     *            the y coordinate of the rectangle's top-left corner.
+     * @param w
+     *            the width of rectangle.
+     * @param h
+     *            the height of rectangle.
+     */
+    public void setBounds(int x, int y, int w, int h) {
+        toolkit.lockAWT();
+        try {
+            reshape(x, y, w, h);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets rectangle for this Component to be the rectangle with the specified
+     * x,y coordinates of the top-left corner and the width and height and posts
+     * the appropriate events.
+     * 
+     * @param x
+     *            the x coordinate of the rectangle's top-left corner.
+     * @param y
+     *            the y coordinate of the rectangle's top-left corner.
+     * @param w
+     *            the width of rectangle.
+     * @param h
+     *            the height of rectangle.
+     * @param bMask
+     *            the bitmask of bounds options.
+     * @param updateBehavior
+     *            the whether to update the behavoir's bounds as well.
+     */
+    void setBounds(int x, int y, int w, int h, int bMask, boolean updateBehavior) {
+        int oldX = this.x;
+        int oldY = this.y;
+        int oldW = this.w;
+        int oldH = this.h;
+        setBoundsFields(x, y, w, h, bMask);
+        // Moved
+        if ((oldX != this.x) || (oldY != this.y)) {
+            // ???AWT: invalidateRealParent();
+            postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_MOVED));
+            spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_MOVED);
+        }
+        // Resized
+        if ((oldW != this.w) || (oldH != this.h)) {
+            invalidate();
+            postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED));
+            spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_RESIZED);
+        }
+        if (updateBehavior) {
+            behaviour.setBounds(this.x, this.y, this.w, this.h, bMask);
+        }
+        notifyInputMethod(new Rectangle(x, y, w, h));
+    }
+
+    /**
+     * Calls InputContextImpl.notifyClientWindowChanged.
+     * 
+     * @param bounds
+     *            the bounds.
+     */
+    void notifyInputMethod(Rectangle bounds) {
+        // only Window actually notifies IM of bounds change
+    }
+
+    /**
+     * Sets the bounds fields.
+     * 
+     * @param x
+     *            the x.
+     * @param y
+     *            the y.
+     * @param w
+     *            the w.
+     * @param h
+     *            the h.
+     * @param bMask
+     *            the b mask.
+     */
+    private void setBoundsFields(int x, int y, int w, int h, int bMask) {
+        if ((bMask & NativeWindow.BOUNDS_NOSIZE) == 0) {
+            this.w = w;
+            this.h = h;
+        }
+        if ((bMask & NativeWindow.BOUNDS_NOMOVE) == 0) {
+            this.x = x;
+            this.y = y;
+        }
+    }
+
+    /**
+     * Gets the native insets.
+     * 
+     * @return the native insets.
+     */
+    Insets getNativeInsets() {
+        return new Insets(0, 0, 0, 0);
+    }
+
+    /**
+     * Gets the insets.
+     * 
+     * @return the insets.
+     */
+    Insets getInsets() {
+        return new Insets(0, 0, 0, 0);
+    }
+
+    /**
+     * Checks if is mouse exited expected.
+     * 
+     * @return true, if is mouse exited expected.
+     */
+    boolean isMouseExitedExpected() {
+        return mouseExitedExpected;
+    }
+
+    /**
+     * Sets the mouse exited expected.
+     * 
+     * @param expected
+     *            the new mouse exited expected.
+     */
+    void setMouseExitedExpected(boolean expected) {
+        mouseExitedExpected = expected;
+    }
+
+    /**
+     * Sets the new bounding rectangle for this Component.
+     * 
+     * @param r
+     *            the new bounding rectangle.
+     */
+    public void setBounds(Rectangle r) {
+        toolkit.lockAWT();
+        try {
+            setBounds(r.x, r.y, r.width, r.height);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the component orientation which affects the component's elements and
+     * text within this component.
+     * 
+     * @param o
+     *            the ComponentOrientation object.
+     */
+    public void setComponentOrientation(ComponentOrientation o) {
+        ComponentOrientation oldOrientation;
+        toolkit.lockAWT();
+        try {
+            oldOrientation = orientation;
+            orientation = o;
+        } finally {
+            toolkit.unlockAWT();
+        }
+        firePropertyChange("componentOrientation", oldOrientation, orientation); //$NON-NLS-1$
+        invalidate();
+    }
+
+    /**
+     * Sets the specified cursor for this Component.
+     * 
+     * @param cursor
+     *            the new Cursor.
+     */
+    public void setCursor(Cursor cursor) {
+        toolkit.lockAWT();
+        try {
+            this.cursor = cursor;
+            setCursor();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Set current cursor shape to Component's Cursor.
+     */
+    void setCursor() {
+        if (isDisplayable() && isShowing()) {
+            Rectangle absRect = new Rectangle(getLocationOnScreen(), getSize());
+            Point absPointerPos = toolkit.dispatcher.mouseDispatcher.getPointerPos();
+            // ???AWT
+            /*
+             * if (absRect.contains(absPointerPos)) { // set Cursor only on
+             * top-level Windows(on X11) Window topLevelWnd =
+             * getWindowAncestor(); if (topLevelWnd != null) { Point pointerPos
+             * = MouseDispatcher.convertPoint(null, absPointerPos, topLevelWnd);
+             * Component compUnderCursor =
+             * topLevelWnd.findComponentAt(pointerPos); // if (compUnderCursor
+             * == this || // compUnderCursor.getCursorAncestor() == this) {
+             * NativeWindow wnd = topLevelWnd.getNativeWindow(); if
+             * (compUnderCursor != null && wnd != null) {
+             * compUnderCursor.getRealCursor().getNativeCursor()
+             * .setCursor(wnd.getId()); } // } } }
+             */
+        }
+    }
+
+    /**
+     * Gets the ancestor Cursor if Component is disabled (directly or via an
+     * ancestor) even if Cursor is explicitly set.
+     * 
+     * @param value
+     *            the value.
+     * @return the actual Cursor to be displayed.
+     */
+    // ???AWT
+    /*
+     * Cursor getRealCursor() { Component cursorAncestor = getCursorAncestor();
+     * return cursorAncestor != null ? cursorAncestor.getCursor() :
+     * Cursor.getDefaultCursor(); }
+     */
+
+    /**
+     * Gets the ancestor(or component itself) whose cursor is set when pointer
+     * is inside component
+     * 
+     * @return the actual Cursor to be displayed.
+     */
+    // ???AWT
+    /*
+     * Component getCursorAncestor() { Component comp; for (comp = this; comp !=
+     * null; comp = comp.getParent()) { if (comp instanceof Window ||
+     * comp.isCursorSet() && comp.isKeyEnabled()) { return comp; } } return
+     * null; } public void setDropTarget(DropTarget dt) { toolkit.lockAWT(); try
+     * { if (dropTarget == dt) { return; } DropTarget oldDropTarget =
+     * dropTarget; dropTarget = dt; if (oldDropTarget != null) { if
+     * (behaviour.isDisplayable()) { oldDropTarget.removeNotify(peer); }
+     * oldDropTarget.setComponent(null); } if (dt != null) {
+     * dt.setComponent(this); if (behaviour.isDisplayable()) {
+     * dt.addNotify(peer); } } } finally { toolkit.unlockAWT(); } }
+     */
+
+    /**
+     * Sets this component to the "enabled" or "disabled" state depending on the
+     * specified boolean parameter.
+     * 
+     * @param value
+     *            true if this component should be enabled; false if this
+     *            component should be disabled.
+     */
+    public void setEnabled(boolean value) {
+        toolkit.lockAWT();
+        try {
+            enable(value);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the enabled impl.
+     * 
+     * @param value
+     *            the new enabled impl.
+     */
+    void setEnabledImpl(boolean value) {
+        if (enabled != value) {
+            enabled = value;
+            setCursor();
+            if (!enabled) {
+                moveFocusOnHide();
+            }
+            behaviour.setEnabled(value);
+        }
+    }
+
+    // ???AWT
+    /*
+     * private void fireAccessibleStateChange(AccessibleState state, boolean
+     * value) { if (behaviour.isLightweight()) { return; } AccessibleContext ac
+     * = getAccessibleContext(); if (ac != null) { AccessibleState oldValue =
+     * null; AccessibleState newValue = null; if (value) { newValue = state; }
+     * else { oldValue = state; }
+     * ac.firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
+     * oldValue, newValue); } }
+     */
+
+    // ???AWT
+    /*
+     * public void setFocusTraversalKeys(int id, Set<? extends AWTKeyStroke>
+     * keystrokes) { Set<? extends AWTKeyStroke> oldTraversalKeys; String
+     * propName = "FocusTraversalKeys"; //$NON-NLS-1$ toolkit.lockAWT(); try {
+     * Integer kId = new Integer(id);
+     * KeyboardFocusManager.checkTraversalKeysID(traversalKeys, kId);
+     * Map<Integer, Set<? extends AWTKeyStroke>> keys = new HashMap<Integer,
+     * Set<? extends AWTKeyStroke>>(); for (int kid : traversalIDs) { Integer
+     * key = new Integer(kid); keys.put(key, getFocusTraversalKeys(kid)); }
+     * KeyboardFocusManager.checkKeyStrokes(traversalIDs, keys, kId,
+     * keystrokes); oldTraversalKeys = traversalKeys.get(new Integer(id)); //
+     * put a copy of keystrokes object into map: Set<? extends AWTKeyStroke>
+     * newKeys = keystrokes; if (keystrokes != null) { newKeys = new
+     * HashSet<AWTKeyStroke>(keystrokes); } traversalKeys.put(kId, newKeys);
+     * String direction = ""; //$NON-NLS-1$ switch (id) { case
+     * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: direction = "forward";
+     * //$NON-NLS-1$ break; case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS:
+     * direction = "backward"; //$NON-NLS-1$ break; case
+     * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: direction = "upCycle";
+     * //$NON-NLS-1$ break; case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS:
+     * direction = "downCycle"; //$NON-NLS-1$ break; } propName = direction +
+     * propName; } finally { toolkit.unlockAWT(); } firePropertyChange(propName,
+     * oldTraversalKeys, keystrokes); }
+     */
+
+    /**
+     * Sets the focus traversal keys state for this component.
+     * 
+     * @param value
+     *            true if the focus traversal keys state is enabled, false if
+     *            the focus traversal keys state is disabled.
+     */
+    public void setFocusTraversalKeysEnabled(boolean value) {
+        boolean oldFocusTraversalKeysEnabled;
+        toolkit.lockAWT();
+        try {
+            oldFocusTraversalKeysEnabled = focusTraversalKeysEnabled;
+            focusTraversalKeysEnabled = value;
+        } finally {
+            toolkit.unlockAWT();
+        }
+        firePropertyChange("focusTraversalKeysEnabled", oldFocusTraversalKeysEnabled, //$NON-NLS-1$
+                focusTraversalKeysEnabled);
+    }
+
+    // ???AWT
+    /*
+     * public void setFocusable(boolean focusable) { boolean oldFocusable;
+     * toolkit.lockAWT(); try { calledSetFocusable = true; oldFocusable =
+     * this.focusable; this.focusable = focusable; if (!focusable) {
+     * moveFocus(); } } finally { toolkit.unlockAWT(); }
+     * firePropertyChange("focusable", oldFocusable, focusable); //$NON-NLS-1$ }
+     * public Font getFont() { toolkit.lockAWT(); try { return (font == null) &&
+     * (parent != null) ? parent.getFont() : font; } finally {
+     * toolkit.unlockAWT(); } }
+     */
+
+    /**
+     * Sets the font for this Component.
+     * 
+     * @param f
+     *            the new font of the Component.
+     */
+    public void setFont(Font f) {
+        Font oldFont;
+        toolkit.lockAWT();
+        try {
+            oldFont = font;
+            setFontImpl(f);
+        } finally {
+            toolkit.unlockAWT();
+        }
+        firePropertyChange("font", oldFont, font); //$NON-NLS-1$
+    }
+
+    /**
+     * Sets the font impl.
+     * 
+     * @param f
+     *            the new font impl.
+     */
+    void setFontImpl(Font f) {
+        font = f;
+        invalidate();
+        if (isShowing()) {
+            repaint();
+        }
+    }
+
+    /**
+     * Invalidate the component if it inherits the font from the parent. This
+     * method is overridden in Container.
+     * 
+     * @return true if the component was invalidated, false otherwise.
+     */
+    boolean propagateFont() {
+        if (font == null) {
+            invalidate();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Sets the foreground color for this Component.
+     * 
+     * @param c
+     *            the new foreground color.
+     */
+    public void setForeground(Color c) {
+        Color oldFgColor;
+        toolkit.lockAWT();
+        try {
+            oldFgColor = foreColor;
+            foreColor = c;
+        } finally {
+            toolkit.unlockAWT();
+        }
+        firePropertyChange("foreground", oldFgColor, foreColor); //$NON-NLS-1$
+        repaint();
+    }
+
+    /**
+     * Sets the background color for the Component.
+     * 
+     * @param c
+     *            the new background color for this component.
+     */
+    public void setBackground(Color c) {
+        Color oldBkColor;
+        toolkit.lockAWT();
+        try {
+            oldBkColor = backColor;
+            backColor = c;
+        } finally {
+            toolkit.unlockAWT();
+        }
+        firePropertyChange("background", oldBkColor, backColor); //$NON-NLS-1$
+        repaint();
+    }
+
+    /**
+     * Sets the flag for whether paint messages received from the operating
+     * system should be ignored or not.
+     * 
+     * @param value
+     *            true if paint messages received from the operating system
+     *            should be ignored, false otherwise.
+     */
+    public void setIgnoreRepaint(boolean value) {
+        toolkit.lockAWT();
+        try {
+            ignoreRepaint = value;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the locale of the component.
+     * 
+     * @param locale
+     *            the new Locale.
+     */
+    public void setLocale(Locale locale) {
+        Locale oldLocale;
+        toolkit.lockAWT();
+        try {
+            oldLocale = this.locale;
+            this.locale = locale;
+        } finally {
+            toolkit.unlockAWT();
+        }
+        firePropertyChange("locale", oldLocale, locale); //$NON-NLS-1$
+    }
+
+    /**
+     * Sets the location of the Component to the specified point.
+     * 
+     * @param p
+     *            the new location of the Component.
+     */
+    public void setLocation(Point p) {
+        toolkit.lockAWT();
+        try {
+            setLocation(p.x, p.y);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the location of the Component to the specified x, y coordinates.
+     * 
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     */
+    public void setLocation(int x, int y) {
+        toolkit.lockAWT();
+        try {
+            move(x, y);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the visibility state of the component.
+     * 
+     * @param b
+     *            true if the component is visible, false if the component is
+     *            not shown.
+     */
+    public void setVisible(boolean b) {
+        // show() & hide() are not deprecated for Window,
+        // so have to call them from setVisible()
+        show(b);
+    }
+
+    /**
+     * Deprecated: replaced by setVisible(boolean) method.
+     * 
+     * @deprecated Replaced by setVisible(boolean) method.
+     */
+    @Deprecated
+    public void show() {
+        toolkit.lockAWT();
+        try {
+            if (visible) {
+                return;
+            }
+            prepare4HierarchyChange();
+            mapToDisplay(true);
+            validate();
+            visible = true;
+            behaviour.setVisible(true);
+            postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_SHOWN));
+            // ???AWT: finishHierarchyChange(this, parent, 0);
+            notifyInputMethod(new Rectangle(x, y, w, h));
+            // ???AWT: invalidateRealParent();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Deprecated: replaced by setVisible(boolean) method.
+     * 
+     * @param b
+     *            the visibility's state.
+     * @deprecated Replaced by setVisible(boolean) method.
+     */
+    @Deprecated
+    public void show(boolean b) {
+        if (b) {
+            show();
+        } else {
+            hide();
+        }
+    }
+
+    // ???AWT
+    /*
+     * void transferFocus(int dir) { Container root = null; if (this instanceof
+     * Container) { Container cont = (Container) this; if
+     * (cont.isFocusCycleRoot()) { root = cont.getFocusTraversalRoot(); } } if
+     * (root == null) { root = getFocusCycleRootAncestor(); } // transfer focus
+     * up cycle if root is unreachable Component comp = this; while ((root !=
+     * null) && !(root.isFocusCycleRoot() && root.isShowing() &&
+     * root.isEnabled() && root .isFocusable())) { comp = root; root =
+     * root.getFocusCycleRootAncestor(); } if (root == null) { return; }
+     * FocusTraversalPolicy policy = root.getFocusTraversalPolicy(); Component
+     * nextComp = null; switch (dir) { case
+     * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: nextComp =
+     * policy.getComponentAfter(root, comp); break; case
+     * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: nextComp =
+     * policy.getComponentBefore(root, comp); break; } if (nextComp != null) {
+     * nextComp.requestFocus(false); } } public void transferFocus() {
+     * toolkit.lockAWT(); try { nextFocus(); } finally { toolkit.unlockAWT(); }
+     * } public void transferFocusBackward() { toolkit.lockAWT(); try {
+     * transferFocus(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); } finally {
+     * toolkit.unlockAWT(); } } public void transferFocusUpCycle() {
+     * toolkit.lockAWT(); try { KeyboardFocusManager kfm =
+     * KeyboardFocusManager.getCurrentKeyboardFocusManager(); Container root =
+     * kfm.getCurrentFocusCycleRoot(); if(root == null) { return; } boolean
+     * success = false; Component nextComp = null; Container newRoot = root; do
+     * { nextComp = newRoot instanceof Window ?
+     * newRoot.getFocusTraversalPolicy() .getDefaultComponent(newRoot) :
+     * newRoot; newRoot = newRoot.getFocusCycleRootAncestor(); if (nextComp ==
+     * null) { break; } success = nextComp.requestFocusInWindow(); if (newRoot
+     * == null) { break; } kfm.setGlobalCurrentFocusCycleRoot(newRoot); } while
+     * (!success); if (!success && root != newRoot) {
+     * kfm.setGlobalCurrentFocusCycleRoot(root); } } finally {
+     * toolkit.unlockAWT(); } }
+     */
+
+    /**
+     * Validates that this component has a valid layout.
+     */
+    public void validate() {
+        toolkit.lockAWT();
+        try {
+            if (!behaviour.isDisplayable()) {
+                return;
+            }
+            validateImpl();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Validate impl.
+     */
+    void validateImpl() {
+        valid = true;
+    }
+
+    /**
+     * Gets the native window.
+     * 
+     * @return the native window.
+     */
+    NativeWindow getNativeWindow() {
+        return behaviour.getNativeWindow();
+    }
+
+    /**
+     * Checks whether or not a maximum size is set for the Component.
+     * 
+     * @return true, if the maximum size is set for the Component, false
+     *         otherwise.
+     */
+    public boolean isMaximumSizeSet() {
+        toolkit.lockAWT();
+        try {
+            return maximumSize != null;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks whether or not the minimum size is set for the component.
+     * 
+     * @return true, if the minimum size is set for the component, false
+     *         otherwise.
+     */
+    public boolean isMinimumSizeSet() {
+        toolkit.lockAWT();
+        try {
+            return minimumSize != null;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks whether or not the preferred size is set for the Component.
+     * 
+     * @return true, if the preferred size is set for the Component, false
+     *         otherwise.
+     */
+    public boolean isPreferredSizeSet() {
+        toolkit.lockAWT();
+        try {
+            return preferredSize != null;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the maximum size of the Component.
+     * 
+     * @return the maximum size of the Component.
+     */
+    public Dimension getMaximumSize() {
+        toolkit.lockAWT();
+        try {
+            return isMaximumSizeSet() ? new Dimension(maximumSize) : new Dimension(Short.MAX_VALUE,
+                    Short.MAX_VALUE);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the minimum size of the Component.
+     * 
+     * @return the minimum size of the Component.
+     */
+    public Dimension getMinimumSize() {
+        toolkit.lockAWT();
+        try {
+            return minimumSize();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Deprecated: replaced by getMinimumSize() method.
+     * 
+     * @return the Dimension.
+     * @deprecated Replaced by getMinimumSize() method.
+     */
+    @Deprecated
+    public Dimension minimumSize() {
+        toolkit.lockAWT();
+        try {
+            if (isMinimumSizeSet()) {
+                return (Dimension)minimumSize.clone();
+            }
+            Dimension defSize = getDefaultMinimumSize();
+            if (defSize != null) {
+                return (Dimension)defSize.clone();
+            }
+            return isDisplayable() ? new Dimension(1, 1) : new Dimension(w, h);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the preferred size of the Component.
+     * 
+     * @return the preferred size of the Component.
+     */
+    public Dimension getPreferredSize() {
+        toolkit.lockAWT();
+        try {
+            return preferredSize();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Deprecated: replaced by getPreferredSize() method.
+     * 
+     * @return the Dimension.
+     * @deprecated Replaced by getPreferredSize() method.
+     */
+    @Deprecated
+    public Dimension preferredSize() {
+        toolkit.lockAWT();
+        try {
+            if (isPreferredSizeSet()) {
+                return new Dimension(preferredSize);
+            }
+            Dimension defSize = getDefaultPreferredSize();
+            if (defSize != null) {
+                return new Dimension(defSize);
+            }
+            return new Dimension(getMinimumSize());
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the maximum size of the Component.
+     * 
+     * @param maximumSize
+     *            the new maximum size of the Component.
+     */
+    public void setMaximumSize(Dimension maximumSize) {
+        Dimension oldMaximumSize;
+        toolkit.lockAWT();
+        try {
+            oldMaximumSize = this.maximumSize;
+            if (oldMaximumSize != null) {
+                oldMaximumSize = oldMaximumSize.getSize();
+            }
+            if (this.maximumSize == null) {
+                if (maximumSize != null) {
+                    this.maximumSize = new Dimension(maximumSize);
+                }
+            } else {
+                if (maximumSize != null) {
+                    this.maximumSize.setSize(maximumSize);
+                } else {
+                    this.maximumSize = null;
+                }
+            }
+        } finally {
+            toolkit.unlockAWT();
+        }
+        firePropertyChange("maximumSize", oldMaximumSize, this.maximumSize); //$NON-NLS-1$
+        toolkit.lockAWT();
+        try {
+            // ???AWT: invalidateRealParent();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the minimum size of the Component.
+     * 
+     * @param minimumSize
+     *            the new minimum size of the Component.
+     */
+    public void setMinimumSize(Dimension minimumSize) {
+        Dimension oldMinimumSize;
+        toolkit.lockAWT();
+        try {
+            oldMinimumSize = this.minimumSize;
+            if (oldMinimumSize != null) {
+                oldMinimumSize = oldMinimumSize.getSize();
+            }
+            if (this.minimumSize == null) {
+                if (minimumSize != null) {
+                    this.minimumSize = new Dimension(minimumSize);
+                }
+            } else {
+                if (minimumSize != null) {
+                    this.minimumSize.setSize(minimumSize);
+                } else {
+                    this.minimumSize = null;
+                }
+            }
+        } finally {
+            toolkit.unlockAWT();
+        }
+        firePropertyChange("minimumSize", oldMinimumSize, this.minimumSize); //$NON-NLS-1$
+        toolkit.lockAWT();
+        try {
+            // ???AWT: invalidateRealParent();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the preferred size of the Component.
+     * 
+     * @param preferredSize
+     *            the new preferred size of the Component.
+     */
+    public void setPreferredSize(Dimension preferredSize) {
+        Dimension oldPreferredSize;
+        toolkit.lockAWT();
+        try {
+            oldPreferredSize = this.preferredSize;
+            if (oldPreferredSize != null) {
+                oldPreferredSize = oldPreferredSize.getSize();
+            }
+            if (this.preferredSize == null) {
+                if (preferredSize != null) {
+                    this.preferredSize = new Dimension(preferredSize);
+                }
+            } else {
+                if (preferredSize != null) {
+                    this.preferredSize.setSize(preferredSize);
+                } else {
+                    this.preferredSize = null;
+                }
+            }
+        } finally {
+            toolkit.unlockAWT();
+        }
+        firePropertyChange("preferredSize", oldPreferredSize, this.preferredSize); //$NON-NLS-1$
+        toolkit.lockAWT();
+        try {
+            // ???AWT: invalidateRealParent();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    // ???AWT
+    /*
+     * RedrawManager getRedrawManager() { if (parent == null) { return null; }
+     * return parent.getRedrawManager(); }
+     */
+
+    /**
+     * Checks if is focusability explicitly set.
+     * 
+     * @return true if component has a focusable peer.
+     */
+    // ???AWT
+    /*
+     * boolean isPeerFocusable() { // The recommendations for Windows and Unix
+     * are that // Canvases, Labels, Panels, Scrollbars, ScrollPanes, Windows,
+     * // and lightweight Components have non-focusable peers, // and all other
+     * Components have focusable peers. if (this instanceof Canvas || this
+     * instanceof Label || this instanceof Panel || this instanceof Scrollbar ||
+     * this instanceof ScrollPane || this instanceof Window || isLightweight())
+     * { return false; } return true; }
+     */
+
+    /**
+     * @return true if focusability was explicitly set via a call to
+     *         setFocusable() or via overriding isFocusable() or
+     *         isFocusTraversable().
+     */
+    boolean isFocusabilityExplicitlySet() {
+        return calledSetFocusable || overridenIsFocusable;
+    }
+
+    /**
+     * Paints the component and all of its subcomponents.
+     * 
+     * @param g
+     *            the Graphics to be used for painting.
+     */
+    public void paintAll(Graphics g) {
+        toolkit.lockAWT();
+        try {
+            paint(g);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Updates this Component.
+     * 
+     * @param g
+     *            the Graphics to be used for updating.
+     */
+    public void update(Graphics g) {
+        toolkit.lockAWT();
+        try {
+            if (!isLightweight() && !isPrepainter()) {
+                g.setColor(getBackground());
+                g.fillRect(0, 0, w, h);
+                g.setColor(getForeground());
+            }
+            paint(g);
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Paints this component.
+     * 
+     * @param g
+     *            the Graphics to be used for painting.
+     */
+    public void paint(Graphics g) {
+        toolkit.lockAWT();
+        try {
+            // Just to nothing
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Prepares the component to be painted.
+     * 
+     * @param g
+     *            the Graphics to be used for painting.
+     */
+    void prepaint(Graphics g) {
+        // Just to nothing. For overriding.
+    }
+
+    /**
+     * Checks if is prepainter.
+     * 
+     * @return true, if is prepainter.
+     */
+    boolean isPrepainter() {
+        return false;
+    }
+
+    /**
+     * Prepare4 hierarchy change.
+     */
+    void prepare4HierarchyChange() {
+        if (hierarchyChangingCounter++ == 0) {
+            wasShowing = isShowing();
+            wasDisplayable = isDisplayable();
+            prepareChildren4HierarchyChange();
+        }
+    }
+
+    /**
+     * Prepare children4 hierarchy change.
+     */
+    void prepareChildren4HierarchyChange() {
+        // To be inherited by Container
+    }
+
+    // ???AWT
+    /*
+     * void finishHierarchyChange(Component changed, Container changedParent,
+     * int ancestorFlags) { if (--hierarchyChangingCounter == 0) { int
+     * changeFlags = ancestorFlags; if (wasShowing != isShowing()) { changeFlags
+     * |= HierarchyEvent.SHOWING_CHANGED; } if (wasDisplayable !=
+     * isDisplayable()) { changeFlags |= HierarchyEvent.DISPLAYABILITY_CHANGED;
+     * } if (changeFlags > 0) { postEvent(new HierarchyEvent(this,
+     * HierarchyEvent.HIERARCHY_CHANGED, changed, changedParent, changeFlags));
+     * } finishChildrenHierarchyChange(changed, changedParent, ancestorFlags); }
+     * } void finishChildrenHierarchyChange(Component changed, Container
+     * changedParent, int ancestorFlags) { // To be inherited by Container }
+     * void postHierarchyBoundsEvents(Component changed, int id) { postEvent(new
+     * HierarchyEvent(this, id, changed, null, 0)); }
+     */
+
+    /**
+     * Spread hierarchy bounds events.
+     * 
+     * @param changed
+     *            the changed.
+     * @param id
+     *            the id.
+     */
+    void spreadHierarchyBoundsEvents(Component changed, int id) {
+        // To be inherited by Container
+    }
+
+    /**
+     * Dispatches an event to this component.
+     * 
+     * @param e
+     *            the Event.
+     */
+    public final void dispatchEvent(AWTEvent e) {
+        // ???AWT
+        /*
+         * if (e.isConsumed()) { return; } if (e instanceof PaintEvent) {
+         * toolkit.dispatchAWTEvent(e); processPaintEvent((PaintEvent) e);
+         * return; } KeyboardFocusManager kfm =
+         * KeyboardFocusManager.getCurrentKeyboardFocusManager(); if
+         * (!e.dispatchedByKFM && kfm.dispatchEvent(e)) { return; } if (e
+         * instanceof KeyEvent) { KeyEvent ke = (KeyEvent) e; // consumes
+         * KeyEvent which represents a focus traversal key if
+         * (getFocusTraversalKeysEnabled()) { kfm.processKeyEvent(this, ke); if
+         * (ke.isConsumed()) { return; } } } if (inputMethodsEnabled &&
+         * dispatchToIM && e.isPosted && dispatchEventToIM(e)) { return; } if
+         * (e.getID() == WindowEvent.WINDOW_ICONIFIED) {
+         * notifyInputMethod(null); } AWTEvent.EventDescriptor descriptor =
+         * toolkit.eventTypeLookup.getEventDescriptor(e);
+         * toolkit.dispatchAWTEvent(e); if (descriptor != null) { if
+         * (isEventEnabled(descriptor.eventMask) ||
+         * (getListeners(descriptor.listenerType).length > 0)) {
+         * processEvent(e); } // input events can be consumed by user listeners:
+         * if (!e.isConsumed() && ((enabledAWTEvents & descriptor.eventMask) !=
+         * 0)) { postprocessEvent(e, descriptor.eventMask); } }
+         * postDeprecatedEvent(e);
+         */
+    }
+
+    /**
+     * Post deprecated event.
+     * 
+     * @param e
+     *            the e.
+     */
+    private void postDeprecatedEvent(AWTEvent e) {
+        if (deprecatedEventHandler) {
+            Event evt = e.getEvent();
+            if (evt != null) {
+                postEvent(evt);
+            }
+        }
+    }
+
+    /**
+     * Postprocess event.
+     * 
+     * @param e
+     *            the e.
+     * @param eventMask
+     *            the event mask.
+     */
+    void postprocessEvent(AWTEvent e, long eventMask) {
+        toolkit.lockAWT();
+        try {
+            // call system listeners under AWT lock
+            if (eventMask == AWTEvent.FOCUS_EVENT_MASK) {
+                preprocessFocusEvent((FocusEvent)e);
+            } else if (eventMask == AWTEvent.KEY_EVENT_MASK) {
+                preprocessKeyEvent((KeyEvent)e);
+            } else if (eventMask == AWTEvent.MOUSE_EVENT_MASK) {
+                preprocessMouseEvent((MouseEvent)e);
+            } else if (eventMask == AWTEvent.MOUSE_MOTION_EVENT_MASK) {
+                preprocessMouseMotionEvent((MouseEvent)e);
+            } else if (eventMask == AWTEvent.COMPONENT_EVENT_MASK) {
+                preprocessComponentEvent((ComponentEvent)e);
+            } else if (eventMask == AWTEvent.MOUSE_WHEEL_EVENT_MASK) {
+                preprocessMouseWheelEvent((MouseWheelEvent)e);
+            } else if (eventMask == AWTEvent.INPUT_METHOD_EVENT_MASK) {
+                preprocessInputMethodEvent((InputMethodEvent)e);
+            }
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Preprocess input method event.
+     * 
+     * @param e
+     *            the e.
+     */
+    private void preprocessInputMethodEvent(InputMethodEvent e) {
+        processInputMethodEventImpl(e, inputMethodListeners.getSystemListeners());
+    }
+
+    /**
+     * Preprocess mouse wheel event.
+     * 
+     * @param e
+     *            the e.
+     */
+    private void preprocessMouseWheelEvent(MouseWheelEvent e) {
+        processMouseWheelEventImpl(e, mouseWheelListeners.getSystemListeners());
+    }
+
+    /**
+     * Process mouse wheel event impl.
+     * 
+     * @param e
+     *            the e.
+     * @param c
+     *            the c.
+     */
+    private void processMouseWheelEventImpl(MouseWheelEvent e, Collection<MouseWheelListener> c) {
+        for (MouseWheelListener listener : c) {
+            switch (e.getID()) {
+                case MouseEvent.MOUSE_WHEEL:
+                    listener.mouseWheelMoved(e);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Preprocess component event.
+     * 
+     * @param e
+     *            the e.
+     */
+    private void preprocessComponentEvent(ComponentEvent e) {
+        processComponentEventImpl(e, componentListeners.getSystemListeners());
+    }
+
+    /**
+     * Preprocess mouse motion event.
+     * 
+     * @param e
+     *            the e.
+     */
+    void preprocessMouseMotionEvent(MouseEvent e) {
+        processMouseMotionEventImpl(e, mouseMotionListeners.getSystemListeners());
+    }
+
+    /**
+     * Preprocess mouse event.
+     * 
+     * @param e
+     *            the e
+     */
+    void preprocessMouseEvent(MouseEvent e) {
+        processMouseEventImpl(e, mouseListeners.getSystemListeners());
+    }
+
+    /**
+     * Preprocess key event.
+     * 
+     * @param e
+     *            the e.
+     */
+    void preprocessKeyEvent(KeyEvent e) {
+        processKeyEventImpl(e, keyListeners.getSystemListeners());
+    }
+
+    /**
+     * Preprocess focus event.
+     * 
+     * @param e
+     *            the e.
+     */
+    void preprocessFocusEvent(FocusEvent e) {
+        processFocusEventImpl(e, focusListeners.getSystemListeners());
+    }
+
+    /**
+     * Processes AWTEvent occurred on this component.
+     * 
+     * @param e
+     *            the AWTEvent.
+     */
+    protected void processEvent(AWTEvent e) {
+        long eventMask = toolkit.eventTypeLookup.getEventMask(e);
+        if (eventMask == AWTEvent.COMPONENT_EVENT_MASK) {
+            processComponentEvent((ComponentEvent)e);
+        } else if (eventMask == AWTEvent.FOCUS_EVENT_MASK) {
+            processFocusEvent((FocusEvent)e);
+        } else if (eventMask == AWTEvent.KEY_EVENT_MASK) {
+            processKeyEvent((KeyEvent)e);
+        } else if (eventMask == AWTEvent.MOUSE_EVENT_MASK) {
+            processMouseEvent((MouseEvent)e);
+        } else if (eventMask == AWTEvent.MOUSE_WHEEL_EVENT_MASK) {
+            processMouseWheelEvent((MouseWheelEvent)e);
+        } else if (eventMask == AWTEvent.MOUSE_MOTION_EVENT_MASK) {
+            processMouseMotionEvent((MouseEvent)e);
+        } else if (eventMask == AWTEvent.HIERARCHY_EVENT_MASK) {
+            processHierarchyEvent((HierarchyEvent)e);
+        } else if (eventMask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) {
+            processHierarchyBoundsEvent((HierarchyEvent)e);
+        } else if (eventMask == AWTEvent.INPUT_METHOD_EVENT_MASK) {
+            processInputMethodEvent((InputMethodEvent)e);
+        }
+    }
+
+    /**
+     * Gets an array of all listener's objects based on the specified listener
+     * type and registered to this Component.
+     * 
+     * @param listenerType
+     *            the listener type.
+     * @return an array of all listener's objects based on the specified
+     *         listener type and registered to this Component.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
+        if (ComponentListener.class.isAssignableFrom(listenerType)) {
+            return (T[])getComponentListeners();
+        } else if (FocusListener.class.isAssignableFrom(listenerType)) {
+            return (T[])getFocusListeners();
+        } else if (HierarchyBoundsListener.class.isAssignableFrom(listenerType)) {
+            return (T[])getHierarchyBoundsListeners();
+        } else if (HierarchyListener.class.isAssignableFrom(listenerType)) {
+            return (T[])getHierarchyListeners();
+        } else if (InputMethodListener.class.isAssignableFrom(listenerType)) {
+            return (T[])getInputMethodListeners();
+        } else if (KeyListener.class.isAssignableFrom(listenerType)) {
+            return (T[])getKeyListeners();
+        } else if (MouseWheelListener.class.isAssignableFrom(listenerType)) {
+            return (T[])getMouseWheelListeners();
+        } else if (MouseMotionListener.class.isAssignableFrom(listenerType)) {
+            return (T[])getMouseMotionListeners();
+        } else if (MouseListener.class.isAssignableFrom(listenerType)) {
+            return (T[])getMouseListeners();
+        } else if (PropertyChangeListener.class.isAssignableFrom(listenerType)) {
+            return (T[])getPropertyChangeListeners();
+        }
+        return (T[])Array.newInstance(listenerType, 0);
+    }
+
+    /**
+     * Process paint event.
+     * 
+     * @param event
+     *            the event.
+     */
+    private void processPaintEvent(PaintEvent event) {
+        if (redrawManager == null) {
+            return;
+        }
+        Rectangle clipRect = event.getUpdateRect();
+        if ((clipRect.width <= 0) || (clipRect.height <= 0)) {
+            return;
+        }
+        Graphics g = getGraphics();
+        if (g == null) {
+            return;
+        }
+        initGraphics(g, event);
+        if (!getIgnoreRepaint()) {
+            if (event.getID() == PaintEvent.PAINT) {
+                paint(g);
+            } else {
+                update(g);
+            }
+        }
+        g.dispose();
+    }
+
+    /**
+     * Inits the graphics.
+     * 
+     * @param g
+     *            the g.
+     * @param e
+     *            the e.
+     */
+    void initGraphics(Graphics g, PaintEvent e) {
+        Rectangle clip = e.getUpdateRect();
+        if (clip instanceof ClipRegion) {
+            g.setClip(((ClipRegion)clip).getClip());
+        } else {
+            g.setClip(clip);
+        }
+        if (isPrepainter()) {
+            prepaint(g);
+        } else if (!isLightweight() && (e.getID() == PaintEvent.PAINT)) {
+            g.setColor(getBackground());
+            g.fillRect(0, 0, w, h);
+        }
+        g.setFont(getFont());
+        g.setColor(getForeground());
+    }
+
+    /**
+     * Enables the events with the specified event mask to be delivered to this
+     * component.
+     * 
+     * @param eventsToEnable
+     *            the events mask which specifies the types of events to enable.
+     */
+    protected final void enableEvents(long eventsToEnable) {
+        toolkit.lockAWT();
+        try {
+            enabledEvents |= eventsToEnable;
+            deprecatedEventHandler = false;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Enable awt events.
+     * 
+     * @param eventsToEnable
+     *            the events to enable.
+     */
+    private void enableAWTEvents(long eventsToEnable) {
+        enabledAWTEvents |= eventsToEnable;
+    }
+
+    /**
+     * Disables the events with types specified by the specified event mask from
+     * being delivered to this component.
+     * 
+     * @param eventsToDisable
+     *            the event mask specifying the event types.
+     */
+    protected final void disableEvents(long eventsToDisable) {
+        toolkit.lockAWT();
+        try {
+            enabledEvents &= ~eventsToDisable;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /*
+     * For use in MouseDispatcher only. Really it checks not only mouse events.
+     */
+    /**
+     * Checks if is mouse event enabled.
+     * 
+     * @param eventMask
+     *            the event mask.
+     * @return true, if is mouse event enabled.
+     */
+    boolean isMouseEventEnabled(long eventMask) {
+        return (isEventEnabled(eventMask) || (enabledAWTEvents & eventMask) != 0);
+    }
+
+    /**
+     * Checks if is event enabled.
+     * 
+     * @param eventMask
+     *            the event mask.
+     * @return true, if is event enabled.
+     */
+    boolean isEventEnabled(long eventMask) {
+        return ((enabledEvents & eventMask) != 0);
+    }
+
+    /**
+     * Enables or disables input method support for this component.
+     * 
+     * @param enable
+     *            true to enable input method support, false to disable it.
+     */
+    public void enableInputMethods(boolean enable) {
+        toolkit.lockAWT();
+        try {
+            if (!enable) {
+                removeNotifyInputContext();
+            }
+            inputMethodsEnabled = enable;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets an array of all component's listeners registered for this component.
+     * 
+     * @return an array of all component's listeners registered for this
+     *         component.
+     */
+    public ComponentListener[] getComponentListeners() {
+        return componentListeners.getUserListeners(new ComponentListener[0]);
+    }
+
+    /**
+     * Adds the specified component listener to the Component for receiving
+     * component's event.
+     * 
+     * @param l
+     *            the ComponentListener.
+     */
+    public void addComponentListener(ComponentListener l) {
+        componentListeners.addUserListener(l);
+    }
+
+    /**
+     * Removes the component listener registered for this Component.
+     * 
+     * @param l
+     *            the ComponentListener.
+     */
+    public void removeComponentListener(ComponentListener l) {
+        componentListeners.removeUserListener(l);
+    }
+
+    /**
+     * Processes a component event that has occurred on this component by
+     * dispatching them to any registered ComponentListener objects.
+     * 
+     * @param e
+     *            the ComponentEvent.
+     */
+    protected void processComponentEvent(ComponentEvent e) {
+        processComponentEventImpl(e, componentListeners.getUserListeners());
+    }
+
+    /**
+     * Process component event impl.
+     * 
+     * @param e
+     *            the e.
+     * @param c
+     *            the c.
+     */
+    private void processComponentEventImpl(ComponentEvent e, Collection<ComponentListener> c) {
+        for (ComponentListener listener : c) {
+            switch (e.getID()) {
+                case ComponentEvent.COMPONENT_HIDDEN:
+                    listener.componentHidden(e);
+                    break;
+                case ComponentEvent.COMPONENT_MOVED:
+                    listener.componentMoved(e);
+                    break;
+                case ComponentEvent.COMPONENT_RESIZED:
+                    listener.componentResized(e);
+                    break;
+                case ComponentEvent.COMPONENT_SHOWN:
+                    listener.componentShown(e);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Gets an array of focus listeners registered for this Component.
+     * 
+     * @return the array of focus listeners registered for this Component.
+     */
+    public FocusListener[] getFocusListeners() {
+        return focusListeners.getUserListeners(new FocusListener[0]);
+    }
+
+    /**
+     * Adds the specified focus listener to the Component for receiving focus
+     * events.
+     * 
+     * @param l
+     *            the FocusListener.
+     */
+    public void addFocusListener(FocusListener l) {
+        focusListeners.addUserListener(l);
+    }
+
+    /**
+     * Adds the awt focus listener.
+     * 
+     * @param l
+     *            the l.
+     */
+    void addAWTFocusListener(FocusListener l) {
+        enableAWTEvents(AWTEvent.FOCUS_EVENT_MASK);
+        focusListeners.addSystemListener(l);
+    }
+
+    /**
+     * Removes the focus listener registered for this Component.
+     * 
+     * @param l
+     *            the FocusListener.
+     */
+    public void removeFocusListener(FocusListener l) {
+        focusListeners.removeUserListener(l);
+    }
+
+    /**
+     * Processes a FocusEvent that has occurred on this component by dispatching
+     * it to the registered listeners.
+     * 
+     * @param e
+     *            the FocusEvent.
+     */
+    protected void processFocusEvent(FocusEvent e) {
+        processFocusEventImpl(e, focusListeners.getUserListeners());
+    }
+
+    /**
+     * Process focus event impl.
+     * 
+     * @param e
+     *            the e.
+     * @param c
+     *            the c.
+     */
+    private void processFocusEventImpl(FocusEvent e, Collection<FocusListener> c) {
+        for (FocusListener listener : c) {
+            switch (e.getID()) {
+                case FocusEvent.FOCUS_GAINED:
+                    listener.focusGained(e);
+                    break;
+                case FocusEvent.FOCUS_LOST:
+                    listener.focusLost(e);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Gets an array of registered HierarchyListeners for this Component.
+     * 
+     * @return an array of registered HierarchyListeners for this Component.
+     */
+    public HierarchyListener[] getHierarchyListeners() {
+        return hierarchyListeners.getUserListeners(new HierarchyListener[0]);
+    }
+
+    /**
+     * Adds the specified hierarchy listener.
+     * 
+     * @param l
+     *            the HierarchyListener.
+     */
+    public void addHierarchyListener(HierarchyListener l) {
+        hierarchyListeners.addUserListener(l);
+    }
+
+    /**
+     * Removes the hierarchy listener registered for this component.
+     * 
+     * @param l
+     *            the HierarchyListener.
+     */
+    public void removeHierarchyListener(HierarchyListener l) {
+        hierarchyListeners.removeUserListener(l);
+    }
+
+    /**
+     * Processes a hierarchy event that has occurred on this component by
+     * dispatching it to the registered listeners.
+     * 
+     * @param e
+     *            the HierarchyEvent.
+     */
+    protected void processHierarchyEvent(HierarchyEvent e) {
+        for (HierarchyListener listener : hierarchyListeners.getUserListeners()) {
+            switch (e.getID()) {
+                case HierarchyEvent.HIERARCHY_CHANGED:
+                    listener.hierarchyChanged(e);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Gets an array of HierarchyBoundsListener objects registered to this
+     * Component.
+     * 
+     * @return an array of HierarchyBoundsListener objects.
+     */
+    public HierarchyBoundsListener[] getHierarchyBoundsListeners() {
+        return hierarchyBoundsListeners.getUserListeners(new HierarchyBoundsListener[0]);
+    }
+
+    /**
+     * Adds the specified hierarchy bounds listener.
+     * 
+     * @param l
+     *            the HierarchyBoundsListener.
+     */
+    public void addHierarchyBoundsListener(HierarchyBoundsListener l) {
+        hierarchyBoundsListeners.addUserListener(l);
+    }
+
+    /**
+     * Removes the hierarchy bounds listener registered for this Component.
+     * 
+     * @param l
+     *            the HierarchyBoundsListener.
+     */
+    public void removeHierarchyBoundsListener(HierarchyBoundsListener l) {
+        hierarchyBoundsListeners.removeUserListener(l);
+    }
+
+    /**
+     * Processes a hierarchy bounds event that has occurred on this component by
+     * dispatching it to the registered listeners.
+     * 
+     * @param e
+     *            the HierarchyBoundsEvent.
+     */
+    protected void processHierarchyBoundsEvent(HierarchyEvent e) {
+        for (HierarchyBoundsListener listener : hierarchyBoundsListeners.getUserListeners()) {
+            switch (e.getID()) {
+                case HierarchyEvent.ANCESTOR_MOVED:
+                    listener.ancestorMoved(e);
+                    break;
+                case HierarchyEvent.ANCESTOR_RESIZED:
+                    listener.ancestorResized(e);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Gets an array of the key listeners registered to the Component.
+     * 
+     * @return an array of the key listeners registered to the Component.
+     */
+    public KeyListener[] getKeyListeners() {
+        return keyListeners.getUserListeners(new KeyListener[0]);
+    }
+
+    /**
+     * Adds the specified key listener.
+     * 
+     * @param l
+     *            the KeyListener.
+     */
+    public void addKeyListener(KeyListener l) {
+        keyListeners.addUserListener(l);
+    }
+
+    /**
+     * Adds the awt key listener.
+     * 
+     * @param l
+     *            the l.
+     */
+    void addAWTKeyListener(KeyListener l) {
+        enableAWTEvents(AWTEvent.KEY_EVENT_MASK);
+        keyListeners.addSystemListener(l);
+    }
+
+    /**
+     * Removes the key listener registered for this Component.
+     * 
+     * @param l
+     *            the KeyListener.
+     */
+    public void removeKeyListener(KeyListener l) {
+        keyListeners.removeUserListener(l);
+    }
+
+    /**
+     * Processes a key event that has occurred on this component by dispatching
+     * it to the registered listeners.
+     * 
+     * @param e
+     *            the KeyEvent.
+     */
+    protected void processKeyEvent(KeyEvent e) {
+        processKeyEventImpl(e, keyListeners.getUserListeners());
+    }
+
+    /**
+     * Process key event impl.
+     * 
+     * @param e
+     *            the e.
+     * @param c
+     *            the c.
+     */
+    private void processKeyEventImpl(KeyEvent e, Collection<KeyListener> c) {
+        for (KeyListener listener : c) {
+            switch (e.getID()) {
+                case KeyEvent.KEY_PRESSED:
+                    listener.keyPressed(e);
+                    break;
+                case KeyEvent.KEY_RELEASED:
+                    listener.keyReleased(e);
+                    break;
+                case KeyEvent.KEY_TYPED:
+                    listener.keyTyped(e);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Gets an array of the mouse listeners registered to the Component.
+     * 
+     * @return an array of the mouse listeners registered to the Component.
+     */
+    public MouseListener[] getMouseListeners() {
+        return mouseListeners.getUserListeners(new MouseListener[0]);
+    }
+
+    /**
+     * Adds the specified mouse listener.
+     * 
+     * @param l
+     *            the MouseListener.
+     */
+    public void addMouseListener(MouseListener l) {
+        mouseListeners.addUserListener(l);
+    }
+
+    /**
+     * Adds the awt mouse listener.
+     * 
+     * @param l
+     *            the l.
+     */
+    void addAWTMouseListener(MouseListener l) {
+        enableAWTEvents(AWTEvent.MOUSE_EVENT_MASK);
+        mouseListeners.addSystemListener(l);
+    }
+
+    /**
+     * Adds the awt mouse motion listener.
+     * 
+     * @param l
+     *            the l.
+     */
+    void addAWTMouseMotionListener(MouseMotionListener l) {
+        enableAWTEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
+        mouseMotionListeners.addSystemListener(l);
+    }
+
+    /**
+     * Adds the awt component listener.
+     * 
+     * @param l
+     *            the l.
+     */
+    void addAWTComponentListener(ComponentListener l) {
+        enableAWTEvents(AWTEvent.COMPONENT_EVENT_MASK);
+        componentListeners.addSystemListener(l);
+    }
+
+    /**
+     * Adds the awt input method listener.
+     * 
+     * @param l
+     *            the l.
+     */
+    void addAWTInputMethodListener(InputMethodListener l) {
+        enableAWTEvents(AWTEvent.INPUT_METHOD_EVENT_MASK);
+        inputMethodListeners.addSystemListener(l);
+    }
+
+    /**
+     * Adds the awt mouse wheel listener.
+     * 
+     * @param l
+     *            the l.
+     */
+    void addAWTMouseWheelListener(MouseWheelListener l) {
+        enableAWTEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK);
+        mouseWheelListeners.addSystemListener(l);
+    }
+
+    /**
+     * Removes the mouse listener registered for this Component.
+     * 
+     * @param l
+     *            the MouseListener.
+     */
+    public void removeMouseListener(MouseListener l) {
+        mouseListeners.removeUserListener(l);
+    }
+
+    /**
+     * Processes a mouse event that has occurred on this component by
+     * dispatching it to the registered listeners.
+     * 
+     * @param e
+     *            the MouseEvent.
+     */
+    protected void processMouseEvent(MouseEvent e) {
+        processMouseEventImpl(e, mouseListeners.getUserListeners());
+    }
+
+    /**
+     * Process mouse event impl.
+     * 
+     * @param e
+     *            the e.
+     * @param c
+     *            the c.
+     */
+    private void processMouseEventImpl(MouseEvent e, Collection<MouseListener> c) {
+        for (MouseListener listener : c) {
+            switch (e.getID()) {
+                case MouseEvent.MOUSE_CLICKED:
+                    listener.mouseClicked(e);
+                    break;
+                case MouseEvent.MOUSE_ENTERED:
+                    listener.mouseEntered(e);
+                    break;
+                case MouseEvent.MOUSE_EXITED:
+                    listener.mouseExited(e);
+                    break;
+                case MouseEvent.MOUSE_PRESSED:
+                    listener.mousePressed(e);
+                    break;
+                case MouseEvent.MOUSE_RELEASED:
+                    listener.mouseReleased(e);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Process mouse motion event impl.
+     * 
+     * @param e
+     *            the e.
+     * @param c
+     *            the c.
+     */
+    private void processMouseMotionEventImpl(MouseEvent e, Collection<MouseMotionListener> c) {
+        for (MouseMotionListener listener : c) {
+            switch (e.getID()) {
+                case MouseEvent.MOUSE_DRAGGED:
+                    listener.mouseDragged(e);
+                    break;
+                case MouseEvent.MOUSE_MOVED:
+                    listener.mouseMoved(e);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Gets an array of the mouse motion listeners registered to the Component.
+     * 
+     * @return an array of the MouseMotionListeners registered to the Component.
+     */
+    public MouseMotionListener[] getMouseMotionListeners() {
+        return mouseMotionListeners.getUserListeners(new MouseMotionListener[0]);
+    }
+
+    /**
+     * Adds the specified mouse motion listener.
+     * 
+     * @param l
+     *            the MouseMotionListener.
+     */
+    public void addMouseMotionListener(MouseMotionListener l) {
+        mouseMotionListeners.addUserListener(l);
+    }
+
+    /**
+     * Removes the mouse motion listener registered for this component.
+     * 
+     * @param l
+     *            the MouseMotionListener.
+     */
+    public void removeMouseMotionListener(MouseMotionListener l) {
+        mouseMotionListeners.removeUserListener(l);
+    }
+
+    /**
+     * Processes a mouse motion event that has occurred on this component by
+     * dispatching it to the registered listeners.
+     * 
+     * @param e
+     *            the MouseEvent.
+     */
+    protected void processMouseMotionEvent(MouseEvent e) {
+        processMouseMotionEventImpl(e, mouseMotionListeners.getUserListeners());
+    }
+
+    /**
+     * Gets an array of the mouse wheel listeners registered to the Component.
+     * 
+     * @return an array of the MouseWheelListeners registered to the Component.
+     */
+    public MouseWheelListener[] getMouseWheelListeners() {
+        return mouseWheelListeners.getUserListeners(new MouseWheelListener[0]);
+    }
+
+    /**
+     * Adds the specified mouse wheel listener.
+     * 
+     * @param l
+     *            the MouseWheelListener.
+     */
+    public void addMouseWheelListener(MouseWheelListener l) {
+        mouseWheelListeners.addUserListener(l);
+    }
+
+    /**
+     * Removes the mouse wheel listener registered for this component.
+     * 
+     * @param l
+     *            the MouseWheelListener.
+     */
+    public void removeMouseWheelListener(MouseWheelListener l) {
+        mouseWheelListeners.removeUserListener(l);
+    }
+
+    /**
+     * Processes a mouse wheel event that has occurred on this component by
+     * dispatching it to the registered listeners.
+     * 
+     * @param e
+     *            the MouseWheelEvent.
+     */
+    protected void processMouseWheelEvent(MouseWheelEvent e) {
+        processMouseWheelEventImpl(e, mouseWheelListeners.getUserListeners());
+    }
+
+    /**
+     * Gets an array of the InputMethodListener listeners registered to the
+     * Component.
+     * 
+     * @return an array of the InputMethodListener listeners registered to the
+     *         Component.
+     */
+    public InputMethodListener[] getInputMethodListeners() {
+        return inputMethodListeners.getUserListeners(new InputMethodListener[0]);
+    }
+
+    /**
+     * Adds the specified input method listener.
+     * 
+     * @param l
+     *            the InputMethodListener.
+     */
+    public void addInputMethodListener(InputMethodListener l) {
+        inputMethodListeners.addUserListener(l);
+    }
+
+    /**
+     * Removes the input method listener registered for this component.
+     * 
+     * @param l
+     *            the InputMethodListener.
+     */
+    public void removeInputMethodListener(InputMethodListener l) {
+        inputMethodListeners.removeUserListener(l);
+    }
+
+    /**
+     * Processes an input method event that has occurred on this component by
+     * dispatching it to the registered listeners.
+     * 
+     * @param e
+     *            the InputMethodEvent.
+     */
+    protected void processInputMethodEvent(InputMethodEvent e) {
+        processInputMethodEventImpl(e, inputMethodListeners.getUserListeners());
+    }
+
+    /**
+     * Process input method event impl.
+     * 
+     * @param e
+     *            the e.
+     * @param c
+     *            the c.
+     */
+    private void processInputMethodEventImpl(InputMethodEvent e, Collection<InputMethodListener> c) {
+        for (InputMethodListener listener : c) {
+            switch (e.getID()) {
+                case InputMethodEvent.CARET_POSITION_CHANGED:
+                    listener.caretPositionChanged(e);
+                    break;
+                case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED:
+                    listener.inputMethodTextChanged(e);
+                    break;
+            }
+        }
+    }
+
+    // ???AWT
+    /*
+     * public Point getMousePosition() throws HeadlessException { Point
+     * absPointerPos = MouseInfo.getPointerInfo().getLocation(); Window
+     * winUnderPtr =
+     * toolkit.dispatcher.mouseDispatcher.findWindowAt(absPointerPos); Point
+     * pointerPos = MouseDispatcher.convertPoint(null, absPointerPos,
+     * winUnderPtr); boolean isUnderPointer = false; if (winUnderPtr == null) {
+     * return null; } isUnderPointer = winUnderPtr.isComponentAt(this,
+     * pointerPos); if (isUnderPointer) { return
+     * MouseDispatcher.convertPoint(null, absPointerPos, this); } return null; }
+     */
+
+    /**
+     * Set native caret at the given position <br>
+     * Note: this method takes AWT lock inside because it walks through the
+     * component hierarchy.
+     * 
+     * @param x
+     *            the x.
+     * @param y
+     *            the y.
+     */
+    void setCaretPos(final int x, final int y) {
+        Runnable r = new Runnable() {
+            public void run() {
+                toolkit.lockAWT();
+                try {
+                    setCaretPosImpl(x, y);
+                } finally {
+                    toolkit.unlockAWT();
+                }
+            }
+        };
+        if (Thread.currentThread() instanceof EventDispatchThread) {
+            r.run();
+        } else {
+            toolkit.getSystemEventQueueImpl().postEvent(new InvocationEvent(this, r));
+        }
+    }
+
+    /**
+     * This method should be called only at event dispatch thread.
+     * 
+     * @param x
+     *            the x.
+     * @param y
+     *            the y.
+     */
+    void setCaretPosImpl(int x, int y) {
+        Component c = this;
+        while ((c != null) && c.behaviour.isLightweight()) {
+            x += c.x;
+            y += c.y;
+            // ???AWT: c = c.getParent();
+        }
+        if (c == null) {
+            return;
+        }
+        // ???AWT
+        /*
+         * if (c instanceof Window) { Insets insets = c.getNativeInsets(); x -=
+         * insets.left; y -= insets.top; }
+         * toolkit.getWindowFactory().setCaretPosition(x, y);
+         */
+    }
+
+    // to be overridden in standard components such as Button and List
+    /**
+     * Gets the default minimum size.
+     * 
+     * @return the default minimum size.
+     */
+    Dimension getDefaultMinimumSize() {
+        return null;
+    }
+
+    // to be overridden in standard components such as Button and List
+    /**
+     * Gets the default preferred size.
+     * 
+     * @return the default preferred size.
+     */
+    Dimension getDefaultPreferredSize() {
+        return null;
+    }
+
+    // to be overridden in standard components such as Button and List
+    /**
+     * Reset default size.
+     */
+    void resetDefaultSize() {
+    }
+
+    // ???AWT
+    /*
+     * ComponentBehavior createBehavior() { return new LWBehavior(this); }
+     */
+
+    /**
+     * Gets the default background.
+     * 
+     * @return the default background.
+     */
+    Color getDefaultBackground() {
+        // ???AWT: return getWindowAncestor().getDefaultBackground();
+        return getBackground();
+    }
+
+    /**
+     * Gets the default foreground.
+     * 
+     * @return the default foreground.
+     */
+    Color getDefaultForeground() {
+        // ???AWT return getWindowAncestor().getDefaultForeground();
+        return getForeground();
+    }
+
+    /**
+     * Called when native resource for this component is created (for
+     * heavyweights only).
+     * 
+     * @param win
+     *            the win.
+     */
+    void nativeWindowCreated(NativeWindow win) {
+        // to be overridden
+    }
+
+    /**
+     * Determine the component's area hidden behind the windows that have higher
+     * Z-order, including windows of other applications.
+     * 
+     * @param image
+     *            the image.
+     * @param destLocation
+     *            the dest location.
+     * @param destSize
+     *            the dest size.
+     * @param source
+     *            the source.
+     * @return the calculated region, or null if it cannot be determined.
+     */
+    // ???AWT
+    /*
+     * MultiRectArea getObscuredRegion(Rectangle part) { if (!visible || parent
+     * == null || !parent.visible) { return null; } Rectangle r = new
+     * Rectangle(0, 0, w, h); if (part != null) { r = r.intersection(part); } if
+     * (r.isEmpty()) { return null; } r.translate(x, y); MultiRectArea ret =
+     * parent.getObscuredRegion(r); if (ret != null) {
+     * parent.addObscuredRegions(ret, this); ret.translate(-x, -y);
+     * ret.intersect(new Rectangle(0, 0, w, h)); } return ret; }
+     */
+
+    // ???AWT
+    /*
+     * private void readObject(ObjectInputStream stream) throws IOException,
+     * ClassNotFoundException { stream.defaultReadObject(); FieldsAccessor
+     * accessor = new FieldsAccessor(Component.class, this);
+     * accessor.set("toolkit", Toolkit.getDefaultToolkit()); //$NON-NLS-1$
+     * accessor.set("behaviour", createBehavior()); //$NON-NLS-1$
+     * accessor.set("componentLock", new Object()); // $NON-LOCK-1$
+     * //$NON-NLS-1$ }
+     */
+
+    final void onDrawImage(Image image, Point destLocation, Dimension destSize, Rectangle source) {
+        ImageParameters imageParams;
+        if (updatedImages == null) {
+            updatedImages = new HashMap<Image, ImageParameters>();
+        }
+        imageParams = updatedImages.get(image);
+        if (imageParams == null) {
+            imageParams = new ImageParameters();
+            updatedImages.put(image, imageParams);
+        }
+        imageParams.addDrawing(destLocation, destSize, source);
+    }
+
+    public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
+        toolkit.lockAWT();
+        try {
+            boolean done = false;
+            if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) {
+                done = true;
+            } else if ((infoflags & SOMEBITS) != 0 && incrementalImageUpdate) {
+                done = true;
+            }
+            if (done) {
+                repaint();
+            }
+            return (infoflags & (ABORT | ALLBITS)) == 0;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    // ???AWT
+    /*
+     * private void invalidateRealParent() { Container realParent =
+     * getRealParent(); if ((realParent != null) && realParent.isValid()) {
+     * realParent.invalidate(); } }
+     */
+
+    /**
+     * The Class ImageParameters.
+     */
+    private class ImageParameters {
+
+        /**
+         * The drawing params.
+         */
+        private final LinkedList<DrawingParameters> drawingParams = new LinkedList<DrawingParameters>();
+
+        /**
+         * The size.
+         */
+        Dimension size = new Dimension(Component.this.w, Component.this.h);
+
+        /**
+         * Adds the drawing.
+         * 
+         * @param destLocation
+         *            the dest location.
+         * @param destSize
+         *            the dest size.
+         * @param source
+         *            the source.
+         */
+        void addDrawing(Point destLocation, Dimension destSize, Rectangle source) {
+            drawingParams.add(new DrawingParameters(destLocation, destSize, source));
+        }
+
+        /**
+         * Drawing parameters iterator.
+         * 
+         * @return the iterator< drawing parameters>.
+         */
+        Iterator<DrawingParameters> drawingParametersIterator() {
+            return drawingParams.iterator();
+        }
+
+        /**
+         * The Class DrawingParameters.
+         */
+        class DrawingParameters {
+
+            /**
+             * The dest location.
+             */
+            Point destLocation;
+
+            /**
+             * The dest size.
+             */
+            Dimension destSize;
+
+            /**
+             * The source.
+             */
+            Rectangle source;
+
+            /**
+             * Instantiates a new drawing parameters.
+             * 
+             * @param destLocation
+             *            the dest location.
+             * @param destSize
+             *            the dest size.
+             * @param source
+             *            the source.
+             */
+            DrawingParameters(Point destLocation, Dimension destSize, Rectangle source) {
+                this.destLocation = new Point(destLocation);
+                if (destSize != null) {
+                    this.destSize = new Dimension(destSize);
+                } else {
+                    this.destSize = null;
+                }
+                if (source != null) {
+                    this.source = new Rectangle(source);
+                } else {
+                    this.source = null;
+                }
+            }
+        }
+    }
+
+    /**
+     * TextComponent support.
+     * 
+     * @param e
+     *            the e.
+     * @return true, if dispatch event to im.
+     */
+    // ???AWT
+    /*
+     * private TextKit textKit = null; TextKit getTextKit() { return textKit; }
+     * void setTextKit(TextKit kit) { textKit = kit; }
+     */
+
+    /**
+     * TextField support.
+     */
+    // ???AWT
+    /*
+     * private TextFieldKit textFieldKit = null; TextFieldKit getTextFieldKit()
+     * { return textFieldKit; } void setTextFieldKit(TextFieldKit kit) {
+     * textFieldKit = kit; }
+     */
+
+    /**
+     * Dispatches input & focus events to input method context.
+     * 
+     * @param e
+     *            event to pass to InputContext.dispatchEvent().
+     * @return true if event was consumed by IM, false otherwise.
+     */
+    private boolean dispatchEventToIM(AWTEvent e) {
+        InputContext ic = getInputContext();
+        if (ic == null) {
+            return false;
+        }
+        int id = e.getID();
+        boolean isInputEvent = ((id >= KeyEvent.KEY_FIRST) && (id <= KeyEvent.KEY_LAST))
+                || ((id >= MouseEvent.MOUSE_FIRST) && (id <= MouseEvent.MOUSE_LAST));
+        if (((id >= FocusEvent.FOCUS_FIRST) && (id <= FocusEvent.FOCUS_LAST)) || isInputEvent) {
+            ic.dispatchEvent(e);
+        }
+        return e.isConsumed();
+    }
+}
diff --git a/awt/java/awt/ComponentBehavior.java b/awt/java/awt/ComponentBehavior.java
new file mode 100644
index 0000000..f4e8ffb
--- /dev/null
+++ b/awt/java/awt/ComponentBehavior.java
@@ -0,0 +1,56 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import org.apache.harmony.awt.wtk.NativeWindow;
+
+/**
+ * The interface of the helper object that encapsulates the difference
+ * between lightweight and heavyweight components.
+ */
+interface ComponentBehavior {
+
+    void addNotify();
+
+    void setBounds(int x, int y, int w, int h, int bMask);
+
+    void setVisible(boolean b);
+
+    Graphics getGraphics(int translationX, int translationY, int width, int height);
+
+    NativeWindow getNativeWindow();
+
+    boolean isLightweight();
+
+    void onMove(int x, int y);
+
+    boolean isOpaque();
+
+    boolean isDisplayable();
+
+    void setEnabled(boolean value);
+
+    void removeNotify();
+
+    void setZOrder(int newIndex, int oldIndex);
+
+    boolean setFocus(boolean focus, Component opposite);
+}
diff --git a/awt/java/awt/ComponentOrientation.java b/awt/java/awt/ComponentOrientation.java
new file mode 100644
index 0000000..5acc11a
--- /dev/null
+++ b/awt/java/awt/ComponentOrientation.java
@@ -0,0 +1,154 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov, Dmitry A. Durnev
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * The ComponentOrientation class specifies the language-sensitive orientation
+ * of component's elements or text. It is used to reflect the differences in
+ * this ordering between different writing systems. The ComponentOrientation
+ * class indicates the orientation of the elements/text in the horizontal
+ * direction ("left to right" or "right to left") and in the vertical direction
+ * ("top to bottom" or "bottom to top").
+ * 
+ * @since Android 1.0
+ */
+public final class ComponentOrientation implements Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -4113291392143563828L;
+
+    /**
+     * The Constant LEFT_TO_RIGHT indicates that items run left to right.
+     */
+    public static final ComponentOrientation LEFT_TO_RIGHT = new ComponentOrientation(true, true);
+
+    /**
+     * The Constant RIGHT_TO_LEFT indicates that items run right to left.
+     */
+    public static final ComponentOrientation RIGHT_TO_LEFT = new ComponentOrientation(true, false);
+
+    /**
+     * The Constant UNKNOWN indicates that a component's orientation is not set.
+     */
+    public static final ComponentOrientation UNKNOWN = new ComponentOrientation(true, true);
+
+    /**
+     * The Constant rlLangs.
+     */
+    private static final Set<String> rlLangs = new HashSet<String>(); // RIGHT_TO_LEFT
+
+    // languages
+
+    /**
+     * The horizontal.
+     */
+    private final boolean horizontal;
+
+    /**
+     * The left2right.
+     */
+    private final boolean left2right;
+
+    static {
+        rlLangs.add("ar"); //$NON-NLS-1$
+        rlLangs.add("fa"); //$NON-NLS-1$
+        rlLangs.add("iw"); //$NON-NLS-1$
+        rlLangs.add("ur"); //$NON-NLS-1$
+    }
+
+    /**
+     * Gets the orientation for the given ResourceBundle's localization.
+     * 
+     * @param bdl
+     *            the ResourceBundle.
+     * @return the ComponentOrientation.
+     * @deprecated Use getOrientation(java.util.Locale) method.
+     */
+    @Deprecated
+    public static ComponentOrientation getOrientation(ResourceBundle bdl) {
+        Object obj = null;
+        try {
+            obj = bdl.getObject("Orientation"); //$NON-NLS-1$
+        } catch (MissingResourceException mre) {
+            obj = null;
+        }
+        if (obj instanceof ComponentOrientation) {
+            return (ComponentOrientation)obj;
+        }
+        Locale locale = bdl.getLocale();
+        if (locale == null) {
+            locale = Locale.getDefault();
+        }
+        return getOrientation(locale);
+    }
+
+    /**
+     * Gets the orientation for the specified locale.
+     * 
+     * @param locale
+     *            the specified Locale.
+     * @return the ComponentOrientation.
+     */
+    public static ComponentOrientation getOrientation(Locale locale) {
+        String lang = locale.getLanguage();
+        return rlLangs.contains(lang) ? RIGHT_TO_LEFT : LEFT_TO_RIGHT;
+    }
+
+    /**
+     * Instantiates a new component orientation.
+     * 
+     * @param hor
+     *            whether the items should be arranged horizontally.
+     * @param l2r
+     *            whether this orientation specifies a left-to-right flow.
+     */
+    private ComponentOrientation(boolean hor, boolean l2r) {
+        horizontal = hor;
+        left2right = l2r;
+    }
+
+    /**
+     * Returns true if the text of the of writing systems arranged horizontally.
+     * 
+     * @return true, if the text is written horizontally, false for a vertical
+     *         arrangement.
+     */
+    public boolean isHorizontal() {
+        return horizontal;
+    }
+
+    /**
+     * Returns true if the text is arranged from left to right.
+     * 
+     * @return true, for writing systems written from left to right; false for
+     *         right-to-left.
+     */
+    public boolean isLeftToRight() {
+        return left2right;
+    }
+
+}
diff --git a/awt/java/awt/Composite.java b/awt/java/awt/Composite.java
new file mode 100644
index 0000000..d1730fe
--- /dev/null
+++ b/awt/java/awt/Composite.java
@@ -0,0 +1,51 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.image.ColorModel;
+
+/**
+ * The Composite interface allows the methods to compose a draw primitive on the
+ * graphics area. The classes implementing this interface provides the rules and
+ * a method to create the context for a particular operation.
+ * 
+ * @since Android 1.0
+ */
+public interface Composite {
+
+    /**
+     * Creates a CompositeContext which defines the encapsulated and optimized
+     * environment for a compositing operation. Several contexts can exist for a
+     * single Composite object.
+     * 
+     * @param srcColorModel
+     *            the source's ColorModel.
+     * @param dstColorModel
+     *            the destination's ColorModel.
+     * @param hints
+     *            the RenderingHints.
+     * @return the CompositeContext object.
+     */
+    public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel,
+            RenderingHints hints);
+
+}
diff --git a/awt/java/awt/CompositeContext.java b/awt/java/awt/CompositeContext.java
new file mode 100644
index 0000000..795640d
--- /dev/null
+++ b/awt/java/awt/CompositeContext.java
@@ -0,0 +1,54 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+/**
+ * The CompositeContext interface specifies the encapsulated and optimized
+ * environment for a compositing operation.
+ * 
+ * @since Android 1.0
+ */
+public interface CompositeContext {
+
+    /**
+     * Composes the two source Raster objects and places the result in the
+     * destination WritableRaster.
+     * 
+     * @param src
+     *            the source Raster.
+     * @param dstIn
+     *            the destination Raster.
+     * @param dstOut
+     *            the WritableRaster object where the result of composing
+     *            operation is stored.
+     */
+    public void compose(Raster src, Raster dstIn, WritableRaster dstOut);
+
+    /**
+     * Releases resources allocated for a context.
+     */
+    public void dispose();
+
+}
diff --git a/awt/java/awt/Cursor.java b/awt/java/awt/Cursor.java
new file mode 100644
index 0000000..0a0cc84
--- /dev/null
+++ b/awt/java/awt/Cursor.java
@@ -0,0 +1,427 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.wtk.NativeCursor;
+
+/**
+ * The Cursor class represents the bitmap of the mouse cursor.
+ * 
+ * @since Android 1.0
+ */
+public class Cursor implements Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 8028237497568985504L;
+
+    /**
+     * The Constant DEFAULT_CURSOR indicates the default cursor type.
+     */
+    public static final int DEFAULT_CURSOR = 0;
+
+    /**
+     * The Constant CROSSHAIR_CURSOR cursor type.
+     */
+    public static final int CROSSHAIR_CURSOR = 1;
+
+    /**
+     * The Constant TEXT_CURSOR cursor type.
+     */
+    public static final int TEXT_CURSOR = 2;
+
+    /**
+     * The Constant WAIT_CURSOR cursor type.
+     */
+    public static final int WAIT_CURSOR = 3;
+
+    /**
+     * The Constant SW_RESIZE_CURSOR cursor type.
+     */
+    public static final int SW_RESIZE_CURSOR = 4;
+
+    /**
+     * The Constant SE_RESIZE_CURSOR cursor type.
+     */
+    public static final int SE_RESIZE_CURSOR = 5;
+
+    /**
+     * The Constant NW_RESIZE_CURSOR cursor type.
+     */
+    public static final int NW_RESIZE_CURSOR = 6;
+
+    /**
+     * The Constant NE_RESIZE_CURSOR cursor type.
+     */
+    public static final int NE_RESIZE_CURSOR = 7;
+
+    /**
+     * The Constant N_RESIZE_CURSOR cursor type.
+     */
+    public static final int N_RESIZE_CURSOR = 8;
+
+    /**
+     * The Constant S_RESIZE_CURSOR cursor type.
+     */
+    public static final int S_RESIZE_CURSOR = 9;
+
+    /**
+     * The Constant W_RESIZE_CURSOR cursor type.
+     */
+    public static final int W_RESIZE_CURSOR = 10;
+
+    /**
+     * The Constant E_RESIZE_CURSOR cursor type.
+     */
+    public static final int E_RESIZE_CURSOR = 11;
+
+    /**
+     * The Constant HAND_CURSOR cursor type.
+     */
+    public static final int HAND_CURSOR = 12;
+
+    /**
+     * The Constant MOVE_CURSOR cursor type.
+     */
+    public static final int MOVE_CURSOR = 13;
+
+    /**
+     * A mapping from names to system custom cursors.
+     */
+    static Map<String, Cursor> systemCustomCursors;
+
+    /**
+     * The cursor props.
+     */
+    static Properties cursorProps;
+
+    /**
+     * The Constant predefinedNames.
+     */
+    static final String[] predefinedNames = {
+            "Default", "Crosshair", "Text", "Wait", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+            "Southwest Resize", "Southeast Resize", //$NON-NLS-1$ //$NON-NLS-2$
+            "Northwest Resize", "Northeast Resize", //$NON-NLS-1$ //$NON-NLS-2$
+            "North Resize", "South Resize", "West Resize", "East Resize", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+            "Hand", "Move" //$NON-NLS-1$ //$NON-NLS-2$
+
+    };
+
+    /**
+     * The predefined set of cursors.
+     */
+    protected static Cursor[] predefined = {
+            new Cursor(DEFAULT_CURSOR), null, null, null, null, null, null, null, null, null, null,
+            null, null, null
+    };
+
+    /**
+     * The Constant CUSTOM_CURSOR is associated with all custom cursor types.
+     * (Those which are not predefined)
+     */
+    public static final int CUSTOM_CURSOR = -1;
+
+    /**
+     * The name of the cursor.
+     */
+    protected String name;
+
+    /**
+     * The type of the cursor, chosen from the list of cursor type constants.
+     */
+    private final int type;
+
+    /**
+     * The native cursor.
+     */
+    private transient NativeCursor nativeCursor;
+
+    /**
+     * The exact point on the cursor image that indicates which point the cursor
+     * is selecting (pointing to). The coordinates are given with respect the
+     * origin of the Image (its upper left corner).
+     */
+    private Point hotSpot;
+
+    /**
+     * The image to draw on the screen representing the cursor.
+     */
+    private Image image;
+
+    /**
+     * Instantiates a new cursor with the specified name.
+     * 
+     * @param name
+     *            the name of cursor.
+     */
+    protected Cursor(String name) {
+        this(name, null, new Point());
+    }
+
+    /**
+     * Instantiates a new cursor of the specified type.
+     * 
+     * @param type
+     *            the type of cursor.
+     */
+    public Cursor(int type) {
+        checkType(type);
+        this.type = type;
+        if ((type >= 0) && (type < predefinedNames.length)) {
+            name = predefinedNames[type] + " Cursor"; //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Instantiates a new cursor.
+     * 
+     * @param name
+     *            the name.
+     * @param img
+     *            the img.
+     * @param hotSpot
+     *            the hot spot.
+     */
+    Cursor(String name, Image img, Point hotSpot) {
+        this.name = name;
+        type = CUSTOM_CURSOR;
+        this.hotSpot = hotSpot;
+        image = img;
+    }
+
+    /**
+     * Finalize method overrides the finalize method from Object class.
+     * 
+     * @throws Throwable
+     *             if the native cursor is not null and throws a Throwable when
+     *             destroyed.
+     */
+    @Override
+    protected void finalize() throws Throwable {
+        if (nativeCursor != null) {
+            nativeCursor.destroyCursor();
+        }
+    }
+
+    /**
+     * Gets the name of the cursor.
+     * 
+     * @return the name of the cursor.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the String representation of the cursor.
+     * 
+     * @return the String representation of the cursor.
+     */
+    @Override
+    public String toString() {
+        return getClass().getName() + "[" + name + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+    /**
+     * Gets the cursor type.
+     * 
+     * @return the cursor type.
+     */
+    public int getType() {
+        return type;
+    }
+
+    /**
+     * Gets the predefined cursor with the specified type.
+     * 
+     * @param type
+     *            the type of cursor.
+     * @return the predefined cursor with the specified type.
+     */
+    public static Cursor getPredefinedCursor(int type) {
+        checkType(type);
+        Cursor cursor = predefined[type];
+        if (cursor == null) {
+            cursor = new Cursor(type);
+            predefined[type] = cursor;
+        }
+        return cursor;
+    }
+
+    /**
+     * Gets the default cursor.
+     * 
+     * @return the default cursor.
+     */
+    public static Cursor getDefaultCursor() {
+        return getPredefinedCursor(DEFAULT_CURSOR);
+    }
+
+    /**
+     * Gets the specified system custom cursor.
+     * 
+     * @param name
+     *            the name of the desired system cursor.
+     * @return the specific system cursor with the specified name.
+     * @throws AWTException
+     *             if the desired cursor has malformed data such as an
+     *             incorrectly defined hot spot.
+     * @throws HeadlessException
+     *             if the isHeadless method of the GraphicsEnvironment returns
+     *             true.
+     */
+    public static Cursor getSystemCustomCursor(String name) throws AWTException, HeadlessException {
+        Toolkit.checkHeadless();
+        return getSystemCustomCursorFromMap(name);
+    }
+
+    /**
+     * Gets the specified system custom cursor from the map of system custom
+     * cursors.
+     * 
+     * @param name
+     *            the name of the desired cursor.
+     * @return the desired system custom cursor from the map of system custom
+     *         cursors.
+     * @throws AWTException
+     *             the AWT exception.
+     */
+    private static Cursor getSystemCustomCursorFromMap(String name) throws AWTException {
+        loadCursorProps();
+        if (systemCustomCursors == null) {
+            systemCustomCursors = new HashMap<String, Cursor>();
+        }
+        Cursor cursor = systemCustomCursors.get(name);
+        if (cursor != null) {
+            return cursor;
+        }
+        // awt.141=failed to parse hotspot property for cursor:
+        String exMsg = Messages.getString("awt.141") + name; //$NON-NLS-1$
+        String nm = "Cursor." + name; //$NON-NLS-1$
+        String nameStr = cursorProps.getProperty(nm + ".Name"); //$NON-NLS-1$
+        String hotSpotStr = cursorProps.getProperty(nm + ".HotSpot"); //$NON-NLS-1$
+        String fileStr = cursorProps.getProperty(nm + ".File"); //$NON-NLS-1$
+        int idx = hotSpotStr.indexOf(',');
+        if (idx < 0) {
+            throw new AWTException(exMsg);
+        }
+        int x, y;
+        try {
+            x = new Integer(hotSpotStr.substring(0, idx)).intValue();
+            y = new Integer(hotSpotStr.substring(idx + 1, hotSpotStr.length())).intValue();
+        } catch (NumberFormatException nfe) {
+            throw new AWTException(exMsg);
+        }
+        Image img = Toolkit.getDefaultToolkit().createImage(fileStr);
+        cursor = new Cursor(nameStr, img, new Point(x, y));
+        systemCustomCursors.put(name, cursor);
+
+        return cursor;
+    }
+
+    /**
+     * Load cursor props.
+     * 
+     * @throws AWTException
+     *             the AWT exception.
+     */
+    private static void loadCursorProps() throws AWTException {
+        if (cursorProps != null) {
+            return;
+        }
+        String sep = File.separator;
+        String cursorsDir = "lib" + sep + "images" + sep + "cursors"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        String cursorsAbsDir = System.getProperty("java.home") + sep + //$NON-NLS-1$
+                cursorsDir;
+        String cursorPropsFileName = "cursors.properties"; //$NON-NLS-1$
+        String cursorPropsFullFileName = (cursorsAbsDir + sep + cursorPropsFileName);
+        cursorProps = new Properties();
+        try {
+            cursorProps.load(new FileInputStream(new File(cursorPropsFullFileName)));
+        } catch (FileNotFoundException e) {
+            // awt.142=Exception: class {0} {1} occurred while loading: {2}
+            throw new AWTException(Messages.getString("awt.142",//$NON-NLS-1$
+                    new Object[] {
+                            e.getClass(), e.getMessage(), cursorPropsFullFileName
+                    }));
+        } catch (IOException e) {
+            throw new AWTException(e.getMessage());
+        }
+
+    }
+
+    /**
+     * Check type.
+     * 
+     * @param type
+     *            the type.
+     */
+    static void checkType(int type) {
+        // can't use predefined array here because it may not have been
+        // initialized yet
+        if ((type < 0) || (type >= predefinedNames.length)) {
+            // awt.143=illegal cursor type
+            throw new IllegalArgumentException(Messages.getString("awt.143")); //$NON-NLS-1$
+        }
+    }
+
+    // "lazily" create native cursors:
+    /**
+     * Gets the native cursor.
+     * 
+     * @return the native cursor.
+     */
+    NativeCursor getNativeCursor() {
+        if (nativeCursor != null) {
+            return nativeCursor;
+        }
+        Toolkit toolkit = Toolkit.getDefaultToolkit();
+        if (type != CUSTOM_CURSOR) {
+            nativeCursor = toolkit.createNativeCursor(type);
+        } else {
+            nativeCursor = toolkit.createCustomNativeCursor(image, hotSpot, name);
+        }
+        return nativeCursor;
+    }
+
+    /**
+     * Sets the native cursor.
+     * 
+     * @param nativeCursor
+     *            the new native cursor.
+     */
+    void setNativeCursor(NativeCursor nativeCursor) {
+        this.nativeCursor = nativeCursor;
+    }
+}
diff --git a/awt/java/awt/Dimension.java b/awt/java/awt/Dimension.java
new file mode 100644
index 0000000..6777962
--- /dev/null
+++ b/awt/java/awt/Dimension.java
@@ -0,0 +1,201 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.geom.Dimension2D;
+import java.io.Serializable;
+
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Dimension represents the size (width and height) of a component. The
+ * width and height values can be negative, but in that case the behavior of
+ * some methods is unexpected.
+ * 
+ * @since Android 1.0
+ */
+public class Dimension extends Dimension2D implements Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 4723952579491349524L;
+
+    /**
+     * The width dimension.
+     */
+    public int width;
+
+    /**
+     * The height dimension.
+     */
+    public int height;
+
+    /**
+     * Instantiates a new Dimension with the same data as the specified
+     * Dimension.
+     * 
+     * @param d
+     *            the Dimension to copy the data from when creating the new
+     *            Dimension object.
+     */
+    public Dimension(Dimension d) {
+        this(d.width, d.height);
+    }
+
+    /**
+     * Instantiates a new Dimension with zero width and height.
+     */
+    public Dimension() {
+        this(0, 0);
+    }
+
+    /**
+     * Instantiates a new Dimension with the specified width and height.
+     * 
+     * @param width
+     *            the width of the new Dimension.
+     * @param height
+     *            the height of the new Dimension.
+     */
+    public Dimension(int width, int height) {
+        setSize(width, height);
+    }
+
+    /**
+     * Returns the hash code of the Dimension.
+     * 
+     * @return the hash code of the Dimension.
+     */
+    @Override
+    public int hashCode() {
+        HashCode hash = new HashCode();
+        hash.append(width);
+        hash.append(height);
+        return hash.hashCode();
+    }
+
+    /**
+     * Compares this Dimension object with the specified object.
+     * 
+     * @param obj
+     *            the Object to be compared.
+     * @return true, if the specified Object is a Dimension with the same width
+     *         and height data as this Dimension.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof Dimension) {
+            Dimension d = (Dimension)obj;
+            return (d.width == width && d.height == height);
+        }
+        return false;
+    }
+
+    /**
+     * Returns the String associated to this Dimension object.
+     * 
+     * @return the String associated to this Dimension object.
+     */
+    @Override
+    public String toString() {
+        // The output format based on 1.5 release behaviour. It could be
+        // obtained in the following way
+        // System.out.println(new Dimension().toString())
+        return getClass().getName() + "[width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+
+    /**
+     * Sets the size of this Dimension object with the specified width and
+     * height.
+     * 
+     * @param width
+     *            the width of the Dimension.
+     * @param height
+     *            the height of the Dimension.
+     */
+    public void setSize(int width, int height) {
+        this.width = width;
+        this.height = height;
+    }
+
+    /**
+     * Sets the size of this Dimension object by copying the data from the
+     * specified Dimension object.
+     * 
+     * @param d
+     *            the Dimension that gives the new size values.
+     */
+    public void setSize(Dimension d) {
+        setSize(d.width, d.height);
+    }
+
+    /**
+     * Sets the size of this Dimension object with the specified double width
+     * and height.
+     * 
+     * @param width
+     *            the width of the Dimension.
+     * @param height
+     *            the height of the Dimension.
+     * @see java.awt.geom.Dimension2D#setSize(double, double)
+     */
+    @Override
+    public void setSize(double width, double height) {
+        setSize((int)Math.ceil(width), (int)Math.ceil(height));
+    }
+
+    /**
+     * Gets the size of the Dimension.
+     * 
+     * @return the size of the Dimension.
+     */
+    public Dimension getSize() {
+        return new Dimension(width, height);
+    }
+
+    /**
+     * Gets the height of the Dimension.
+     * 
+     * @return the height of the Dimension.
+     * @see java.awt.geom.Dimension2D#getHeight()
+     */
+    @Override
+    public double getHeight() {
+        return height;
+    }
+
+    /**
+     * Gets the width of the Dimension.
+     * 
+     * @return the width of the Dimension.
+     * @see java.awt.geom.Dimension2D#getWidth()
+     */
+    @Override
+    public double getWidth() {
+        return width;
+    }
+
+}
diff --git a/awt/java/awt/Dispatcher.java b/awt/java/awt/Dispatcher.java
new file mode 100644
index 0000000..d457af4
--- /dev/null
+++ b/awt/java/awt/Dispatcher.java
@@ -0,0 +1,723 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov, Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.ComponentEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.PaintEvent;
+import java.awt.event.WindowEvent;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.wtk.NativeEvent;
+import org.apache.harmony.awt.wtk.NativeWindow;
+
+
+/**
+ * Helper package-private class for managing lightweight components &
+ * dispatching events from heavyweight source
+ */
+class Dispatcher {
+
+    //???AWT: final PopupDispatcher popupDispatcher = new PopupDispatcher();
+
+    //???AWT: final FocusDispatcher focusDispatcher;
+
+    final MouseGrabManager mouseGrabManager = new MouseGrabManager();
+
+    final MouseDispatcher mouseDispatcher;
+
+    private final ComponentDispatcher componentDispatcher = new ComponentDispatcher();
+
+    private final KeyDispatcher keyDispatcher = new KeyDispatcher();
+
+    private final Toolkit toolkit;
+
+    int clickInterval = 250;
+
+    /**
+     * @param toolkit - AWT toolkit
+     */
+    Dispatcher(Toolkit toolkit) {
+        this.toolkit = toolkit;
+
+        //???AWT: focusDispatcher = new FocusDispatcher(toolkit);
+        mouseDispatcher = new MouseDispatcher(mouseGrabManager, toolkit);
+    }
+
+    /**
+     * Dispatch native event: produce appropriate AWT events, 
+     * update component's fields when needed
+     * @param event - native event to dispatch
+     * @return - true means default processing by OS is not needed
+     */
+    public boolean onEvent(NativeEvent event) {
+        int eventId = event.getEventId();
+
+        if (eventId == NativeEvent.ID_CREATED) {
+            return toolkit.onWindowCreated(event.getWindowId());
+        } else if (eventId == NativeEvent.ID_MOUSE_GRAB_CANCELED) {
+            return mouseGrabManager.onGrabCanceled();
+        //???AWT
+//        } else if (popupDispatcher.onEvent(event)) {
+//            return false;
+        } else {
+            Component src = toolkit.getComponentById(event.getWindowId());
+
+            if (src != null) {
+                if (((eventId >= ComponentEvent.COMPONENT_FIRST) && (eventId <= ComponentEvent.COMPONENT_LAST))
+                        || ((eventId >= WindowEvent.WINDOW_FIRST) && (eventId <= WindowEvent.WINDOW_LAST))
+                        || (eventId == NativeEvent.ID_INSETS_CHANGED)
+                        || (eventId == NativeEvent.ID_BOUNDS_CHANGED)
+                        || (eventId == NativeEvent.ID_THEME_CHANGED)) {
+                    return componentDispatcher.dispatch(src, event);
+                } else if ((eventId >= MouseEvent.MOUSE_FIRST)
+                        && (eventId <= MouseEvent.MOUSE_LAST)) {
+                    return mouseDispatcher.dispatch(src, event);
+                } else if (eventId == PaintEvent.PAINT) {
+                    //???AWT: src.redrawManager.addPaintRegion(src, event.getClipRects());
+                    return true;
+                }
+            }
+            if ((eventId >= FocusEvent.FOCUS_FIRST)
+                    && (eventId <= FocusEvent.FOCUS_LAST)) {
+
+                //???AWT: return focusDispatcher.dispatch(src, event);
+                return false;
+            } else if ((eventId >= KeyEvent.KEY_FIRST)
+                    && (eventId <= KeyEvent.KEY_LAST)) {
+                return keyDispatcher.dispatch(src, event);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * The dispatcher of native events that affect 
+     * component's state or bounds
+     */
+    final class ComponentDispatcher {
+
+        /**
+         * Handle native event that affects component's state or bounds
+         * @param src - the component updated by the event
+         * @param event - the native event
+         * @return - as in Dispatcher.onEvent()
+         * @see Dispatcher#onEvent(NativeEvent)
+         */
+        boolean dispatch(Component src, NativeEvent event) {
+            int id = event.getEventId();
+
+            if ((id == NativeEvent.ID_INSETS_CHANGED)
+                    || (id == NativeEvent.ID_THEME_CHANGED)) {
+                return dispatchInsets(event, src);
+            } else if ((id >= WindowEvent.WINDOW_FIRST)
+                    && (id <= WindowEvent.WINDOW_LAST)) {
+                return dispatchWindow(event, src);
+            } else {
+                return dispatchPureComponent(event, src);
+            }
+        }
+
+        /**
+         * Handle the change of top-level window's native decorations 
+         * @param event - the native event
+         * @param src - the component updated by the event
+         * @return - as in Dispatcher.onEvent()
+         * @see Dispatcher#onEvent(NativeEvent)
+         */
+        boolean dispatchInsets(NativeEvent event, Component src) {
+            //???AWT
+            /*
+            if (src instanceof Window) {
+                ((Window) src).setNativeInsets(event.getInsets());
+            }
+            */
+            return false;
+        }
+
+        /**
+         * Handle the change of top-level window's state
+         * @param event - the native event
+         * @param src - the component updated by the event
+         * @return - as in Dispatcher.onEvent()
+         * @see Dispatcher#onEvent(NativeEvent)
+         */
+        boolean dispatchWindow(NativeEvent event, Component src) {
+            //???AWT
+            /*
+            Window window = (Window) src;
+            int id = event.getEventId();
+
+            if (id == WindowEvent.WINDOW_CLOSING) {
+                toolkit.getSystemEventQueueImpl().postEvent(
+                          new WindowEvent(window, WindowEvent.WINDOW_CLOSING));
+
+                return true;
+            } else if (id == WindowEvent.WINDOW_STATE_CHANGED) {
+                if (window instanceof Frame) {
+                    ((Frame) window)
+                            .updateExtendedState(event.getWindowState());
+                }
+            }
+            */
+
+            return false;
+        }
+
+        /**
+         * Handle the change of component's size and/or position
+         * @param event - the native event
+         * @param src - the component updated by the event
+         * @return - as in Dispatcher.onEvent()
+         * @see Dispatcher#onEvent(NativeEvent)
+         */
+        private boolean dispatchPureComponent(NativeEvent event, Component src) {
+            Rectangle rect = event.getWindowRect();
+            Point loc = rect.getLocation();
+            int mask;
+
+            switch (event.getEventId()) {
+            case NativeEvent.ID_BOUNDS_CHANGED:
+                mask = 0;
+                break;
+            case ComponentEvent.COMPONENT_MOVED:
+                mask = NativeWindow.BOUNDS_NOSIZE;
+                break;
+            case ComponentEvent.COMPONENT_RESIZED:
+                mask = NativeWindow.BOUNDS_NOMOVE;
+                break;
+            default:
+                // awt.12E=Unknown component event id.
+                throw new RuntimeException(Messages.getString("awt.12E")); //$NON-NLS-1$
+            }
+
+            //???AWT
+            /*
+            if (!(src instanceof Window)) {
+                Component compTo = src.getParent();
+                Component compFrom = src.getHWAncestor();
+
+                if ((compTo != null) && (compFrom != null)) {
+                    loc = MouseDispatcher.convertPoint(compFrom, loc, compTo);
+                }
+            } else {
+                int windowState = event.getWindowState();
+
+                if ((windowState >= 0) && (src instanceof Frame)) {
+                    ((Frame) src).updateExtendedState(windowState);
+                }
+            }
+            src.setBounds(loc.x, loc.y, rect.width, rect.height, mask, false);
+            */
+            
+            return false;
+        }
+
+    }
+
+    /**
+     * The dispatcher of the keyboard events
+     */
+    final class KeyDispatcher {
+
+        /**
+         * Handle the keyboard event using the KeyboardFocusManager
+         * @param src - the component receiving the event
+         * @param event - the native event
+         * @return - as in Dispatcher.onEvent()
+         * @see Dispatcher#onEvent(NativeEvent)
+         */
+        boolean dispatch(Component src, NativeEvent event) {
+            int id = event.getEventId();
+            int modifiers = event.getInputModifiers();
+            int location = event.getKeyLocation();
+            int code = event.getVKey();
+            StringBuffer chars = event.getKeyChars();
+            int charsLength = chars.length();
+            long time = event.getTime();
+            char keyChar = event.getLastChar();
+
+            //???AWT
+            /*
+            if (src == null) {
+                //retarget focus proxy key events to focusOwner:
+                Window focusProxyOwner = toolkit.getFocusProxyOwnerById(event
+                        .getWindowId());
+                if (focusProxyOwner == null) {
+                    return false;
+                }
+                src = KeyboardFocusManager.actualFocusOwner;
+            }
+            */
+
+            EventQueue eventQueue = toolkit.getSystemEventQueueImpl();
+            
+            if (src != null) {
+                eventQueue.postEvent(new KeyEvent(src, id, time, modifiers,
+                        code, keyChar, location));
+                // KEY_TYPED goes after KEY_PRESSED
+                if (id == KeyEvent.KEY_PRESSED) {
+                    for (int i = 0; i < charsLength; i++) {
+                        keyChar = chars.charAt(i);
+                        if (keyChar != KeyEvent.CHAR_UNDEFINED) {
+                            eventQueue.postEvent(new KeyEvent(src,
+                                    KeyEvent.KEY_TYPED, time, modifiers,
+                                    KeyEvent.VK_UNDEFINED, keyChar,
+                                    KeyEvent.KEY_LOCATION_UNKNOWN));
+                        }
+                    }
+                }
+            }
+
+            return false;
+        }
+
+    }
+
+    /**
+     * Retargets the mouse events to the grab owner when mouse is grabbed,
+     * grab and ungrab mouse when mouse buttons are pressed and released
+     */
+
+    static final class MouseGrabManager {
+
+        /** 
+         * The top-level window holding the mouse grab 
+         * that was explicitly started by startGrab() method
+         */
+        //???AWT: private Window nativeGrabOwner = null;
+        /** 
+         * The component that owns the synthetic 
+         * mouse grab while at least one of the
+         * mouse buttons is pressed
+         */
+        private Component syntheticGrabOwner = null;
+
+        /**
+         * Previous value of syntheticGrabOwner
+         */
+        private Component lastSyntheticGrabOwner = null;
+
+        /**
+         * Number of mouse buttons currently pressed
+         */
+        private int syntheticGrabDepth = 0;
+
+        /**
+         * The callback to be called when the explicit mouse grab ends
+         */
+        private Runnable whenCanceled;
+
+        /**
+         * Explicitly start the mouse grab
+         * @param grabWindow - the window that will own the grab
+         * @param whenCanceled - the callback to call when the grab ends. 
+         * This parameter can be null
+         */
+        //???AWT
+        /*
+        void startGrab(Window grabWindow, Runnable whenCanceled) {
+
+            if (nativeGrabOwner != null) {
+                // awt.12F=Attempt to start nested mouse grab
+                throw new RuntimeException(Messages.getString("awt.12F")); //$NON-NLS-1$
+            }
+
+            NativeWindow win = grabWindow.getNativeWindow();
+            if (win == null) {
+                // awt.130=Attempt to grab mouse in not displayable window
+                throw new RuntimeException(Messages.getString("awt.130")); //$NON-NLS-1$
+            }
+
+            nativeGrabOwner = grabWindow;
+            this.whenCanceled = whenCanceled;
+            win.grabMouse();
+        }
+        */
+
+        /**
+         * Ends the explicit mouse grab. If the non-null callback was provided
+         * in the startGrab() method, this callback is called 
+         */
+        void endGrab() {
+            //???AWT
+            /*
+            if (nativeGrabOwner == null) {
+                return;
+            }
+
+            Window grabWindow = nativeGrabOwner;
+            nativeGrabOwner = null;
+            NativeWindow win = grabWindow.getNativeWindow();
+
+            if (win != null) {
+                win.ungrabMouse();
+                if (whenCanceled != null) {
+                    whenCanceled.run();
+                    whenCanceled = null;
+                }
+            }
+            */
+        }
+
+        /**
+         * Ends both explicit and synthetic grans 
+         * @return - always returns false
+         */
+        boolean onGrabCanceled() {
+            endGrab();
+            resetSyntheticGrab();
+
+            return false;
+        }
+
+        /**
+         * Starts the synthetic mouse grab, increases the counter 
+         * of currently pressed mouse buttons
+         * @param source - the component where mouse press event occured
+         * @return - the component that owns the synthetic grab
+         */
+        Component onMousePressed(Component source) {
+            if (syntheticGrabDepth == 0) {
+                syntheticGrabOwner = source;
+                lastSyntheticGrabOwner = source;
+            }
+            syntheticGrabDepth++;
+
+            return syntheticGrabOwner;
+        }
+
+        /**
+         * Decreases the counter of currently pressed mouse buttons,
+         * ends the synthetic mouse grab, when this counter becomes zero
+         * @param source - the component where mouse press event occured
+         * @return - the component that owns the synthetic grab, 
+         * or source parameter if mouse grab was released
+         */
+        Component onMouseReleased(Component source) {
+            Component ret = source;
+
+            //???AWT
+            /*
+            if (syntheticGrabOwner != null && nativeGrabOwner == null) {
+                ret = syntheticGrabOwner;
+            }
+            */
+            syntheticGrabDepth--;
+            if (syntheticGrabDepth <= 0) {
+                resetSyntheticGrab();
+                lastSyntheticGrabOwner = null;
+            }
+
+            return ret;
+        }
+
+        /**
+         * Update the state of synthetic ouse gram 
+         * when the mouse is moved/dragged
+         * @param event - the native event
+         */
+        void preprocessEvent(NativeEvent event) {
+            int id = event.getEventId();
+            switch (id) {
+            case MouseEvent.MOUSE_MOVED:
+                if (syntheticGrabOwner != null) {
+                    syntheticGrabOwner = null;
+                    syntheticGrabDepth = 0;
+                }
+                if (lastSyntheticGrabOwner != null) {
+                    lastSyntheticGrabOwner = null;
+                }
+            case MouseEvent.MOUSE_DRAGGED:
+                if (syntheticGrabOwner == null
+                        && lastSyntheticGrabOwner != null) {
+                    syntheticGrabOwner = lastSyntheticGrabOwner;
+                    syntheticGrabDepth = 0;
+                    int mask = event.getInputModifiers();
+                    syntheticGrabDepth += (mask & InputEvent.BUTTON1_DOWN_MASK) != 0 ? 1
+                            : 0;
+                    syntheticGrabDepth += (mask & InputEvent.BUTTON2_DOWN_MASK) != 0 ? 1
+                            : 0;
+                    syntheticGrabDepth += (mask & InputEvent.BUTTON3_DOWN_MASK) != 0 ? 1
+                            : 0;
+                }
+            }
+        }
+
+        /**
+         * @return the component that currently owns the synthetic grab 
+         */
+        Component getSyntheticGrabOwner() {
+            return syntheticGrabOwner;
+        }
+
+        /**
+         * ends synthetic grab
+         */
+        private void resetSyntheticGrab() {
+            syntheticGrabOwner = null;
+            syntheticGrabDepth = 0;
+        }
+
+    }
+    
+    /**
+     * Dispatches native events related to the pop-up boxes 
+     * (the non-component windows such as menus and drop lists)
+     */
+//    final class PopupDispatcher {
+//
+//        private PopupBox activePopup;
+//
+//        private PopupBox underCursor;
+//
+//        private final MouseGrab grab = new MouseGrab();
+//
+//        /**
+//         * Handles the mouse grab for pop-up boxes
+//         */
+//        private final class MouseGrab {
+//            private int depth;
+//
+//            private PopupBox owner;
+//
+//            private final Point start = new Point();
+//
+//            /**
+//             * Starts the grab when mouse is pressed
+//             * @param src - the pop-up box where mouse event has occured
+//             * @param where - the mouse pointer location
+//             * @return - the grab owner
+//             */
+//            PopupBox mousePressed(PopupBox src, Point where) {
+//                if (depth == 0) {
+//                    owner = src;
+//                    start.setLocation(where);
+//                }
+//                depth++;
+//                return owner;
+//            }
+//
+//            /**
+//             * Ends the grab when all mousebuttons are released
+//             * @param src - the pop-up box where mouse event has occured
+//             * @param where - the mouse pointer location
+//             * @return - the grab owner, or src parameter if the grab has ended
+//             */
+//            PopupBox mouseReleased(PopupBox src, Point where) {
+//                PopupBox ret = (owner != null) ? owner : src;
+//                if (depth == 0) {
+//                    return ret;
+//                }
+//                depth--;
+//                if (depth == 0) {
+//                    PopupBox tgt = owner;
+//                    owner = null;
+//                    if (tgt != null && src == null) {
+//                        Point a = new Point(start);
+//                        Point b = new Point(where);
+//                        Point pos = tgt.getScreenLocation();
+//                        a.translate(-pos.x, -pos.y);
+//                        b.translate(-pos.x, -pos.y);
+//                        if (tgt.closeOnUngrab(a, b)) {
+//                            return null;
+//                        }
+//                    }
+//                }
+//                return ret;
+//            }
+//
+//            /**
+//             * Set the grab owner to null
+//             */
+//            void reset() {
+//                depth = 0;
+//                owner = null;
+//                start.setLocation(0, 0);
+//            }
+//
+//            /**
+//             * @return - the pop-up box currently owning the grab
+//             */
+//            public PopupBox getOwner() {
+//                return owner;
+//            }
+//        }
+//
+//        /**
+//         * Call the mouse event handler of the pop-up box
+//         * @param src - the pop-up box where the mouse event occured
+//         * @param eventId - the event ID, one of MouseEvent.MOUSE_* constants
+//         * @param where - the mouse pointer location
+//         * @param event - native event
+//         */
+//        private void mouseEvent(PopupBox src, int eventId, Point where,
+//                NativeEvent event) {
+//            Point pos = src.getScreenLocation();
+//            pos.setLocation(where.x - pos.x, where.y - pos.y);
+//
+//            src.onMouseEvent(eventId, pos, event.getMouseButton(), event
+//                    .getTime(), event.getInputModifiers(), event
+//                    .getWheelRotation());
+//        }
+//
+//        /**
+//         * Handle the native event targeted by a pop-up box. This could be 
+//         * paint event, mouse or keyboard event.
+//         * @param event - the native event
+//         * @return - false if the event was handled and doesn't 
+//         * need the further processing; true when the further 
+//         * processing is needed
+//         */
+//        boolean onEvent(NativeEvent event) {
+//            PopupBox src = toolkit.getPopupBoxById(event.getWindowId());
+//            int id = event.getEventId();
+//
+//            if ((id == PaintEvent.PAINT)) {
+//                if (src != null) {
+//                    src.paint(event.getClipRects());
+//                    return true;
+//                }
+//                Component c = toolkit.getComponentById(event.getWindowId());
+//                if ((c != null) && (c instanceof Frame)) {
+//                    ((Frame) c).paintMenuBar(event.getClipRects());
+//                }
+//                return false;
+//            }
+//
+//            if ((id >= MouseEvent.MOUSE_FIRST) && (id <= MouseEvent.MOUSE_LAST)) {
+//                Point where = event.getScreenPos();
+//
+//                if (src != underCursor) {
+//                    if (underCursor != null) {
+//                        mouseEvent(underCursor, MouseEvent.MOUSE_EXITED, where,
+//                                event);
+//                    }
+//                    underCursor = src;
+//                    if (underCursor != null) {
+//                        mouseEvent(underCursor, MouseEvent.MOUSE_ENTERED,
+//                                where, event);
+//                        underCursor.setDefaultCursor();
+//                    }
+//                }
+//                if (id == MouseEvent.MOUSE_EXITED) {
+//                    underCursor = null;
+//                }
+//
+//                if ((activePopup == null) && (src == null || !src.isMenuBar())) {
+//                    return false;
+//                }
+//
+//                if (id == MouseEvent.MOUSE_PRESSED) {
+//                    src = grab.mousePressed(src, where);
+//                } else if (id == MouseEvent.MOUSE_RELEASED) {
+//                    src = grab.mouseReleased(src, where);
+//                } else if (src == null) {
+//                    src = grab.getOwner();
+//                }
+//
+//                PopupBox wasActive = activePopup;
+//
+//                if (src != null) {
+//                    mouseEvent(src, id, where, event);
+//                    return src.isMenu() || src.contains(where);
+//                }
+//
+//                if (wasActive != null && activePopup == null) {
+//                    return wasActive.isMenu();
+//                }
+//
+//                if ((id == MouseEvent.MOUSE_PRESSED)
+//                        || (id == MouseEvent.MOUSE_RELEASED)) {
+//                    boolean isMenu = activePopup.isMenu();
+//                    deactivateAll();
+//                    return !isMenu;
+//                }
+//                return true;
+//            }
+//
+//            if (activePopup == null) {
+//                return false;
+//            }
+//
+//            if ((id >= KeyEvent.KEY_FIRST) && (id <= KeyEvent.KEY_LAST)) {
+//                boolean isMenu = activePopup.isMenu();
+//                activePopup.dispatchKeyEvent(id, event.getVKey(), event
+//                        .getTime(), event.getInputModifiers());
+//
+//                return isMenu;
+//            }
+//
+//            return false;
+//        }
+//
+//        /**
+//         * Remember the pop-up as active and grab the mouse on it
+//         * @param popup - the pop-up box to activate
+//         */
+//        void activate(final PopupBox popup) {
+//            if (activePopup == null) {
+//
+//                activePopup = popup;
+//                mouseGrabManager.startGrab(popup.getOwner(), new Runnable() {
+//                    public void run() {
+//                        deactivate(popup);
+//                    }
+//                });
+//            }
+//        }
+//
+//        /**
+//         * Deactivate the currently active pop-up box
+//         */
+//        void deactivateAll() {
+//            deactivate(activePopup);
+//        }
+//
+//        /**
+//         * Deactivate the pop-up box, end the mouse grab
+//         */
+//        void deactivate(PopupBox popup) {
+//            grab.reset();
+//
+//            if (activePopup != null && activePopup == popup) {
+//                activePopup = null;
+//                mouseGrabManager.endGrab();
+//                popup.hide();
+//                underCursor = null;
+//            }
+//        }
+//
+//        /**
+//         * Check that the pop-up box is currently active
+//         * @param popup - the pop-up box to check
+//         * @return - true if active
+//         */
+//        boolean isActive(PopupBox popup) {
+//            return (popup == activePopup) && (popup != null);
+//        }
+//    }
+
+}
\ No newline at end of file
diff --git a/awt/java/awt/DisplayMode.java b/awt/java/awt/DisplayMode.java
new file mode 100644
index 0000000..8021010
--- /dev/null
+++ b/awt/java/awt/DisplayMode.java
@@ -0,0 +1,165 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+/**
+ * The DisplayMode class contains the bit depth, height, width and refresh rate
+ * of a GraphicsDevice.
+ * 
+ * @since Android 1.0
+ */
+public final class DisplayMode {
+
+    /**
+     * The width.
+     */
+    private final int width;
+
+    /**
+     * The height.
+     */
+    private final int height;
+
+    /**
+     * The bit depth.
+     */
+    private final int bitDepth;
+
+    /**
+     * The refresh rate.
+     */
+    private final int refreshRate;
+
+    /**
+     * The Constant Value BIT_DEPTH_MULTI indicates the bit depth
+     */
+
+    public static final int BIT_DEPTH_MULTI = -1;
+
+    /**
+     * The Constant REFRESH_RATE_UNKNOWN indicates the refresh rate.
+     */
+    public static final int REFRESH_RATE_UNKNOWN = 0;
+
+    /**
+     * Creates a new DisplayMode object with the specified parameters.
+     * 
+     * @param width
+     *            the width of the display.
+     * @param height
+     *            the height of the display.
+     * @param bitDepth
+     *            the bit depth of the display.
+     * @param refreshRate
+     *            the refresh rate of the display.
+     */
+
+    public DisplayMode(int width, int height, int bitDepth, int refreshRate) {
+        this.width = width;
+        this.height = height;
+        this.bitDepth = bitDepth;
+        this.refreshRate = refreshRate;
+    }
+
+    /**
+     * Compares if this DisplayMode is equal to the specified object or not.
+     * 
+     * @param dm
+     *            the Object to be compared.
+     * @return true, if the specified object is a DisplayMode with the same data
+     *         values as this DisplayMode, false otherwise.
+     */
+
+    @Override
+    public boolean equals(Object dm) {
+        if (dm instanceof DisplayMode) {
+            return equals((DisplayMode)dm);
+        }
+        return false;
+    }
+
+    /**
+     * Compares if this DisplayMode is equal to the specified DisplayMode object
+     * or not.
+     * 
+     * @param dm
+     *            the DisplayMode to be compared.
+     * @return true, if all of the data values of this DisplayMode are equal to
+     *         the values of the specified DisplayMode object, false otherwise.
+     */
+    public boolean equals(DisplayMode dm) {
+        if (dm == null) {
+            return false;
+        }
+        if (dm.bitDepth != bitDepth) {
+            return false;
+        }
+        if (dm.refreshRate != refreshRate) {
+            return false;
+        }
+        if (dm.width != width) {
+            return false;
+        }
+        if (dm.height != height) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Gets the bit depth of the DisplayMode, returns BIT_DEPTH_MULTI value if
+     * multiple bit depths are supported in this display mode.
+     * 
+     * @return the bit depth of the DisplayMode.
+     */
+    public int getBitDepth() {
+        return bitDepth;
+    }
+
+    /**
+     * Gets the height of the DisplayMode.
+     * 
+     * @return the height of the DisplayMode.
+     */
+    public int getHeight() {
+        return height;
+    }
+
+    /**
+     * Gets the refresh rate of the DisplayMode, returns REFRESH_RATE_UNKNOWN
+     * value if the information is not available.
+     * 
+     * @return the refresh rate of the DisplayMode.
+     */
+    public int getRefreshRate() {
+        return refreshRate;
+    }
+
+    /**
+     * Gets the width of the DisplayMode.
+     * 
+     * @return the width of the DisplayMode.
+     */
+    public int getWidth() {
+        return width;
+    }
+}
diff --git a/awt/java/awt/Event.java b/awt/java/awt/Event.java
new file mode 100644
index 0000000..226a61f
--- /dev/null
+++ b/awt/java/awt/Event.java
@@ -0,0 +1,596 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.io.Serializable;
+
+/**
+ * The Event class is obsolete and has been replaced by AWTEvent class.
+ * 
+ * @since Android 1.0
+ */
+public class Event implements Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 5488922509400504703L;
+
+    /**
+     * The Constant SHIFT_MASK indicates that the Shift key is down when the
+     * event occurred.
+     */
+    public static final int SHIFT_MASK = 1;
+
+    /**
+     * The Constant CTRL_MASK indicates that the Control key is down when the
+     * event occurred.
+     */
+    public static final int CTRL_MASK = 2;
+
+    /**
+     * The Constant META_MASK indicates that the Meta key is down when t he
+     * event occurred (or the right mouse button).
+     */
+    public static final int META_MASK = 4;
+
+    /**
+     * The Constant ALT_MASK indicates that the Alt key is down when the event
+     * occurred (or the middle mouse button).
+     */
+    public static final int ALT_MASK = 8;
+
+    /**
+     * The Constant HOME indicates Home key.
+     */
+    public static final int HOME = 1000;
+
+    /**
+     * The Constant END indicates End key.
+     */
+    public static final int END = 1001;
+
+    /**
+     * The Constant PGUP indicates Page Up key.
+     */
+    public static final int PGUP = 1002;
+
+    /**
+     * The Constant PGDN indicates Page Down key.
+     */
+    public static final int PGDN = 1003;
+
+    /**
+     * The Constant UP indicates Up key.
+     */
+    public static final int UP = 1004;
+
+    /**
+     * The Constant DOWN indicates Down key.
+     */
+    public static final int DOWN = 1005;
+
+    /**
+     * The Constant LEFT indicates Left key.
+     */
+    public static final int LEFT = 1006;
+
+    /**
+     * The Constant RIGHT indicates Right key.
+     */
+    public static final int RIGHT = 1007;
+
+    /**
+     * The Constant F1 indicates F1 key.
+     */
+    public static final int F1 = 1008;
+
+    /**
+     * The Constant F2 indicates F2 key.
+     */
+    public static final int F2 = 1009;
+
+    /**
+     * The Constant F3 indicates F3 key.
+     */
+    public static final int F3 = 1010;
+
+    /**
+     * The Constant F4 indicates F4 key.
+     */
+    public static final int F4 = 1011;
+
+    /**
+     * The Constant F5 indicates F5 key.
+     */
+    public static final int F5 = 1012;
+
+    /**
+     * The Constant F6 indicates F6 key.
+     */
+    public static final int F6 = 1013;
+
+    /**
+     * The Constant F7 indicates F7 key.
+     */
+    public static final int F7 = 1014;
+
+    /**
+     * The Constant F8 indicates F8 key.
+     */
+    public static final int F8 = 1015;
+
+    /**
+     * The Constant F9 indicates F9 key.
+     */
+    public static final int F9 = 1016;
+
+    /**
+     * The Constant F10 indicates F10 key.
+     */
+    public static final int F10 = 1017;
+
+    /**
+     * The Constant F11 indicates F11 key.
+     */
+    public static final int F11 = 1018;
+
+    /**
+     * The Constant F12 indicates F12 key.
+     */
+    public static final int F12 = 1019;
+
+    /**
+     * The Constant PRINT_SCREEN indicates Print Screen key.
+     */
+    public static final int PRINT_SCREEN = 1020;
+
+    /**
+     * The Constant SCROLL_LOCK indicates Scroll Lock key.
+     */
+    public static final int SCROLL_LOCK = 1021;
+
+    /**
+     * The Constant CAPS_LOCK indicates Caps Lock key.
+     */
+    public static final int CAPS_LOCK = 1022;
+
+    /**
+     * The Constant NUM_LOCK indicates Num Lock key.
+     */
+    public static final int NUM_LOCK = 1023;
+
+    /**
+     * The Constant PAUSE indicates Pause key.
+     */
+    public static final int PAUSE = 1024;
+
+    /**
+     * The Constant INSERT indicates Insert key.
+     */
+    public static final int INSERT = 1025;
+
+    /**
+     * The Constant ENTER indicates Enter key.
+     */
+    public static final int ENTER = 10;
+
+    /**
+     * The Constant BACK_SPACE indicates Back Space key.
+     */
+    public static final int BACK_SPACE = 8;
+
+    /**
+     * The Constant TAB indicates TAb key.
+     */
+    public static final int TAB = 9;
+
+    /**
+     * The Constant ESCAPE indicates Escape key.
+     */
+    public static final int ESCAPE = 27;
+
+    /**
+     * The Constant DELETE indicates Delete key.
+     */
+    public static final int DELETE = 127;
+
+    /**
+     * The Constant WINDOW_DESTROY indicates an event when the user has asked
+     * the window manager to kill the window.
+     */
+    public static final int WINDOW_DESTROY = 201;
+
+    /**
+     * The Constant WINDOW_EXPOSE indicates an event when the user has asked the
+     * window manager to expose the window.
+     */
+    public static final int WINDOW_EXPOSE = 202;
+
+    /**
+     * The Constant WINDOW_ICONIFY indicates an event when the user has asked
+     * the window manager to iconify the window.
+     */
+    public static final int WINDOW_ICONIFY = 203;
+
+    /**
+     * The Constant WINDOW_DEICONIFY indicates an event when the user has asked
+     * the window manager to deiconify the window.
+     */
+    public static final int WINDOW_DEICONIFY = 204;
+
+    /**
+     * The Constant WINDOW_MOVED indicates an event when the user has asked the
+     * window manager to move the window.
+     */
+    public static final int WINDOW_MOVED = 205;
+
+    /**
+     * The Constant KEY_PRESS indicates an event when the user presses a normal
+     * key.
+     */
+    public static final int KEY_PRESS = 401;
+
+    /**
+     * The Constant KEY_RELEASE indicates an event when the user releases a
+     * normal key.
+     */
+    public static final int KEY_RELEASE = 402;
+
+    /**
+     * The Constant KEY_ACTION indicates an event when the user pressed a
+     * non-ASCII action key.
+     */
+    public static final int KEY_ACTION = 403;
+
+    /**
+     * The Constant KEY_ACTION_RELEASE indicates an event when the user released
+     * a non-ASCII action key.
+     */
+    public static final int KEY_ACTION_RELEASE = 404;
+
+    /**
+     * The Constant MOUSE_DOWN indicates an event when the user has pressed the
+     * mouse button.
+     */
+    public static final int MOUSE_DOWN = 501;
+
+    /**
+     * The Constant MOUSE_UP indicates an event when the user has released the
+     * mouse button.
+     */
+    public static final int MOUSE_UP = 502;
+
+    /**
+     * The Constant MOUSE_MOVE indicates an event when the user has moved the
+     * mouse with no button pressed.
+     */
+    public static final int MOUSE_MOVE = 503;
+
+    /**
+     * The Constant MOUSE_ENTER indicates an event when the mouse has entered a
+     * component.
+     */
+    public static final int MOUSE_ENTER = 504;
+
+    /**
+     * The Constant MOUSE_EXIT indicates an event when the mouse has exited a
+     * component.
+     */
+    public static final int MOUSE_EXIT = 505;
+
+    /**
+     * The Constant MOUSE_DRAG indicates an event when the user has moved a
+     * mouse with the pressed button.
+     */
+    public static final int MOUSE_DRAG = 506;
+
+    /**
+     * The Constant SCROLL_LINE_UP indicates an event when the user has
+     * activated line-up area of scrollbar.
+     */
+    public static final int SCROLL_LINE_UP = 601;
+
+    /**
+     * The Constant SCROLL_LINE_DOWN indicates an event when the user has
+     * activated line-down area of scrollbar.
+     */
+    public static final int SCROLL_LINE_DOWN = 602;
+
+    /**
+     * The Constant SCROLL_PAGE_UP indicates an event when the user has
+     * activated page up area of scrollbar.
+     */
+    public static final int SCROLL_PAGE_UP = 603;
+
+    /**
+     * The Constant SCROLL_PAGE_DOWN indicates an event when the user has
+     * activated page down area of scrollbar.
+     */
+    public static final int SCROLL_PAGE_DOWN = 604;
+
+    /**
+     * The Constant SCROLL_ABSOLUTE indicates an event when the user has moved
+     * the bubble in a scroll bar.
+     */
+    public static final int SCROLL_ABSOLUTE = 605;
+
+    /**
+     * The Constant SCROLL_BEGIN indicates a scroll begin event.
+     */
+    public static final int SCROLL_BEGIN = 606;
+
+    /**
+     * The Constant SCROLL_END indicates a scroll end event.
+     */
+    public static final int SCROLL_END = 607;
+
+    /**
+     * The Constant LIST_SELECT indicates that an item in a list has been
+     * selected.
+     */
+    public static final int LIST_SELECT = 701;
+
+    /**
+     * The Constant LIST_DESELECT indicates that an item in a list has been
+     * unselected.
+     */
+    public static final int LIST_DESELECT = 702;
+
+    /**
+     * The Constant ACTION_EVENT indicates that the user wants some action to
+     * occur.
+     */
+    public static final int ACTION_EVENT = 1001;
+
+    /**
+     * The Constant LOAD_FILE indicates a file loading event.
+     */
+    public static final int LOAD_FILE = 1002;
+
+    /**
+     * The Constant SAVE_FILE indicates a file saving event.
+     */
+    public static final int SAVE_FILE = 1003;
+
+    /**
+     * The Constant GOT_FOCUS indicates that a component got the focus.
+     */
+    public static final int GOT_FOCUS = 1004;
+
+    /**
+     * The Constant LOST_FOCUS indicates that the component lost the focus.
+     */
+    public static final int LOST_FOCUS = 1005;
+
+    /**
+     * The target is the component with which the event is associated.
+     */
+    public Object target;
+
+    /**
+     * The when is timestamp when event has occured.
+     */
+    public long when;
+
+    /**
+     * The id indicates the type of the event.
+     */
+    public int id;
+
+    /**
+     * The x coordinate of event.
+     */
+    public int x;
+
+    /**
+     * The y coordinate of event.
+     */
+    public int y;
+
+    /**
+     * The key code of key event.
+     */
+    public int key;
+
+    /**
+     * The state of the modifier keys (given by a bitmask).
+     */
+    public int modifiers;
+
+    /**
+     * The click count indicates the number of consecutive clicks.
+     */
+    public int clickCount;
+
+    /**
+     * The argument of the event.
+     */
+    public Object arg;
+
+    /**
+     * The next event.
+     */
+    public Event evt;
+
+    /**
+     * Instantiates a new event with the specified target component, event type,
+     * and argument.
+     * 
+     * @param target
+     *            the target component.
+     * @param id
+     *            the event type.
+     * @param arg
+     *            the argument.
+     */
+    public Event(Object target, int id, Object arg) {
+        this(target, 0l, id, 0, 0, 0, 0, arg);
+    }
+
+    /**
+     * Instantiates a new event with the specified target component, time stamp,
+     * event type, x and y coordinates, keyboard key, state of the modifier
+     * keys, and an argument set to null.
+     * 
+     * @param target
+     *            the target component.
+     * @param when
+     *            the time stamp.
+     * @param id
+     *            the event type.
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     * @param key
+     *            the key.
+     * @param modifiers
+     *            the modifier keys state.
+     */
+    public Event(Object target, long when, int id, int x, int y, int key, int modifiers) {
+        this(target, when, id, x, y, key, modifiers, null);
+    }
+
+    /**
+     * Instantiates a new event with the specified target component, time stamp,
+     * event type, x and y coordinates, keyboard key, state of the modifier
+     * keys, and an argument.
+     * 
+     * @param target
+     *            the target component.
+     * @param when
+     *            the time stamp.
+     * @param id
+     *            the event type.
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     * @param key
+     *            the key.
+     * @param modifiers
+     *            the modifier keys state.
+     * @param arg
+     *            the specified argument.
+     */
+    public Event(Object target, long when, int id, int x, int y, int key, int modifiers, Object arg) {
+        this.target = target;
+        this.when = when;
+        this.id = id;
+        this.x = x;
+        this.y = y;
+        this.key = key;
+        this.modifiers = modifiers;
+        this.arg = arg;
+    }
+
+    /**
+     * Returns a string representation of this Event.
+     * 
+     * @return a string representation of this Event.
+     */
+    @Override
+    public String toString() {
+        /*
+         * The format is based on 1.5 release behavior which can be revealed by
+         * the following code: Event e = new Event(new Button(), 0l,
+         * Event.KEY_PRESS, 0, 0, Event.TAB, Event.SHIFT_MASK, "arg");
+         * System.out.println(e);
+         */
+
+        return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+    /**
+     * Returns a string representing the state of this Event.
+     * 
+     * @return a string representing the state of this Event.
+     */
+    protected String paramString() {
+        return "id=" + id + ",x=" + x + ",y=" + y + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                (key != 0 ? ",key=" + key + getModifiersString() : "") + //$NON-NLS-1$ //$NON-NLS-2$
+                ",target=" + target + //$NON-NLS-1$
+                (arg != null ? ",arg=" + arg : ""); //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+    /**
+     * Gets a string representation of the modifiers.
+     * 
+     * @return a string representation of the modifiers.
+     */
+    private String getModifiersString() {
+        String strMod = ""; //$NON-NLS-1$
+        if (shiftDown()) {
+            strMod += ",shift"; //$NON-NLS-1$
+        }
+        if (controlDown()) {
+            strMod += ",control"; //$NON-NLS-1$
+        }
+        if (metaDown()) {
+            strMod += ",meta"; //$NON-NLS-1$
+        }
+        return strMod;
+    }
+
+    /**
+     * Translates x and y coordinates of his event to the x+dx and x+dy
+     * coordinates.
+     * 
+     * @param dx
+     *            the distance by which the event's x coordinate is increased.
+     * @param dy
+     *            the distance by which the event's y coordinate is increased.
+     */
+    public void translate(int dx, int dy) {
+        x += dx;
+        y += dy;
+    }
+
+    /**
+     * Checks if Control key is down or not.
+     * 
+     * @return true, if Control key is down; false otherwise.
+     */
+    public boolean controlDown() {
+        return (modifiers & CTRL_MASK) != 0;
+    }
+
+    /**
+     * Checks if Meta key is down or not.
+     * 
+     * @return true, if Meta key is down; false otherwise.
+     */
+    public boolean metaDown() {
+        return (modifiers & META_MASK) != 0;
+    }
+
+    /**
+     * Checks if Shift key is down or not.
+     * 
+     * @return true, if Shift key is down; false otherwise.
+     */
+    public boolean shiftDown() {
+        return (modifiers & SHIFT_MASK) != 0;
+    }
+
+}
diff --git a/awt/java/awt/EventDispatchThread.java b/awt/java/awt/EventDispatchThread.java
new file mode 100644
index 0000000..442c8a2
--- /dev/null
+++ b/awt/java/awt/EventDispatchThread.java
@@ -0,0 +1,118 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov, Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import org.apache.harmony.awt.wtk.NativeEvent;
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+
+class EventDispatchThread extends Thread  {
+    
+    private static final class MarkerEvent extends AWTEvent {
+        MarkerEvent(Object source, int id) {
+            super(source, id);
+        }
+    }
+
+    final Dispatcher dispatcher;
+    final Toolkit toolkit;
+    private NativeEventQueue nativeQueue;
+
+    protected volatile boolean shutdownPending = false;
+
+    /**
+     * Initialise and run the main event loop
+     */
+    @Override
+    public void run() {
+        nativeQueue = toolkit.getNativeEventQueue();
+
+        try {
+            runModalLoop(null);
+        } finally {
+            toolkit.shutdownWatchdog.forceShutdown();
+        }
+    }
+
+    void runModalLoop(ModalContext context) {
+        long lastPaintTime = System.currentTimeMillis();
+        while (!shutdownPending && (context == null || context.isModalLoopRunning())) {
+            try {
+            EventQueue eventQueue = toolkit.getSystemEventQueueImpl();
+
+            NativeEvent ne = nativeQueue.getNextEvent();
+            if (ne != null) {
+                dispatcher.onEvent(ne);
+                MarkerEvent marker = new MarkerEvent(this, 0);
+                eventQueue.postEvent(marker);
+                for (AWTEvent ae = eventQueue.getNextEventNoWait(); 
+                        (ae != null) && (ae != marker); 
+                        ae = eventQueue.getNextEventNoWait()) {
+                    eventQueue.dispatchEvent(ae);
+                }
+            } else {
+                toolkit.shutdownWatchdog.setNativeQueueEmpty(true);
+                AWTEvent ae = eventQueue.getNextEventNoWait();
+                if (ae != null) {
+                    eventQueue.dispatchEvent(ae);
+                    long curTime = System.currentTimeMillis();
+                    if (curTime - lastPaintTime > 10) {
+                        toolkit.onQueueEmpty();
+                        lastPaintTime = System.currentTimeMillis();
+                    }
+                } else {
+                    toolkit.shutdownWatchdog.setAwtQueueEmpty(true);
+                    toolkit.onQueueEmpty();
+                    lastPaintTime = System.currentTimeMillis();
+                    waitForAnyEvent();
+                }
+            }
+            } catch (Throwable t) {
+                // TODO: Exception handler should be implemented
+                // t.printStackTrace();
+            }
+        }
+    }
+    
+    private void waitForAnyEvent() {
+        EventQueue eventQueue = toolkit.getSystemEventQueueImpl();
+        if (!eventQueue.isEmpty() || !nativeQueue.isEmpty()) {
+            return;
+        }
+        Object eventMonitor = nativeQueue.getEventMonitor();
+        synchronized(eventMonitor) {
+            try {
+                eventMonitor.wait();
+            } catch (InterruptedException e) {}
+        }
+    }
+
+    void shutdown() {
+        shutdownPending = true;
+    }
+
+    EventDispatchThread(Toolkit toolkit, Dispatcher dispatcher ) {
+        this.toolkit = toolkit;
+        this.dispatcher = dispatcher;
+        setName("AWT-EventDispatchThread"); //$NON-NLS-1$
+        setDaemon(true);
+    }
+
+}
diff --git a/awt/java/awt/EventQueue.java b/awt/java/awt/EventQueue.java
new file mode 100644
index 0000000..126a593
--- /dev/null
+++ b/awt/java/awt/EventQueue.java
@@ -0,0 +1,320 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov, Pavel Dolgov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.event.InvocationEvent;
+import java.lang.reflect.InvocationTargetException;
+import java.util.EmptyStackException;
+
+/**
+ * The EventQueue class manages events. It is a platform-independent class that
+ * queues events both from the underlying peer classes and from trusted
+ * application classes.
+ * 
+ * @since Android 1.0
+ */
+public class EventQueue {
+
+    /**
+     * The core ref.
+     */
+    private final EventQueueCoreAtomicReference coreRef = new EventQueueCoreAtomicReference();
+
+    /**
+     * The Class EventQueueCoreAtomicReference.
+     */
+    private static final class EventQueueCoreAtomicReference {
+
+        /**
+         * The core.
+         */
+        private EventQueueCore core;
+
+        /* synchronized */
+        /**
+         * Gets the.
+         * 
+         * @return the event queue core.
+         */
+        EventQueueCore get() {
+            return core;
+        }
+
+        /* synchronized */
+        /**
+         * Sets the.
+         * 
+         * @param newCore
+         *            the new core.
+         */
+        void set(EventQueueCore newCore) {
+            core = newCore;
+        }
+    }
+
+    /**
+     * Returns true if the calling thread is the current AWT EventQueue's
+     * dispatch thread.
+     * 
+     * @return true, if the calling thread is the current AWT EventQueue's
+     *         dispatch thread; false otherwise.
+     */
+    public static boolean isDispatchThread() {
+        return Thread.currentThread() instanceof EventDispatchThread;
+    }
+
+    /**
+     * Posts an InvocationEvent which executes the run() method on a Runnable
+     * when dispatched by the AWT event dispatcher thread.
+     * 
+     * @param runnable
+     *            the Runnable whose run method should be executed synchronously
+     *            on the EventQueue.
+     */
+    public static void invokeLater(Runnable runnable) {
+        Toolkit toolkit = Toolkit.getDefaultToolkit();
+        InvocationEvent event = new InvocationEvent(toolkit, runnable);
+        toolkit.getSystemEventQueueImpl().postEvent(event);
+    }
+
+    /**
+     * Posts an InvocationEvent which executes the run() method on a Runnable
+     * when dispatched by the AWT event dispatcher thread and the notifyAll
+     * method is called on it immediately after run returns.
+     * 
+     * @param runnable
+     *            the Runnable whose run method should be executed synchronously
+     *            on the EventQueue.
+     * @throws InterruptedException
+     *             if another thread has interrupted this thread.
+     * @throws InvocationTargetException
+     *             if an error occurred while running the runnable.
+     */
+    public static void invokeAndWait(Runnable runnable) throws InterruptedException,
+            InvocationTargetException {
+
+        if (isDispatchThread()) {
+            throw new Error();
+        }
+
+        final Toolkit toolkit = Toolkit.getDefaultToolkit();
+        final Object notifier = new Object(); // $NON-LOCK-1$
+        InvocationEvent event = new InvocationEvent(toolkit, runnable, notifier, true);
+
+        synchronized (notifier) {
+            toolkit.getSystemEventQueueImpl().postEvent(event);
+            notifier.wait();
+        }
+
+        Exception exception = event.getException();
+
+        if (exception != null) {
+            throw new InvocationTargetException(exception);
+        }
+    }
+
+    /**
+     * Gets the system event queue.
+     * 
+     * @return the system event queue.
+     */
+    private static EventQueue getSystemEventQueue() {
+        Thread th = Thread.currentThread();
+        if (th instanceof EventDispatchThread) {
+            return ((EventDispatchThread)th).toolkit.getSystemEventQueueImpl();
+        }
+        return null;
+    }
+
+    /**
+     * Gets the most recent event's timestamp. This event was dispatched from
+     * the EventQueue associated with the calling thread.
+     * 
+     * @return the timestamp of the last Event to be dispatched, or
+     *         System.currentTimeMillis() if this method is invoked from a
+     *         thread other than an event-dispatching thread.
+     */
+    public static long getMostRecentEventTime() {
+        EventQueue eq = getSystemEventQueue();
+        return (eq != null) ? eq.getMostRecentEventTimeImpl() : System.currentTimeMillis();
+    }
+
+    /**
+     * Gets the most recent event time impl.
+     * 
+     * @return the most recent event time impl.
+     */
+    private long getMostRecentEventTimeImpl() {
+        return getCore().getMostRecentEventTime();
+    }
+
+    /**
+     * Returns the the currently dispatched event by the EventQueue associated
+     * with the calling thread.
+     * 
+     * @return the currently dispatched event or null if this method is invoked
+     *         from a thread other than an event-dispatching thread.
+     */
+    public static AWTEvent getCurrentEvent() {
+        EventQueue eq = getSystemEventQueue();
+        return (eq != null) ? eq.getCurrentEventImpl() : null;
+    }
+
+    /**
+     * Gets the current event impl.
+     * 
+     * @return the current event impl.
+     */
+    private AWTEvent getCurrentEventImpl() {
+        return getCore().getCurrentEvent();
+    }
+
+    /**
+     * Instantiates a new event queue.
+     */
+    public EventQueue() {
+        setCore(new EventQueueCore(this));
+    }
+
+    /**
+     * Instantiates a new event queue.
+     * 
+     * @param t
+     *            the t.
+     */
+    EventQueue(Toolkit t) {
+        setCore(new EventQueueCore(this, t));
+    }
+
+    /**
+     * Posts a event to the EventQueue.
+     * 
+     * @param event
+     *            AWTEvent.
+     */
+    public void postEvent(AWTEvent event) {
+        event.isPosted = true;
+        getCore().postEvent(event);
+    }
+
+    /**
+     * Returns an event from the EventQueue and removes it from this queue.
+     * 
+     * @return the next AWTEvent.
+     * @throws InterruptedException
+     *             is thrown if another thread interrupts this thread.
+     */
+    public AWTEvent getNextEvent() throws InterruptedException {
+        return getCore().getNextEvent();
+    }
+
+    /**
+     * Gets the next event no wait.
+     * 
+     * @return the next event no wait.
+     */
+    AWTEvent getNextEventNoWait() {
+        return getCore().getNextEventNoWait();
+    }
+
+    /**
+     * Returns the first event of the EventQueue (without removing it from the
+     * queue).
+     * 
+     * @return the the first AWT event of the EventQueue.
+     */
+    public AWTEvent peekEvent() {
+        return getCore().peekEvent();
+    }
+
+    /**
+     * Returns the first event of the EventQueue with the specified ID (without
+     * removing it from the queue).
+     * 
+     * @param id
+     *            the type ID of event.
+     * @return the first event of the EventQueue with the specified ID.
+     */
+    public AWTEvent peekEvent(int id) {
+        return getCore().peekEvent(id);
+    }
+
+    /**
+     * Replaces the existing EventQueue with the specified EventQueue. Any
+     * pending events are transferred to the new EventQueue.
+     * 
+     * @param newEventQueue
+     *            the new event queue.
+     */
+    public void push(EventQueue newEventQueue) {
+        getCore().push(newEventQueue);
+    }
+
+    /**
+     * Stops dispatching events using this EventQueue. Any pending events are
+     * transferred to the previous EventQueue.
+     * 
+     * @throws EmptyStackException
+     *             is thrown if no previous push was made on this EventQueue.
+     */
+    protected void pop() throws EmptyStackException {
+        getCore().pop();
+    }
+
+    /**
+     * Dispatches the specified event.
+     * 
+     * @param event
+     *            the AWTEvent.
+     */
+    protected void dispatchEvent(AWTEvent event) {
+        getCore().dispatchEventImpl(event);
+    }
+
+    /**
+     * Checks if the queue is empty.
+     * 
+     * @return true, if is empty.
+     */
+    boolean isEmpty() {
+        return getCore().isEmpty();
+    }
+
+    /**
+     * Gets the core.
+     * 
+     * @return the core.
+     */
+    EventQueueCore getCore() {
+        return coreRef.get();
+    }
+
+    /**
+     * Sets the core.
+     * 
+     * @param newCore
+     *            the new core.
+     */
+    void setCore(EventQueueCore newCore) {
+        coreRef.set((newCore != null) ? newCore : new EventQueueCore(this));
+    }
+}
diff --git a/awt/java/awt/EventQueueCore.java b/awt/java/awt/EventQueueCore.java
new file mode 100644
index 0000000..ffc7c46
--- /dev/null
+++ b/awt/java/awt/EventQueueCore.java
@@ -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.
+ */
+/** 
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.InputMethodEvent;
+import java.awt.event.InvocationEvent;
+import java.awt.event.MouseEvent;
+import java.util.LinkedList;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The events storage for EventQueue
+ */
+final class EventQueueCore {
+    
+    private final LinkedList<EventQueue> queueStack = new LinkedList<EventQueue>();
+    private final LinkedList<AWTEvent> events = new LinkedList<AWTEvent>();
+    
+    private Toolkit toolkit;
+    private EventQueue activeQueue;
+    private Thread dispatchThread;
+    
+    AWTEvent currentEvent;
+    long mostRecentEventTime = System.currentTimeMillis();
+    
+    EventQueueCore(EventQueue eq) {
+        synchronized (this) {
+            queueStack.addLast(eq);
+            activeQueue = eq;
+        }
+    }
+
+    EventQueueCore(EventQueue eq, Toolkit t) {
+        synchronized (this) {
+            queueStack.addLast(eq);
+            activeQueue = eq;
+            setToolkit(t);
+        }
+    }
+
+    synchronized long getMostRecentEventTime() {
+        return mostRecentEventTime;
+    }
+    
+    synchronized AWTEvent getCurrentEvent() {
+        return currentEvent;
+    }
+    
+    synchronized boolean isSystemEventQueue() {
+        return toolkit != null;
+    }
+    
+    private void setToolkit(Toolkit t) {
+        toolkit = t;
+        if (toolkit != null) {
+            toolkit.setSystemEventQueueCore(this);
+            dispatchThread = toolkit.dispatchThread;
+        }
+    }
+
+    synchronized void postEvent(AWTEvent event) {
+        //???AWT
+        /*
+        events.addLast(event);
+        if ((toolkit == null) && (dispatchThread == null)) {
+            dispatchThread = new EventQueueThread(this);
+            dispatchThread.start();
+        }
+        // TODO: add event coalescing
+        if (toolkit != null) {
+            toolkit.shutdownWatchdog.setAwtQueueEmpty(false);
+            if (!GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) {
+                notifyEventMonitor(toolkit);
+            }
+        }
+        notifyAll();
+        */
+    }
+    
+    void notifyEventMonitor(Toolkit t) {
+        Object em = t.getNativeEventQueue().getEventMonitor();
+        synchronized (em) {
+            em.notifyAll();
+        }
+    }
+    
+    synchronized AWTEvent getNextEvent() throws InterruptedException {
+        while (events.isEmpty()) {
+            wait();
+        }
+        AWTEvent event = events.removeFirst();
+        // TODO: add event coalescing
+        return event;
+    }    
+    
+    synchronized AWTEvent peekEvent() {
+        return events.isEmpty() ? null : events.getFirst();
+    }
+    
+    synchronized AWTEvent peekEvent(int id) {
+        for (AWTEvent event : events) {
+            if (event.getID() == id) {
+                return event;
+            }
+        }
+        return null;
+    }
+    
+    synchronized void dispatchEvent(AWTEvent event) {
+        updateCurrentEventAndTime(event);
+        try {
+            activeQueue.dispatchEvent(event);
+        } finally {
+            currentEvent = null;
+        }
+    }
+    
+    void dispatchEventImpl(AWTEvent event) {
+        if (event instanceof ActiveEvent) {
+            updateCurrentEventAndTime(event);
+            try {
+                ((ActiveEvent) event).dispatch();
+            } finally {
+                currentEvent = null;
+            }
+            return;
+        }
+
+        Object src = event.getSource();
+
+        if (src instanceof Component) {
+            if (preprocessComponentEvent(event)) {
+                ((Component) src).dispatchEvent(event);
+            }
+        } else {
+            if (toolkit != null) {
+                toolkit.dispatchAWTEvent(event);
+            }
+            if (src instanceof MenuComponent) {
+                ((MenuComponent) src).dispatchEvent(event);
+            }
+        }
+    }
+
+    private final boolean preprocessComponentEvent(AWTEvent event) {
+      if (event instanceof MouseEvent) {
+          return preprocessMouseEvent((MouseEvent)event);
+      }
+      return true;
+    }
+
+    private final boolean preprocessMouseEvent(MouseEvent event) {
+        //???AWT
+        /*
+      if (toolkit != null && toolkit.mouseEventPreprocessor != null) {
+          toolkit.lockAWT();
+          try {
+              return toolkit.mouseEventPreprocessor.preprocess(event);
+          } finally {
+              toolkit.unlockAWT();
+          }
+      }
+      return true;
+        */
+        return true;
+    }
+    
+    private void updateCurrentEventAndTime(AWTEvent event) {
+        currentEvent = event;
+        long when = 0;
+        if (event instanceof ActionEvent) {
+            when = ((ActionEvent) event).getWhen();
+        } else if (event instanceof InputEvent) {
+            when = ((InputEvent) event).getWhen();
+        } else if (event instanceof InputMethodEvent) {
+            when = ((InputMethodEvent) event).getWhen();
+        } else if (event instanceof InvocationEvent) {
+            when = ((InvocationEvent) event).getWhen();
+        }
+        if (when != 0) {
+            mostRecentEventTime = when;
+        }
+    }
+    
+    synchronized void push(EventQueue newEventQueue) {
+        // TODO: handle incorrect situations
+        if (queueStack.isEmpty()) {
+            // awt.6B=Queue stack is empty
+            throw new IllegalStateException(Messages.getString("awt.6B")); //$NON-NLS-1$
+        }
+        
+        queueStack.addLast(newEventQueue);
+        activeQueue = newEventQueue;
+        activeQueue.setCore(this);
+    }
+    
+    synchronized void pop() {
+        EventQueue removed = queueStack.removeLast();
+        if (removed != activeQueue) {
+            // awt.6C=Event queue stack is broken
+            throw new IllegalStateException(Messages.getString("awt.6C")); //$NON-NLS-1$
+        }
+        activeQueue = queueStack.getLast();
+        removed.setCore(null);
+    }
+
+    synchronized AWTEvent getNextEventNoWait() {
+        try {
+            return events.isEmpty() ? null : activeQueue.getNextEvent();
+        } catch (InterruptedException e) {
+            return null;
+        }
+    }
+
+    synchronized boolean isEmpty() {
+        return (currentEvent == null) && events.isEmpty();
+    }
+    
+    synchronized boolean isEmpty(long timeout) {
+        if (!isEmpty()) {
+            return false;
+        }
+        try {
+            wait(timeout);
+        } catch (InterruptedException e) {}
+        return isEmpty();
+    }
+    
+    synchronized EventQueue getActiveEventQueue() {
+        return activeQueue;
+    }
+}
diff --git a/awt/java/awt/Font.java b/awt/java/awt/Font.java
new file mode 100644
index 0000000..4ed9343
--- /dev/null
+++ b/awt/java/awt/Font.java
@@ -0,0 +1,1541 @@
+/*
+ *  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.
+ */
+
+package java.awt;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.font.LineMetrics;
+import java.awt.font.TextAttribute;
+import java.awt.font.TransformAttribute;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.text.CharacterIterator;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.harmony.awt.gl.font.AndroidGlyphVector;
+import org.apache.harmony.awt.gl.font.CommonGlyphVector;
+import org.apache.harmony.awt.gl.font.FontPeerImpl;
+import org.apache.harmony.awt.gl.font.FontMetricsImpl;
+import org.apache.harmony.awt.gl.font.LineMetricsImpl;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.luni.util.NotImplementedException;
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Font class represents fonts for rendering text. This class allow to map
+ * characters to glyphs.
+ * <p>
+ * A glyph is a shape used to render a character or a sequence of characters.
+ * For example one character of Latin writing system represented by one glyph,
+ * but in complex writing system such as South and South-East Asian there is
+ * more complicated correspondence between characters and glyphs.
+ * <p>
+ * The Font object is identified by two types of names. The logical font name is
+ * the name that is used to construct the font. The font name is the name of a
+ * particular font face (for example, Arial Bold). The family name is the font's
+ * family name that specifies the typographic design across several faces (for
+ * example, Arial). In all the Font is identified by three attributes: the
+ * family name, the style (such as bold or italic), and the size.
+ * 
+ * @since Android 1.0
+ */
+public class Font implements Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -4206021311591459213L;
+
+    // Identity Transform attribute
+    /**
+     * The Constant IDENTITY_TRANSFORM.
+     */
+    private static final TransformAttribute IDENTITY_TRANSFORM = new TransformAttribute(
+            new AffineTransform());
+
+    /**
+     * The Constant PLAIN indicates font's plain style.
+     */
+    public static final int PLAIN = 0;
+
+    /**
+     * The Constant BOLD indicates font's bold style.
+     */
+    public static final int BOLD = 1;
+
+    /**
+     * The Constant ITALIC indicates font's italic style.
+     */
+    public static final int ITALIC = 2;
+
+    /**
+     * The Constant ROMAN_BASELINE indicated roman baseline.
+     */
+    public static final int ROMAN_BASELINE = 0;
+
+    /**
+     * The Constant CENTER_BASELINE indicates center baseline.
+     */
+    public static final int CENTER_BASELINE = 1;
+
+    /**
+     * The Constant HANGING_BASELINE indicates hanging baseline.
+     */
+    public static final int HANGING_BASELINE = 2;
+
+    /**
+     * The Constant TRUETYPE_FONT indicates a font resource of type TRUETYPE.
+     */
+    public static final int TRUETYPE_FONT = 0;
+
+    /**
+     * The Constant TYPE1_FONT indicates a font resource of type TYPE1.
+     */
+    public static final int TYPE1_FONT = 1;
+
+    /**
+     * The Constant LAYOUT_LEFT_TO_RIGHT indicates that text is left to right.
+     */
+    public static final int LAYOUT_LEFT_TO_RIGHT = 0;
+
+    /**
+     * The Constant LAYOUT_RIGHT_TO_LEFT indicates that text is right to left.
+     */
+    public static final int LAYOUT_RIGHT_TO_LEFT = 1;
+
+    /**
+     * The Constant LAYOUT_NO_START_CONTEXT indicates that the text in the char
+     * array before the indicated start should not be examined.
+     */
+    public static final int LAYOUT_NO_START_CONTEXT = 2;
+
+    /**
+     * The Constant LAYOUT_NO_LIMIT_CONTEXT indicates that text in the char
+     * array after the indicated limit should not be examined.
+     */
+    public static final int LAYOUT_NO_LIMIT_CONTEXT = 4;
+
+    /**
+     * The Constant DEFAULT_FONT.
+     */
+    static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 12); //$NON-NLS-1$
+
+    /**
+     * The name of the Font.
+     */
+    protected String name;
+
+    /**
+     * The style of the Font.
+     */
+    protected int style;
+
+    /**
+     * The size of the Font.
+     */
+    protected int size;
+
+    /**
+     * The point size of the Font.
+     */
+    protected float pointSize;
+
+    // Flag if the Font object transformed
+    /**
+     * The transformed.
+     */
+    private boolean transformed;
+
+    // Set of font attributes
+    /**
+     * The requested attributes.
+     */
+    private Hashtable<Attribute, Object> fRequestedAttributes;
+
+    // font peer object corresponding to this Font
+    /**
+     * The font peer.
+     */
+    private transient FontPeerImpl fontPeer;
+
+    // number of glyphs in this Font
+    /**
+     * The num glyphs.
+     */
+    private transient int numGlyphs = -1;
+
+    // code for missing glyph for this Font
+    /**
+     * The missing glyph code.
+     */
+    private transient int missingGlyphCode = -1;
+
+    /**
+     * Writes object to ObjectOutputStream.
+     * 
+     * @param out
+     *            ObjectOutputStream.
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     */
+    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+    }
+
+    /**
+     * Reads object from ObjectInputStream object and set native platform
+     * dependent fields to default values.
+     * 
+     * @param in
+     *            ObjectInputStream object.
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     * @throws ClassNotFoundException
+     *             the class not found exception.
+     */
+    private void readObject(java.io.ObjectInputStream in) throws IOException,
+            ClassNotFoundException {
+        in.defaultReadObject();
+
+        numGlyphs = -1;
+        missingGlyphCode = -1;
+
+    }
+
+    /**
+     * Instantiates a new Font with the specified attributes. The Font will be
+     * created with default attributes if the attribute's parameter is null.
+     * 
+     * @param attributes
+     *            the attributes to be assigned to the new Font, or null.
+     */
+    public Font(Map<? extends Attribute, ?> attributes) {
+        Object currAttr;
+
+        // Default values are taken from the documentation of the Font class.
+        // See Font constructor, decode and getFont sections.
+
+        this.name = "default"; //$NON-NLS-1$
+        this.size = 12;
+        this.pointSize = 12;
+        this.style = Font.PLAIN;
+
+        if (attributes != null) {
+
+            fRequestedAttributes = new Hashtable<Attribute, Object>(attributes);
+
+            currAttr = attributes.get(TextAttribute.SIZE);
+            if (currAttr != null) {
+                this.pointSize = ((Float)currAttr).floatValue();
+                this.size = (int)Math.ceil(this.pointSize);
+            }
+
+            currAttr = attributes.get(TextAttribute.POSTURE);
+            if (currAttr != null && currAttr.equals(TextAttribute.POSTURE_OBLIQUE)) {
+                this.style |= Font.ITALIC;
+            }
+
+            currAttr = attributes.get(TextAttribute.WEIGHT);
+            if ((currAttr != null)
+                    && (((Float)currAttr).floatValue() >= (TextAttribute.WEIGHT_BOLD).floatValue())) {
+                this.style |= Font.BOLD;
+            }
+
+            currAttr = attributes.get(TextAttribute.FAMILY);
+            if (currAttr != null) {
+                this.name = (String)currAttr;
+            }
+
+            currAttr = attributes.get(TextAttribute.TRANSFORM);
+            if (currAttr != null) {
+                if (currAttr instanceof TransformAttribute) {
+                    this.transformed = !((TransformAttribute)currAttr).getTransform().isIdentity();
+                } else if (currAttr instanceof AffineTransform) {
+                    this.transformed = !((AffineTransform)currAttr).isIdentity();
+                }
+            }
+
+        } else {
+            fRequestedAttributes = new Hashtable<Attribute, Object>(5);
+            fRequestedAttributes.put(TextAttribute.TRANSFORM, IDENTITY_TRANSFORM);
+
+            this.transformed = false;
+
+            fRequestedAttributes.put(TextAttribute.FAMILY, name);
+
+            fRequestedAttributes.put(TextAttribute.SIZE, new Float(this.size));
+
+            if ((this.style & Font.BOLD) != 0) {
+                fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
+            } else {
+                fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR);
+            }
+            if ((this.style & Font.ITALIC) != 0) {
+                fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
+            } else {
+                fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR);
+            }
+
+        }
+    }
+
+    /**
+     * Instantiates a new Font with the specified name, style and size.
+     * 
+     * @param name
+     *            the name of font.
+     * @param style
+     *            the style of font.
+     * @param size
+     *            the size of font.
+     */
+    public Font(String name, int style, int size) {
+
+        this.name = (name != null) ? name : "Default"; //$NON-NLS-1$
+        this.size = (size >= 0) ? size : 0;
+        this.style = (style & ~0x03) == 0 ? style : Font.PLAIN;
+        this.pointSize = this.size;
+
+        fRequestedAttributes = new Hashtable<Attribute, Object>(5);
+
+        fRequestedAttributes.put(TextAttribute.TRANSFORM, IDENTITY_TRANSFORM);
+
+        this.transformed = false;
+
+        fRequestedAttributes.put(TextAttribute.FAMILY, this.name);
+        fRequestedAttributes.put(TextAttribute.SIZE, new Float(this.size));
+
+        if ((this.style & Font.BOLD) != 0) {
+            fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
+        } else {
+            fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR);
+        }
+        if ((this.style & Font.ITALIC) != 0) {
+            fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
+        } else {
+            fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR);
+        }
+    }
+
+    /**
+     * Returns true if this Font has a glyph for the specified character.
+     * 
+     * @param c
+     *            the character.
+     * @return true if this Font has a glyph for the specified character, false
+     *         otherwise.
+     */
+    public boolean canDisplay(char c) {
+        FontPeerImpl peer = (FontPeerImpl)this.getPeer();
+        return peer.canDisplay(c);
+    }
+
+    /**
+     * Returns true if the Font can display the characters of the the specified
+     * text from the specified start position to the specified limit position.
+     * 
+     * @param text
+     *            the text.
+     * @param start
+     *            the start offset (in the character array).
+     * @param limit
+     *            the limit offset (in the character array).
+     * @return the a character's position in the text that this Font can not
+     *         display, or -1 if this Font can display all characters in this
+     *         text.
+     */
+    public int canDisplayUpTo(char[] text, int start, int limit) {
+        int st = start;
+        int result;
+        while ((st < limit) && canDisplay(text[st])) {
+            st++;
+        }
+
+        if (st == limit) {
+            result = -1;
+        } else {
+            result = st;
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns true if the Font can display the characters of the the specified
+     * CharacterIterator from the specified start position and the specified
+     * limit position.
+     * 
+     * @param iter
+     *            the CharacterIterator.
+     * @param start
+     *            the start offset.
+     * @param limit
+     *            the limit offset.
+     * @return the a character's position in the CharacterIterator that this
+     *         Font can not display, or -1 if this Font can display all
+     *         characters in this text.
+     */
+    public int canDisplayUpTo(CharacterIterator iter, int start, int limit) {
+        int st = start;
+        char c = iter.setIndex(start);
+        int result;
+
+        while ((st < limit) && (canDisplay(c))) {
+            st++;
+            c = iter.next();
+        }
+        if (st == limit) {
+            result = -1;
+        } else {
+            result = st;
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns true if this Font can display a specified String.
+     * 
+     * @param str
+     *            the String.
+     * @return the a character's position in the String that this Font can not
+     *         display, or -1 if this Font can display all characters in this
+     *         text.
+     */
+    public int canDisplayUpTo(String str) {
+        char[] chars = str.toCharArray();
+        return canDisplayUpTo(chars, 0, chars.length);
+    }
+
+    /**
+     * Creates a GlyphVector of associating characters to glyphs based on the
+     * Unicode map of this Font.
+     * 
+     * @param frc
+     *            the FontRenderContext.
+     * @param chars
+     *            the characters array.
+     * @return the GlyphVector of associating characters to glyphs based on the
+     *         Unicode map of this Font.
+     */
+    public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars) {
+        return new AndroidGlyphVector(chars, frc, this, 0);
+    }
+
+    /**
+     * Creates a GlyphVector of associating characters contained in the
+     * specified CharacterIterator to glyphs based on the Unicode map of this
+     * Font.
+     * 
+     * @param frc
+     *            the FontRenderContext.
+     * @param iter
+     *            the CharacterIterator.
+     * @return the GlyphVector of associating characters contained in the
+     *         specified CharacterIterator to glyphs based on the Unicode map of
+     *         this Font.
+     */
+    public GlyphVector createGlyphVector(FontRenderContext frc, CharacterIterator iter) {
+        throw new RuntimeException("Not implemented!"); //$NON-NLS-1$    
+    }
+
+    /**
+     * Creates a GlyphVector of associating characters to glyphs based on the
+     * Unicode map of this Font.
+     * 
+     * @param frc
+     *            the FontRenderContext.
+     * @param glyphCodes
+     *            the specified integer array of glyph codes.
+     * @return the GlyphVector of associating characters to glyphs based on the
+     *         Unicode map of this Font.
+     * @throws NotImplementedException
+     *             if this method is not implemented by a subclass.
+     */
+    public GlyphVector createGlyphVector(FontRenderContext frc, int[] glyphCodes)
+            throws org.apache.harmony.luni.util.NotImplementedException {
+        throw new RuntimeException("Not implemented!"); //$NON-NLS-1$
+    }
+
+    /**
+     * Creates a GlyphVector of associating characters to glyphs based on the
+     * Unicode map of this Font.
+     * 
+     * @param frc
+     *            the FontRenderContext.
+     * @param str
+     *            the specified String.
+     * @return the GlyphVector of associating characters to glyphs based on the
+     *         Unicode map of this Font.
+     */
+    public GlyphVector createGlyphVector(FontRenderContext frc, String str) {
+        return new AndroidGlyphVector(str.toCharArray(), frc, this, 0);
+
+    }
+
+    /**
+     * Returns the font style constant value corresponding to one of the font
+     * style names ("BOLD", "ITALIC", "BOLDITALIC"). This method returns
+     * Font.PLAIN if the argument is not one of the predefined style names.
+     * 
+     * @param fontStyleName
+     *            font style name.
+     * @return font style constant value corresponding to the font style name
+     *         specified.
+     */
+    private static int getFontStyle(String fontStyleName) {
+        int result = Font.PLAIN;
+
+        if (fontStyleName.toUpperCase().equals("BOLDITALIC")) { //$NON-NLS-1$
+            result = Font.BOLD | Font.ITALIC;
+        } else if (fontStyleName.toUpperCase().equals("BOLD")) { //$NON-NLS-1$
+            result = Font.BOLD;
+        } else if (fontStyleName.toUpperCase().equals("ITALIC")) { //$NON-NLS-1$
+            result = Font.ITALIC;
+        }
+
+        return result;
+    }
+
+    /**
+     * Decodes the specified string which described the Font. The string should
+     * have the following format: fontname-style-pointsize. The style can be
+     * PLAIN, BOLD, BOLDITALIC, or ITALIC.
+     * 
+     * @param str
+     *            the string which describes the font.
+     * @return the Font from the specified string.
+     */
+    public static Font decode(String str) {
+        // XXX: Documentation doesn't describe all cases, e.g. fonts face names
+        // with
+        // symbols that are suggested as delimiters in the documentation.
+        // In this decode implementation only ***-***-*** format is used with
+        // '-'
+        // as the delimiter to avoid unexpected parse results of font face names
+        // with spaces.
+
+        if (str == null) {
+            return DEFAULT_FONT;
+        }
+
+        StringTokenizer strTokens;
+        String delim = "-"; //$NON-NLS-1$
+        String substr;
+
+        int fontSize = DEFAULT_FONT.size;
+        int fontStyle = DEFAULT_FONT.style;
+        String fontName = DEFAULT_FONT.name;
+
+        strTokens = new StringTokenizer(str.trim(), delim);
+
+        // Font Name
+        if (strTokens.hasMoreTokens()) {
+            fontName = strTokens.nextToken(); // first token is the font name
+        }
+
+        // Font Style or Size (if the style is undefined)
+        if (strTokens.hasMoreTokens()) {
+            substr = strTokens.nextToken();
+
+            try {
+                // if second token is the font size
+                fontSize = Integer.parseInt(substr);
+            } catch (NumberFormatException e) {
+                // then second token is the font style
+                fontStyle = getFontStyle(substr);
+            }
+
+        }
+
+        // Font Size
+        if (strTokens.hasMoreTokens()) {
+            try {
+                fontSize = Integer.parseInt(strTokens.nextToken());
+            } catch (NumberFormatException e) {
+            }
+        }
+
+        return new Font(fontName, fontStyle, fontSize);
+    }
+
+    /**
+     * Performs the specified affine transform to the Font and returns a new
+     * Font.
+     * 
+     * @param trans
+     *            the AffineTransform.
+     * @return the Font object.
+     * @throws IllegalArgumentException
+     *             if affine transform parameter is null.
+     */
+    @SuppressWarnings("unchecked")
+    public Font deriveFont(AffineTransform trans) {
+
+        if (trans == null) {
+            // awt.94=transform can not be null
+            throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$
+        }
+
+        Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes
+                .clone();
+
+        derivefRequestedAttributes.put(TextAttribute.TRANSFORM, new TransformAttribute(trans));
+
+        return new Font(derivefRequestedAttributes);
+
+    }
+
+    /**
+     * Returns a new Font that is a copy of the current Font modified so that
+     * the size is the specified size.
+     * 
+     * @param size
+     *            the size of font.
+     * @return the Font object.
+     */
+    @SuppressWarnings("unchecked")
+    public Font deriveFont(float size) {
+        Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes
+                .clone();
+        derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size));
+        return new Font(derivefRequestedAttributes);
+    }
+
+    /**
+     * Returns a new Font that is a copy of the current Font modified so that
+     * the style is the specified style.
+     * 
+     * @param style
+     *            the style of font.
+     * @return the Font object.
+     */
+    @SuppressWarnings("unchecked")
+    public Font deriveFont(int style) {
+        Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes
+                .clone();
+
+        if ((style & Font.BOLD) != 0) {
+            derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
+        } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) {
+            derivefRequestedAttributes.remove(TextAttribute.WEIGHT);
+        }
+
+        if ((style & Font.ITALIC) != 0) {
+            derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
+        } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) {
+            derivefRequestedAttributes.remove(TextAttribute.POSTURE);
+        }
+
+        return new Font(derivefRequestedAttributes);
+    }
+
+    /**
+     * Returns a new Font that is a copy of the current Font modified to match
+     * the specified style and with the specified affine transform applied to
+     * its glyphs.
+     * 
+     * @param style
+     *            the style of font.
+     * @param trans
+     *            the AffineTransform.
+     * @return the Font object.
+     */
+    @SuppressWarnings("unchecked")
+    public Font deriveFont(int style, AffineTransform trans) {
+
+        if (trans == null) {
+            // awt.94=transform can not be null
+            throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$
+        }
+        Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes
+                .clone();
+
+        if ((style & BOLD) != 0) {
+            derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
+        } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) {
+            derivefRequestedAttributes.remove(TextAttribute.WEIGHT);
+        }
+
+        if ((style & ITALIC) != 0) {
+            derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
+        } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) {
+            derivefRequestedAttributes.remove(TextAttribute.POSTURE);
+        }
+        derivefRequestedAttributes.put(TextAttribute.TRANSFORM, new TransformAttribute(trans));
+
+        return new Font(derivefRequestedAttributes);
+    }
+
+    /**
+     * Returns a new Font that is a copy of the current Font modified so that
+     * the size and style are the specified size and style.
+     * 
+     * @param style
+     *            the style of font.
+     * @param size
+     *            the size of font.
+     * @return the Font object.
+     */
+    @SuppressWarnings("unchecked")
+    public Font deriveFont(int style, float size) {
+        Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes
+                .clone();
+
+        if ((style & BOLD) != 0) {
+            derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
+        } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) {
+            derivefRequestedAttributes.remove(TextAttribute.WEIGHT);
+        }
+
+        if ((style & ITALIC) != 0) {
+            derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
+        } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) {
+            derivefRequestedAttributes.remove(TextAttribute.POSTURE);
+        }
+
+        derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size));
+        return new Font(derivefRequestedAttributes);
+
+    }
+
+    /**
+     * Returns a new Font object with a new set of font attributes.
+     * 
+     * @param attributes
+     *            the map of attributes.
+     * @return the Font.
+     */
+    @SuppressWarnings("unchecked")
+    public Font deriveFont(Map<? extends Attribute, ?> attributes) {
+        Attribute[] avalAttributes = this.getAvailableAttributes();
+
+        Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>)fRequestedAttributes
+                .clone();
+        Object currAttribute;
+        for (Attribute element : avalAttributes) {
+            currAttribute = attributes.get(element);
+            if (currAttribute != null) {
+                derivefRequestedAttributes.put(element, currAttribute);
+            }
+        }
+        return new Font(derivefRequestedAttributes);
+    }
+
+    /**
+     * Compares the specified Object with the current Font.
+     * 
+     * @param obj
+     *            the Object to be compared.
+     * @return true, if the specified Object is an instance of Font with the
+     *         same family, size, and style as this Font, false otherwise.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj != null) {
+            try {
+                Font font = (Font)obj;
+
+                return ((this.style == font.style) && (this.size == font.size)
+                        && this.name.equals(font.name) && (this.pointSize == font.pointSize) && (this
+                        .getTransform()).equals(font.getTransform()));
+            } catch (ClassCastException e) {
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Gets the map of font's attributes.
+     * 
+     * @return the map of font's attributes.
+     */
+    @SuppressWarnings("unchecked")
+    public Map<TextAttribute, ?> getAttributes() {
+        return (Map<TextAttribute, ?>)fRequestedAttributes.clone();
+    }
+
+    /**
+     * Gets the keys of all available attributes.
+     * 
+     * @return the keys array of all available attributes.
+     */
+    public Attribute[] getAvailableAttributes() {
+        Attribute[] attrs = {
+                TextAttribute.FAMILY, TextAttribute.POSTURE, TextAttribute.SIZE,
+                TextAttribute.TRANSFORM, TextAttribute.WEIGHT, TextAttribute.SUPERSCRIPT,
+                TextAttribute.WIDTH
+        };
+        return attrs;
+    }
+
+    /**
+     * Gets the baseline for this character.
+     * 
+     * @param c
+     *            the character.
+     * @return the baseline for this character.
+     */
+    public byte getBaselineFor(char c) {
+        // TODO: implement using TT BASE table data
+        return 0;
+    }
+
+    /**
+     * Gets the family name of the Font.
+     * 
+     * @return the family name of the Font.
+     */
+    public String getFamily() {
+        if (fRequestedAttributes != null) {
+            fRequestedAttributes.get(TextAttribute.FAMILY);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the family name of this Font associated with the specified
+     * locale.
+     * 
+     * @param l
+     *            the locale.
+     * @return the family name of this Font associated with the specified
+     *         locale.
+     */
+    public String getFamily(Locale l) {
+        if (l == null) {
+            // awt.01='{0}' parameter is null
+            throw new NullPointerException(Messages.getString("awt.01", "Locale")); //$NON-NLS-1$ //$NON-NLS-2$ 
+        }
+        return getFamily();
+    }
+
+    /**
+     * Gets a Font with the specified attribute set.
+     * 
+     * @param attributes
+     *            the attributes to be assigned to the new Font.
+     * @return the Font.
+     */
+    public static Font getFont(Map<? extends Attribute, ?> attributes) {
+        Font fnt = (Font)attributes.get(TextAttribute.FONT);
+        if (fnt != null) {
+            return fnt;
+        }
+        return new Font(attributes);
+    }
+
+    /**
+     * Gets a Font object from the system properties list with the specified
+     * name or returns the specified Font if there is no such property.
+     * 
+     * @param sp
+     *            the specified property name.
+     * @param f
+     *            the Font.
+     * @return the Font object from the system properties list with the
+     *         specified name or the specified Font if there is no such
+     *         property.
+     */
+    public static Font getFont(String sp, Font f) {
+        String pr = System.getProperty(sp);
+        if (pr == null) {
+            return f;
+        }
+        return decode(pr);
+    }
+
+    /**
+     * Gets a Font object from the system properties list with the specified
+     * name.
+     * 
+     * @param sp
+     *            the system property name.
+     * @return the Font, or null if there is no such property with the specified
+     *         name.
+     */
+    public static Font getFont(String sp) {
+        return getFont(sp, null);
+    }
+
+    /**
+     * Gets the font name.
+     * 
+     * @return the font name.
+     */
+    public String getFontName() {
+        if (fRequestedAttributes != null) {
+            fRequestedAttributes.get(TextAttribute.FAMILY);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the font name associated with the specified locale.
+     * 
+     * @param l
+     *            the locale.
+     * @return the font name associated with the specified locale.
+     */
+    public String getFontName(Locale l) {
+        return getFamily();
+    }
+
+    /**
+     * Returns a LineMetrics object created with the specified parameters.
+     * 
+     * @param chars
+     *            the chars array.
+     * @param start
+     *            the start offset.
+     * @param end
+     *            the end offset.
+     * @param frc
+     *            the FontRenderContext.
+     * @return the LineMetrics for the specified parameters.
+     */
+    public LineMetrics getLineMetrics(char[] chars, int start, int end, FontRenderContext frc) {
+        if (frc == null) {
+            // awt.00=FontRenderContext is null
+            throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+        }
+
+        // FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics();
+        FontMetrics fm = new FontMetricsImpl(this);
+        float[] fmet = {
+                fm.getAscent(), fm.getDescent(), fm.getLeading()
+        };
+        return new LineMetricsImpl(chars.length, fmet, null);
+    }
+
+    /**
+     * Returns a LineMetrics object created with the specified parameters.
+     * 
+     * @param iter
+     *            the CharacterIterator.
+     * @param start
+     *            the start offset.
+     * @param end
+     *            the end offset.
+     * @param frc
+     *            the FontRenderContext.
+     * @return the LineMetrics for the specified parameters.
+     */
+    public LineMetrics getLineMetrics(CharacterIterator iter, int start, int end,
+            FontRenderContext frc) {
+
+        if (frc == null) {
+            // awt.00=FontRenderContext is null
+            throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+        }
+
+        String resultString;
+        int iterCount;
+
+        iterCount = end - start;
+        if (iterCount < 0) {
+            resultString = ""; //$NON-NLS-1$
+        } else {
+            char[] chars = new char[iterCount];
+            int i = 0;
+            for (char c = iter.setIndex(start); c != CharacterIterator.DONE && (i < iterCount); c = iter
+                    .next()) {
+                chars[i] = c;
+                i++;
+            }
+            resultString = new String(chars);
+        }
+        return this.getLineMetrics(resultString, frc);
+    }
+
+    /**
+     * Returns a LineMetrics object created with the specified parameters.
+     * 
+     * @param str
+     *            the String.
+     * @param frc
+     *            the FontRenderContext.
+     * @return the LineMetrics for the specified parameters.
+     */
+    public LineMetrics getLineMetrics(String str, FontRenderContext frc) {
+        // FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics();
+        FontMetrics fm = new FontMetricsImpl(this);
+        float[] fmet = {
+                fm.getAscent(), fm.getDescent(), fm.getLeading()
+        };
+        // Log.i("FONT FMET", fmet.toString());
+        return new LineMetricsImpl(str.length(), fmet, null);
+
+    }
+
+    /**
+     * Returns a LineMetrics object created with the specified parameters.
+     * 
+     * @param str
+     *            the String.
+     * @param start
+     *            the start offset.
+     * @param end
+     *            the end offset.
+     * @param frc
+     *            the FontRenderContext.
+     * @return the LineMetrics for the specified parameters.
+     */
+    public LineMetrics getLineMetrics(String str, int start, int end, FontRenderContext frc) {
+        return this.getLineMetrics(str.substring(start, end), frc);
+    }
+
+    /**
+     * Gets the logical bounds of the specified String in the specified
+     * FontRenderContext. The logical bounds contains the origin, ascent,
+     * advance, and height.
+     * 
+     * @param ci
+     *            the specified CharacterIterator.
+     * @param start
+     *            the start offset.
+     * @param end
+     *            the end offset.
+     * @param frc
+     *            the FontRenderContext.
+     * @return a Rectangle2D object.
+     */
+    public Rectangle2D getStringBounds(CharacterIterator ci, int start, int end,
+            FontRenderContext frc) {
+        int first = ci.getBeginIndex();
+        int finish = ci.getEndIndex();
+        char[] chars;
+
+        if (start < first) {
+            // awt.95=Wrong start index: {0}
+            throw new IndexOutOfBoundsException(Messages.getString("awt.95", start)); //$NON-NLS-1$
+        }
+        if (end > finish) {
+            // awt.96=Wrong finish index: {0}
+            throw new IndexOutOfBoundsException(Messages.getString("awt.96", end)); //$NON-NLS-1$
+        }
+        if (start > end) {
+            // awt.97=Wrong range length: {0}
+            throw new IndexOutOfBoundsException(Messages.getString("awt.97", //$NON-NLS-1$
+                    (end - start)));
+        }
+
+        if (frc == null) {
+            throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+        }
+
+        chars = new char[end - start];
+
+        ci.setIndex(start);
+        for (int i = 0; i < chars.length; i++) {
+            chars[i] = ci.current();
+            ci.next();
+        }
+
+        return this.getStringBounds(chars, 0, chars.length, frc);
+
+    }
+
+    /**
+     * Gets the logical bounds of the specified String in the specified
+     * FontRenderContext. The logical bounds contains the origin, ascent,
+     * advance, and height.
+     * 
+     * @param str
+     *            the specified String.
+     * @param frc
+     *            the FontRenderContext.
+     * @return a Rectangle2D object.
+     */
+    public Rectangle2D getStringBounds(String str, FontRenderContext frc) {
+        char[] chars = str.toCharArray();
+        return this.getStringBounds(chars, 0, chars.length, frc);
+
+    }
+
+    /**
+     * Gets the logical bounds of the specified String in the specified
+     * FontRenderContext. The logical bounds contains the origin, ascent,
+     * advance, and height.
+     * 
+     * @param str
+     *            the specified String.
+     * @param start
+     *            the start offset.
+     * @param end
+     *            the end offset.
+     * @param frc
+     *            the FontRenderContext.
+     * @return a Rectangle2D object.
+     */
+    public Rectangle2D getStringBounds(String str, int start, int end, FontRenderContext frc) {
+
+        return this.getStringBounds((str.substring(start, end)), frc);
+    }
+
+    /**
+     * Gets the logical bounds of the specified String in the specified
+     * FontRenderContext. The logical bounds contains the origin, ascent,
+     * advance, and height.
+     * 
+     * @param chars
+     *            the specified character array.
+     * @param start
+     *            the start offset.
+     * @param end
+     *            the end offset.
+     * @param frc
+     *            the FontRenderContext.
+     * @return a Rectangle2D object.
+     */
+    public Rectangle2D getStringBounds(char[] chars, int start, int end, FontRenderContext frc) {
+        if (start < 0) {
+            // awt.95=Wrong start index: {0}
+            throw new IndexOutOfBoundsException(Messages.getString("awt.95", start)); //$NON-NLS-1$
+        }
+        if (end > chars.length) {
+            // awt.96=Wrong finish index: {0}
+            throw new IndexOutOfBoundsException(Messages.getString("awt.96", end)); //$NON-NLS-1$
+        }
+        if (start > end) {
+            // awt.97=Wrong range length: {0}
+            throw new IndexOutOfBoundsException(Messages.getString("awt.97", //$NON-NLS-1$
+                    (end - start)));
+        }
+
+        if (frc == null) {
+            throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+        }
+
+        FontPeerImpl peer = (FontPeerImpl)this.getPeer();
+
+        final int TRANSFORM_MASK = AffineTransform.TYPE_GENERAL_ROTATION
+                | AffineTransform.TYPE_GENERAL_TRANSFORM;
+        Rectangle2D bounds;
+
+        AffineTransform transform = getTransform();
+
+        // XXX: for transforms where an angle between basis vectors is not 90
+        // degrees Rectanlge2D class doesn't fit as Logical bounds.
+        if ((transform.getType() & TRANSFORM_MASK) == 0) {
+            int width = 0;
+            for (int i = start; i < end; i++) {
+                width += peer.charWidth(chars[i]);
+            }
+            // LineMetrics nlm = peer.getLineMetrics();
+
+            LineMetrics nlm = getLineMetrics(chars, start, end, frc);
+
+            bounds = transform.createTransformedShape(
+                    new Rectangle2D.Float(0, -nlm.getAscent(), width, nlm.getHeight()))
+                    .getBounds2D();
+        } else {
+            int len = end - start;
+            char[] subChars = new char[len];
+            System.arraycopy(chars, start, subChars, 0, len);
+            bounds = createGlyphVector(frc, subChars).getLogicalBounds();
+        }
+        return bounds;
+    }
+
+    /**
+     * Gets the character's maximum bounds as defined in the specified
+     * FontRenderContext.
+     * 
+     * @param frc
+     *            the FontRenderContext.
+     * @return the character's maximum bounds.
+     */
+    public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
+        if (frc == null) {
+            // awt.00=FontRenderContext is null
+            throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ 
+        }
+
+        FontPeerImpl peer = (FontPeerImpl)this.getPeer();
+
+        Rectangle2D bounds = peer.getMaxCharBounds(frc);
+        AffineTransform transform = getTransform();
+        // !! Documentation doesn't describe meaning of max char bounds
+        // for the fonts that have rotate transforms. For all transforms
+        // returned bounds are the bounds of transformed maxCharBounds
+        // Rectangle2D that corresponds to the font with identity transform.
+        // TODO: resolve this issue to return correct bounds
+        bounds = transform.createTransformedShape(bounds).getBounds2D();
+
+        return bounds;
+    }
+
+    /**
+     * Returns a new GlyphVector object performing full layout of the text.
+     * 
+     * @param frc
+     *            the FontRenderContext.
+     * @param chars
+     *            the character array to be layout.
+     * @param start
+     *            the start offset of the text to use for the GlyphVector.
+     * @param count
+     *            the count of characters to use for the GlyphVector.
+     * @param flags
+     *            the flag indicating text direction: LAYOUT_RIGHT_TO_LEFT,
+     *            LAYOUT_LEFT_TO_RIGHT.
+     * @return the GlyphVector.
+     */
+    public GlyphVector layoutGlyphVector(FontRenderContext frc, char[] chars, int start, int count,
+            int flags) {
+        // TODO: implement method for bidirectional text.
+        // At the moment only LTR and RTL texts supported.
+        if (start < 0) {
+            // awt.95=Wrong start index: {0}
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.95", //$NON-NLS-1$
+                    start));
+        }
+
+        if (count < 0) {
+            // awt.98=Wrong count value, can not be negative: {0}
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.98", //$NON-NLS-1$
+                    count));
+        }
+
+        if (start + count > chars.length) {
+            // awt.99=Wrong [start + count] is out of range: {0}
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.99", //$NON-NLS-1$
+                    (start + count)));
+        }
+
+        char[] out = new char[count];
+        System.arraycopy(chars, start, out, 0, count);
+
+        return new CommonGlyphVector(out, frc, this, flags);
+    }
+
+    /**
+     * Returns the String representation of this Font.
+     * 
+     * @return the String representation of this Font.
+     */
+    @Override
+    public String toString() {
+        String stl = "plain"; //$NON-NLS-1$
+        String result;
+
+        if (this.isBold() && this.isItalic()) {
+            stl = "bolditalic"; //$NON-NLS-1$
+        }
+        if (this.isBold() && !this.isItalic()) {
+            stl = "bold"; //$NON-NLS-1$
+        }
+
+        if (!this.isBold() && this.isItalic()) {
+            stl = "italic"; //$NON-NLS-1$
+        }
+
+        result = this.getClass().getName() + "[family=" + this.getFamily() + //$NON-NLS-1$
+                ",name=" + this.name + //$NON-NLS-1$
+                ",style=" + stl + //$NON-NLS-1$
+                ",size=" + this.size + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+        return result;
+    }
+
+    /**
+     * Gets the postscript name of this Font.
+     * 
+     * @return the postscript name of this Font.
+     */
+    public String getPSName() {
+        FontPeerImpl peer = (FontPeerImpl)this.getPeer();
+        return peer.getPSName();
+    }
+
+    /**
+     * Gets the logical name of this Font.
+     * 
+     * @return the logical name of this Font.
+     */
+    public String getName() {
+        return (this.name);
+    }
+
+    /**
+     * Gets the peer of this Font.
+     * 
+     * @return the peer of this Font.
+     * @deprecated Font rendering is platform independent now.
+     */
+    @Deprecated
+    public java.awt.peer.FontPeer getPeer() {
+        if (fontPeer == null) {
+            fontPeer = (FontPeerImpl)Toolkit.getDefaultToolkit().getGraphicsFactory().getFontPeer(
+                    this);
+        }
+        return fontPeer;
+
+    }
+
+    /**
+     * Gets the transform acting on this Font (from the Font's attributes).
+     * 
+     * @return the transformation of this Font.
+     */
+    public AffineTransform getTransform() {
+        Object transform = fRequestedAttributes.get(TextAttribute.TRANSFORM);
+
+        if (transform != null) {
+            if (transform instanceof TransformAttribute) {
+                return ((TransformAttribute)transform).getTransform();
+            }
+            if (transform instanceof AffineTransform) {
+                return new AffineTransform((AffineTransform)transform);
+            }
+        } else {
+            transform = new AffineTransform();
+        }
+        return (AffineTransform)transform;
+
+    }
+
+    /**
+     * Checks if this font is transformed or not.
+     * 
+     * @return true, if this font is transformed, false otherwise.
+     */
+    public boolean isTransformed() {
+        return this.transformed;
+    }
+
+    /**
+     * Checks if this font has plain style or not.
+     * 
+     * @return true, if this font has plain style, false otherwise.
+     */
+    public boolean isPlain() {
+        return (this.style == PLAIN);
+    }
+
+    /**
+     * Checks if this font has italic style or not.
+     * 
+     * @return true, if this font has italic style, false otherwise.
+     */
+    public boolean isItalic() {
+        return (this.style & ITALIC) != 0;
+    }
+
+    /**
+     * Checks if this font has bold style or not.
+     * 
+     * @return true, if this font has bold style, false otherwise.
+     */
+    public boolean isBold() {
+        return (this.style & BOLD) != 0;
+    }
+
+    /**
+     * Returns true if this Font has uniform line metrics.
+     * 
+     * @return true if this Font has uniform line metrics, false otherwise.
+     */
+    public boolean hasUniformLineMetrics() {
+        FontPeerImpl peer = (FontPeerImpl)this.getPeer();
+        return peer.hasUniformLineMetrics();
+    }
+
+    /**
+     * Returns hash code of this Font object.
+     * 
+     * @return the hash code of this Font object.
+     */
+    @Override
+    public int hashCode() {
+        HashCode hash = new HashCode();
+
+        hash.append(this.name);
+        hash.append(this.style);
+        hash.append(this.size);
+
+        return hash.hashCode();
+    }
+
+    /**
+     * Gets the style of this Font.
+     * 
+     * @return the style of this Font.
+     */
+    public int getStyle() {
+        return this.style;
+    }
+
+    /**
+     * Gets the size of this Font.
+     * 
+     * @return the size of this Font.
+     */
+    public int getSize() {
+        return this.size;
+    }
+
+    /**
+     * Gets the number of glyphs for this Font.
+     * 
+     * @return the number of glyphs for this Font.
+     */
+    public int getNumGlyphs() {
+        if (numGlyphs == -1) {
+            FontPeerImpl peer = (FontPeerImpl)this.getPeer();
+            this.numGlyphs = peer.getNumGlyphs();
+        }
+        return this.numGlyphs;
+    }
+
+    /**
+     * Gets the glyphCode which is used as default glyph when this Font does not
+     * have a glyph for a specified Unicode.
+     * 
+     * @return the missing glyph code.
+     */
+    public int getMissingGlyphCode() {
+        if (missingGlyphCode == -1) {
+            FontPeerImpl peer = (FontPeerImpl)this.getPeer();
+            this.missingGlyphCode = peer.getMissingGlyphCode();
+        }
+        return this.missingGlyphCode;
+    }
+
+    /**
+     * Gets the float value of font's size.
+     * 
+     * @return the float value of font's size.
+     */
+    public float getSize2D() {
+        return this.pointSize;
+    }
+
+    /**
+     * Gets the italic angle of this Font.
+     * 
+     * @return the italic angle of this Font.
+     */
+    public float getItalicAngle() {
+        FontPeerImpl peer = (FontPeerImpl)this.getPeer();
+        return peer.getItalicAngle();
+    }
+
+    /**
+     * Creates the font with the specified font format and font file.
+     * 
+     * @param fontFormat
+     *            the font format.
+     * @param fontFile
+     *            the file object represented the input data for the font.
+     * @return the Font.
+     * @throws FontFormatException
+     *             is thrown if fontFile does not contain the required font
+     *             tables for the specified format.
+     * @throws IOException
+     *             signals that an I/O exception has occurred.
+     */
+    public static Font createFont(int fontFormat, File fontFile) throws FontFormatException,
+            IOException {
+        // ???AWT not supported
+        InputStream is = new FileInputStream(fontFile);
+        try {
+            return createFont(fontFormat, is);
+        } finally {
+            is.close();
+        }
+    }
+
+    /**
+     * Creates the font with the specified font format and input stream.
+     * 
+     * @param fontFormat
+     *            the font format.
+     * @param fontStream
+     *            the input stream represented input data for the font.
+     * @return the Font.
+     * @throws FontFormatException
+     *             is thrown if fontFile does not contain the required font
+     *             tables for the specified format.
+     * @throws IOException
+     *             signals that an I/O exception has occurred.
+     */
+    public static Font createFont(int fontFormat, InputStream fontStream)
+            throws FontFormatException, IOException {
+
+        // ???AWT not supported
+
+        BufferedInputStream buffStream;
+        int bRead = 0;
+        int size = 8192;
+        // memory page size, for the faster reading
+        byte buf[] = new byte[size];
+
+        if (fontFormat != TRUETYPE_FONT) { // awt.9A=Unsupported font format
+            throw new IllegalArgumentException(Messages.getString("awt.9A")); //$NON-NLS-1$ 
+        }
+
+        /* Get font file in system-specific directory */
+
+        File fontFile = Toolkit.getDefaultToolkit().getGraphicsFactory().getFontManager()
+                .getTempFontFile();
+
+        // BEGIN android-modified
+        buffStream = new BufferedInputStream(fontStream, 8192);
+        // END android-modified
+        FileOutputStream fOutStream = new FileOutputStream(fontFile);
+
+        bRead = buffStream.read(buf, 0, size);
+
+        while (bRead != -1) {
+            fOutStream.write(buf, 0, bRead);
+            bRead = buffStream.read(buf, 0, size);
+        }
+
+        buffStream.close();
+        fOutStream.close();
+
+        Font font = null;
+
+        font = Toolkit.getDefaultToolkit().getGraphicsFactory().embedFont(
+                fontFile.getAbsolutePath());
+        if (font == null) { // awt.9B=Can't create font - bad font data
+            throw new FontFormatException(Messages.getString("awt.9B")); //$NON-NLS-1$
+        }
+        return font;
+    }
+
+}
diff --git a/awt/java/awt/FontFormatException.java b/awt/java/awt/FontFormatException.java
new file mode 100644
index 0000000..806711a
--- /dev/null
+++ b/awt/java/awt/FontFormatException.java
@@ -0,0 +1,47 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package java.awt;
+
+/**
+ * The FontFormatException class is used to provide notification and information
+ * that font can't be created.
+ * 
+ * @since Android 1.0
+ */
+public class FontFormatException extends Exception {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -4481290147811361272L;
+
+    /**
+     * Instantiates a new font format exception with detailed message.
+     * 
+     * @param reason
+     *            the detailed message.
+     */
+    public FontFormatException(String reason) {
+        super(reason);
+    }
+
+}
diff --git a/awt/java/awt/FontMetrics.java b/awt/java/awt/FontMetrics.java
new file mode 100644
index 0000000..9082626
--- /dev/null
+++ b/awt/java/awt/FontMetrics.java
@@ -0,0 +1,466 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.awt.geom.Rectangle2D;
+import java.io.Serializable;
+import java.text.CharacterIterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The FontMetrics class contains information about the rendering of a
+ * particular font on a particular screen.
+ * <p>
+ * Each character in the Font has three values that help define where to place
+ * it: an ascent, a descent, and an advance. The ascent is the distance the
+ * character extends above the baseline. The descent is the distance the
+ * character extends below the baseline. The advance width defines the position
+ * at which the next character should be placed.
+ * <p>
+ * An array of characters or a string has an ascent, a descent, and an advance
+ * width too. The ascent or descent of the array is specified by the maximum
+ * ascent or descent of the characters in the array. The advance width is the
+ * sum of the advance widths of each of the characters in the character array.
+ * </p>
+ * 
+ * @since Android 1.0
+ */
+public abstract class FontMetrics implements Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 1681126225205050147L;
+
+    /**
+     * The font from which the FontMetrics is created.
+     */
+    protected Font font;
+
+    /**
+     * Instantiates a new font metrics from the specified Font.
+     * 
+     * @param fnt
+     *            the Font.
+     */
+    protected FontMetrics(Font fnt) {
+        this.font = fnt;
+    }
+
+    /**
+     * Returns the String representation of this FontMetrics.
+     * 
+     * @return the string.
+     */
+    @Override
+    public String toString() {
+        return this.getClass().getName() + "[font=" + this.getFont() + //$NON-NLS-1$
+                "ascent=" + this.getAscent() + //$NON-NLS-1$
+                ", descent=" + this.getDescent() + //$NON-NLS-1$
+                ", height=" + this.getHeight() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+    /**
+     * Gets the font associated with this FontMetrics.
+     * 
+     * @return the font associated with this FontMetrics.
+     */
+    public Font getFont() {
+        return font;
+    }
+
+    /**
+     * Gets the height of the text line in this Font.
+     * 
+     * @return the height of the text line in this Font.
+     */
+    public int getHeight() {
+        return this.getAscent() + this.getDescent() + this.getLeading();
+    }
+
+    /**
+     * Gets the font ascent of the Font associated with this FontMetrics. The
+     * font ascent is the distance from the font's baseline to the top of most
+     * alphanumeric characters.
+     * 
+     * @return the ascent of the Font associated with this FontMetrics.
+     */
+    public int getAscent() {
+        return 0;
+    }
+
+    /**
+     * Gets the font descent of the Font associated with this FontMetrics. The
+     * font descent is the distance from the font's baseline to the bottom of
+     * most alphanumeric characters with descenders.
+     * 
+     * @return the descent of the Font associated with this FontMetrics.
+     */
+    public int getDescent() {
+        return 0;
+    }
+
+    /**
+     * Gets the leading of the Font associated with this FontMetrics.
+     * 
+     * @return the leading of the Font associated with this FontMetrics.
+     */
+    public int getLeading() {
+        return 0;
+    }
+
+    /**
+     * Gets the LineMetrics object for the specified CharacterIterator in the
+     * specified Graphics.
+     * 
+     * @param ci
+     *            the CharacterIterator.
+     * @param beginIndex
+     *            the offset.
+     * @param limit
+     *            the number of characters to be used.
+     * @param context
+     *            the Graphics.
+     * @return the LineMetrics object for the specified CharacterIterator in the
+     *         specified Graphics.
+     */
+    public LineMetrics getLineMetrics(CharacterIterator ci, int beginIndex, int limit,
+            Graphics context) {
+        return font.getLineMetrics(ci, beginIndex, limit, this.getFRCFromGraphics(context));
+    }
+
+    /**
+     * Gets the LineMetrics object for the specified String in the specified
+     * Graphics.
+     * 
+     * @param str
+     *            the String.
+     * @param context
+     *            the Graphics.
+     * @return the LineMetrics object for the specified String in the specified
+     *         Graphics.
+     */
+    public LineMetrics getLineMetrics(String str, Graphics context) {
+        return font.getLineMetrics(str, this.getFRCFromGraphics(context));
+    }
+
+    /**
+     * Gets the LineMetrics object for the specified character array in the
+     * specified Graphics.
+     * 
+     * @param chars
+     *            the character array.
+     * @param beginIndex
+     *            the offset of array.
+     * @param limit
+     *            the number of characters to be used.
+     * @param context
+     *            the Graphics.
+     * @return the LineMetrics object for the specified character array in the
+     *         specified Graphics.
+     */
+    public LineMetrics getLineMetrics(char[] chars, int beginIndex, int limit, Graphics context) {
+        return font.getLineMetrics(chars, beginIndex, limit, this.getFRCFromGraphics(context));
+    }
+
+    /**
+     * Gets the LineMetrics object for the specified String in the specified
+     * Graphics.
+     * 
+     * @param str
+     *            the String.
+     * @param beginIndex
+     *            the offset.
+     * @param limit
+     *            the number of characters to be used.
+     * @param context
+     *            the Graphics.
+     * @return the LineMetrics object for the specified String in the specified
+     *         Graphics.
+     */
+    public LineMetrics getLineMetrics(String str, int beginIndex, int limit, Graphics context) {
+        return font.getLineMetrics(str, beginIndex, limit, this.getFRCFromGraphics(context));
+    }
+
+    /**
+     * Returns the character's maximum bounds in the specified Graphics context.
+     * 
+     * @param context
+     *            the Graphics context.
+     * @return the character's maximum bounds in the specified Graphics context.
+     */
+    public Rectangle2D getMaxCharBounds(Graphics context) {
+        return this.font.getMaxCharBounds(this.getFRCFromGraphics(context));
+    }
+
+    /**
+     * Gets the bounds of the specified CharacterIterator in the specified
+     * Graphics context.
+     * 
+     * @param ci
+     *            the CharacterIterator.
+     * @param beginIndex
+     *            the begin offset of the array.
+     * @param limit
+     *            the number of characters.
+     * @param context
+     *            the Graphics.
+     * @return the bounds of the specified CharacterIterator in the specified
+     *         Graphics context.
+     */
+    public Rectangle2D getStringBounds(CharacterIterator ci, int beginIndex, int limit,
+            Graphics context) {
+        return font.getStringBounds(ci, beginIndex, limit, this.getFRCFromGraphics(context));
+    }
+
+    /**
+     * Gets the bounds of the specified String in the specified Graphics
+     * context.
+     * 
+     * @param str
+     *            the String.
+     * @param beginIndex
+     *            the begin offset of the array.
+     * @param limit
+     *            the number of characters.
+     * @param context
+     *            the Graphics.
+     * @return the bounds of the specified String in the specified Graphics
+     *         context.
+     */
+    public Rectangle2D getStringBounds(String str, int beginIndex, int limit, Graphics context) {
+        return font.getStringBounds(str, beginIndex, limit, this.getFRCFromGraphics(context));
+    }
+
+    /**
+     * Gets the bounds of the specified characters array in the specified
+     * Graphics context.
+     * 
+     * @param chars
+     *            the characters array.
+     * @param beginIndex
+     *            the begin offset of the array.
+     * @param limit
+     *            the number of characters.
+     * @param context
+     *            the Graphics.
+     * @return the bounds of the specified characters array in the specified
+     *         Graphics context.
+     */
+    public Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit, Graphics context) {
+        return font.getStringBounds(chars, beginIndex, limit, this.getFRCFromGraphics(context));
+    }
+
+    /**
+     * Gets the bounds of the specified String in the specified Graphics
+     * context.
+     * 
+     * @param str
+     *            the String.
+     * @param context
+     *            the Graphics.
+     * @return the bounds of the specified String in the specified Graphics
+     *         context.
+     */
+    public Rectangle2D getStringBounds(String str, Graphics context) {
+        return font.getStringBounds(str, this.getFRCFromGraphics(context));
+    }
+
+    /**
+     * Checks if the Font has uniform line metrics or not. The Font can contain
+     * characters of other fonts for covering character set. In this case the
+     * Font isn't uniform.
+     * 
+     * @return true, if the Font has uniform line metrics, false otherwise.
+     */
+    public boolean hasUniformLineMetrics() {
+        return this.font.hasUniformLineMetrics();
+    }
+
+    /**
+     * Returns the distance from the leftmost point to the rightmost point on
+     * the string's baseline showing the specified array of bytes in this Font.
+     * 
+     * @param data
+     *            the array of bytes to be measured.
+     * @param off
+     *            the start offset.
+     * @param len
+     *            the number of bytes to be measured.
+     * @return the advance width of the array.
+     */
+    public int bytesWidth(byte[] data, int off, int len) {
+        int width = 0;
+        if ((off >= data.length) || (off < 0)) {
+            // awt.13B=offset off is out of range
+            throw new IllegalArgumentException(Messages.getString("awt.13B")); //$NON-NLS-1$
+        }
+
+        if ((off + len > data.length)) {
+            // awt.13C=number of elemets len is out of range
+            throw new IllegalArgumentException(Messages.getString("awt.13C")); //$NON-NLS-1$
+        }
+
+        for (int i = off; i < off + len; i++) {
+            width += charWidth(data[i]);
+        }
+
+        return width;
+    }
+
+    /**
+     * Returns the distance from the leftmost point to the rightmost point on
+     * the string's baseline showing the specified array of characters in this
+     * Font.
+     * 
+     * @param data
+     *            the array of characters to be measured.
+     * @param off
+     *            the start offset.
+     * @param len
+     *            the number of bytes to be measured.
+     * @return the advance width of the array.
+     */
+    public int charsWidth(char[] data, int off, int len) {
+        int width = 0;
+        if ((off >= data.length) || (off < 0)) {
+            // awt.13B=offset off is out of range
+            throw new IllegalArgumentException(Messages.getString("awt.13B")); //$NON-NLS-1$
+        }
+
+        if ((off + len > data.length)) {
+            // awt.13C=number of elemets len is out of range
+            throw new IllegalArgumentException(Messages.getString("awt.13C")); //$NON-NLS-1$
+        }
+
+        for (int i = off; i < off + len; i++) {
+            width += charWidth(data[i]);
+        }
+
+        return width;
+    }
+
+    /**
+     * Returns the distance from the leftmost point to the rightmost point of
+     * the specified character in this Font.
+     * 
+     * @param ch
+     *            the specified Unicode point code of character to be measured.
+     * @return the advance width of the character.
+     */
+    public int charWidth(int ch) {
+        return 0;
+    }
+
+    /**
+     * Returns the distance from the leftmost point to the rightmost point of
+     * the specified character in this Font.
+     * 
+     * @param ch
+     *            the specified character to be measured.
+     * @return the advance width of the character.
+     */
+    public int charWidth(char ch) {
+        return 0;
+    }
+
+    /**
+     * Gets the maximum advance width of character in this Font.
+     * 
+     * @return the maximum advance width of character in this Font.
+     */
+    public int getMaxAdvance() {
+        return 0;
+    }
+
+    /**
+     * Gets the maximum font ascent of the Font associated with this
+     * FontMetrics.
+     * 
+     * @return the maximum font ascent of the Font associated with this
+     *         FontMetrics.
+     */
+    public int getMaxAscent() {
+        return 0;
+    }
+
+    /**
+     * Gets the maximum font descent of character in this Font.
+     * 
+     * @return the maximum font descent of character in this Font.
+     * @deprecated Replaced by getMaxDescent() method.
+     */
+    @Deprecated
+    public int getMaxDecent() {
+        return 0;
+    }
+
+    /**
+     * Gets the maximum font descent of character in this Font.
+     * 
+     * @return the maximum font descent of character in this Font.
+     */
+    public int getMaxDescent() {
+        return 0;
+    }
+
+    /**
+     * Gets the advance widths of the characters in the Font.
+     * 
+     * @return the advance widths of the characters in the Font.
+     */
+    public int[] getWidths() {
+        return null;
+    }
+
+    /**
+     * Returns the advance width for the specified String in this Font.
+     * 
+     * @param str
+     *            String to be measured.
+     * @return the the advance width for the specified String in this Font.
+     */
+    public int stringWidth(String str) {
+        return 0;
+    }
+
+    /**
+     * Returns a FontRenderContext instance of the Graphics context specified.
+     * 
+     * @param context
+     *            the specified Graphics context.
+     * @return a FontRenderContext of the specified Graphics context.
+     */
+    private FontRenderContext getFRCFromGraphics(Graphics context) {
+        FontRenderContext frc;
+        if (context instanceof Graphics2D) {
+            frc = ((Graphics2D)context).getFontRenderContext();
+        } else {
+            frc = new FontRenderContext(null, false, false);
+        }
+
+        return frc;
+    }
+}
diff --git a/awt/java/awt/GradientPaint.java b/awt/java/awt/GradientPaint.java
new file mode 100644
index 0000000..3b32ef5
--- /dev/null
+++ b/awt/java/awt/GradientPaint.java
@@ -0,0 +1,255 @@
+/*
+ *  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.
+ */
+
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GradientPaint class defines a way to fill a Shape with a linear color
+ * gradient pattern.
+ * <p>
+ * The GradientPaint's fill pattern is determined by two points and two colors,
+ * plus the cyclic mode option. Each of the two points is painted with its
+ * corresponding color, and on the line segment connecting the two points, the
+ * color is proportionally changed between the two colors. For points on the
+ * same line which are not between the two specified points (outside of the
+ * connecting segment) their color is determined by the cyclic mode option. If
+ * the mode is cyclic, then the rest of the line repeats the color pattern of
+ * the connecting segment, cycling back and forth between the two colors. If
+ * not, the mode is acyclic which means that all points on the line outside the
+ * connecting line segment are given the same color as the closest of the two
+ * specified points.
+ * <p>
+ * The color of points that are not on the line connecting the two specified
+ * points are given by perpendicular projection: by taking the set of lines
+ * perpendicular to the connecting line and for each one, the whole line is
+ * colored with the same color.
+ * 
+ * @since Android 1.0
+ */
+public class GradientPaint implements Paint {
+
+    /**
+     * The start point color.
+     */
+    Color color1;
+
+    /**
+     * The end color point.
+     */
+    Color color2;
+
+    /**
+     * The location of the start point.
+     */
+    Point2D point1;
+
+    /**
+     * The location of the end point.
+     */
+    Point2D point2;
+
+    /**
+     * The indicator of cycle filling. If TRUE filling repeated outside points
+     * stripe, if FALSE solid color filling outside.
+     */
+    boolean cyclic;
+
+    /**
+     * Instantiates a new GradientPaint with cyclic or acyclic mode.
+     * 
+     * @param point1
+     *            the first specified point.
+     * @param color1
+     *            the Color of the first specified point.
+     * @param point2
+     *            the second specified point.
+     * @param color2
+     *            the Color of the second specified point.
+     * @param cyclic
+     *            the cyclic mode - true if the gradient pattern should cycle
+     *            repeatedly between the two colors; false otherwise.
+     */
+    public GradientPaint(Point2D point1, Color color1, Point2D point2, Color color2, boolean cyclic) {
+        if (point1 == null || point2 == null) {
+            // awt.6D=Point is null
+            throw new NullPointerException(Messages.getString("awt.6D")); //$NON-NLS-1$
+        }
+        if (color1 == null || color2 == null) {
+            // awt.6E=Color is null
+            throw new NullPointerException(Messages.getString("awt.6E")); //$NON-NLS-1$
+        }
+
+        this.point1 = point1;
+        this.point2 = point2;
+        this.color1 = color1;
+        this.color2 = color2;
+        this.cyclic = cyclic;
+    }
+
+    /**
+     * Instantiates a new GradientPaint with cyclic or acyclic mode; points are
+     * specified by coordinates.
+     * 
+     * @param x1
+     *            the X coordinate of the first point.
+     * @param y1
+     *            the Y coordinate of the first point.
+     * @param color1
+     *            the color of the first point.
+     * @param x2
+     *            the X coordinate of the second point.
+     * @param y2
+     *            the Y coordinate of the second point.
+     * @param color2
+     *            the color of the second point.
+     * @param cyclic
+     *            the cyclic mode - true if the gradient pattern should cycle
+     *            repeatedly between the two colors; false otherwise.
+     */
+    public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2,
+            boolean cyclic) {
+        this(new Point2D.Float(x1, y1), color1, new Point2D.Float(x2, y2), color2, cyclic);
+    }
+
+    /**
+     * Instantiates a new acyclic GradientPaint; points are specified by
+     * coordinates.
+     * 
+     * @param x1
+     *            the X coordinate of the first point.
+     * @param y1
+     *            the Y coordinate of the first point.
+     * @param color1
+     *            the color of the first point.
+     * @param x2
+     *            the X coordinate of the second point.
+     * @param y2
+     *            the Y coordinate of the second point.
+     * @param color2
+     *            the color of the second point.
+     */
+    public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2) {
+        this(x1, y1, color1, x2, y2, color2, false);
+    }
+
+    /**
+     * Instantiates a new acyclic GradientPaint.
+     * 
+     * @param point1
+     *            the first specified point.
+     * @param color1
+     *            the Color of the first specified point.
+     * @param point2
+     *            the second specified point.
+     * @param color2
+     *            the Color of the second specified point.
+     */
+    public GradientPaint(Point2D point1, Color color1, Point2D point2, Color color2) {
+        this(point1, color1, point2, color2, false);
+    }
+
+    /**
+     * Creates PaintContext for a color pattern generating.
+     * 
+     * @param cm
+     *            the ColorModel of the Paint data.
+     * @param deviceBounds
+     *            the bounding Rectangle of graphics primitives being rendered
+     *            in the device space.
+     * @param userBounds
+     *            the bounding Rectangle of graphics primitives being rendered
+     *            in the user space.
+     * @param t
+     *            the AffineTransform from user space into device space.
+     * @param hints
+     *            the RrenderingHints object.
+     * @return the PaintContext for color pattern generating.
+     * @see java.awt.Paint#createContext(java.awt.image.ColorModel,
+     *      java.awt.Rectangle, java.awt.geom.Rectangle2D,
+     *      java.awt.geom.AffineTransform, java.awt.RenderingHints)
+     */
+    public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
+            Rectangle2D userBounds, AffineTransform t, RenderingHints hints) {
+        return new GradientPaintContext(cm, t, point1, color1, point2, color2, cyclic);
+    }
+
+    /**
+     * Gets the color of the first point.
+     * 
+     * @return the color of the first point.
+     */
+    public Color getColor1() {
+        return color1;
+    }
+
+    /**
+     * Gets the color of the second point.
+     * 
+     * @return the color of the second point.
+     */
+    public Color getColor2() {
+        return color2;
+    }
+
+    /**
+     * Gets the first point.
+     * 
+     * @return the Point object - the first point.
+     */
+    public Point2D getPoint1() {
+        return point1;
+    }
+
+    /**
+     * Gets the second point.
+     * 
+     * @return the Point object - the second point.
+     */
+    public Point2D getPoint2() {
+        return point2;
+    }
+
+    /**
+     * Gets the transparency mode for the GradientPaint.
+     * 
+     * @return the transparency mode for the GradientPaint.
+     * @see java.awt.Transparency#getTransparency()
+     */
+    public int getTransparency() {
+        int a1 = color1.getAlpha();
+        int a2 = color2.getAlpha();
+        return (a1 == 0xFF && a2 == 0xFF) ? OPAQUE : TRANSLUCENT;
+    }
+
+    /**
+     * Returns the GradientPaint mode: true for cyclic mode, false for acyclic
+     * mode.
+     * 
+     * @return true if the gradient cycles repeatedly between the two colors;
+     *         false otherwise.
+     */
+    public boolean isCyclic() {
+        return cyclic;
+    }
+}
diff --git a/awt/java/awt/GradientPaintContext.java b/awt/java/awt/GradientPaintContext.java
new file mode 100644
index 0000000..74575f5
--- /dev/null
+++ b/awt/java/awt/GradientPaintContext.java
@@ -0,0 +1,204 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferInt;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+class GradientPaintContext implements PaintContext {
+
+    /**
+     * The size of noncyclic part of color lookup table
+     */
+    static int LOOKUP_SIZE = 256;
+    
+    /**
+     * The index mask to lookup color in the table
+     */
+    static int LOOKUP_MASK = 0x1FF;
+    
+    /**
+     * The min value equivalent to zero. If absolute value less then ZERO it considered as zero.  
+     */
+    static double ZERO = 1E-10;
+
+    /**
+     * The ColorModel user defined for PaintContext
+     */
+    ColorModel cm;
+    
+    /**
+     * The indicator of cycle filling.
+     */
+    boolean cyclic;
+    
+    /**
+     * The integer color value of the start point
+     */
+    int c1;
+    
+    /**
+     * The integer color value of the end point
+     */
+    int c2;
+    
+    /**
+     * The lookup gradient color table 
+     */
+    int[] table;
+
+    /**
+     * The tempopary pre-calculated value to evalutae color index 
+     */
+    int dx;
+    
+    /**
+     * The tempopary pre-calculated value to evalutae color index 
+     */
+    int dy;
+    
+    /**
+     * The tempopary pre-calculated value to evalutae color index 
+     */
+    int delta;
+    
+    /**
+     * Constructs a new GradientPaintcontext
+     * @param cm - not used
+     * @param t - the fill transformation
+     * @param point1 - the start fill point
+     * @param color1 - color of the start point 
+     * @param point2 - the end fill point
+     * @param color2 - color of the end point
+     * @param cyclic - the indicator of cycle filling
+     */
+    GradientPaintContext(ColorModel cm, AffineTransform t, Point2D point1, Color color1, Point2D point2, Color color2, boolean cyclic) {
+        this.cyclic = cyclic;
+        this.cm = ColorModel.getRGBdefault();
+
+        c1 = color1.getRGB();
+        c2 = color2.getRGB();
+
+        double px = point2.getX() - point1.getX();
+        double py = point2.getY() - point1.getY();
+
+        Point2D p = t.transform(point1, null);
+        Point2D bx = new Point2D.Double(px, py);
+        Point2D by = new Point2D.Double(py, -px);
+
+        t.deltaTransform(bx, bx);
+        t.deltaTransform(by, by);
+
+        double vec = bx.getX() * by.getY() - bx.getY() * by.getX();
+
+        if (Math.abs(vec) < ZERO) {
+            dx = dy = delta = 0;
+            table = new int[1];
+            table[0] = c1;
+        } else {
+            double mult = LOOKUP_SIZE * 256 / vec;
+            dx = (int)(by.getX() * mult);
+            dy = (int)(by.getY() * mult);
+            delta = (int)((p.getX() * by.getY() - p.getY() * by.getX()) * mult);
+            createTable();
+        }
+    }
+
+    /**
+     * Create color index lookup table. Calculate 256 step trasformation from 
+     * the start point color to the end point color. Colors multiplied by 256 to do integer calculations. 
+     */
+    void createTable() {
+        double ca = (c1 >> 24) & 0xFF;
+        double cr = (c1 >> 16) & 0xFF;
+        double cg = (c1 >> 8) & 0xFF;
+        double cb = c1 & 0xFF;
+
+        double k = 1.0 / LOOKUP_SIZE;
+        double da = (((c2 >> 24) & 0xFF) - ca) * k;
+        double dr = (((c2 >> 16) & 0xFF) - cr) * k;
+        double dg = (((c2 >> 8) & 0xFF) - cg) * k;
+        double db = ((c2 & 0xFF) - cb) * k;
+
+        table = new int[cyclic ? LOOKUP_SIZE + LOOKUP_SIZE : LOOKUP_SIZE];
+        for(int i = 0; i < LOOKUP_SIZE; i++) {
+            table[i] =
+                (int)ca << 24 |
+                (int)cr << 16 |
+                (int)cg << 8 |
+                (int)cb;
+            ca += da;
+            cr += dr;
+            cg += dg;
+            cb += db;
+        }
+        if (cyclic) {
+            for(int i = 0; i < LOOKUP_SIZE; i++) {
+                table[LOOKUP_SIZE + LOOKUP_SIZE - 1 - i] = table[i];
+            }
+        }
+    }
+
+    public ColorModel getColorModel() {
+        return cm;
+    }
+
+    public void dispose() {
+    }
+
+    public Raster getRaster(int x, int y, int w, int h) {
+        WritableRaster rast = cm.createCompatibleWritableRaster(w, h);
+
+        int[] buf = ((DataBufferInt)rast.getDataBuffer()).getData();
+
+        int c = x * dy - y * dx - delta;
+        int cx = dy;
+        int cy = - w * dy - dx;
+        int k = 0;
+
+        if (cyclic) {
+            for(int j = 0; j < h; j++) {
+                for(int i = 0; i < w; i++) {
+                    buf[k++] = table[(c >> 8) & LOOKUP_MASK];
+                    c += cx;
+                }
+                c += cy;
+            }
+        } else {
+            for(int j = 0; j < h; j++) {
+                for(int i = 0; i < w; i++) {
+                    int index = c >> 8;
+                    buf[k++] = index < 0 ? c1 : index >= LOOKUP_SIZE ? c2 : table[index];
+                    c += cx;
+                }
+                c += cy;
+            }
+        }
+
+        return rast;
+    }
+
+}
+
diff --git a/awt/java/awt/Graphics.java b/awt/java/awt/Graphics.java
new file mode 100644
index 0000000..2d6e79f
--- /dev/null
+++ b/awt/java/awt/Graphics.java
@@ -0,0 +1,924 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.image.ImageObserver;
+import java.text.AttributedCharacterIterator;
+
+/**
+ * The abstract Graphics class allows applications to draw on a screen or other
+ * rendering target. There are several properties which define rendering
+ * options: origin point, clipping area, color, font. <br>
+ * <br>
+ * The origin point specifies the beginning of the clipping area coordinate
+ * system. All coordinates used in rendering operations are computed with
+ * respect to this point. The clipping area defines the boundaries where
+ * rendering operations can be performed. Rendering operations can't modify
+ * pixels outside of the clipping area. <br>
+ * <br>
+ * The draw and fill methods allow applications to drawing shapes, text, images
+ * with specified font and color options in the specified part of the screen.
+ * 
+ * @since Android 1.0
+ */
+public abstract class Graphics {
+
+    // Constructors
+
+    /**
+     * Instantiates a new Graphics. This constructor is default for Graphics and
+     * can not be called directly.
+     */
+    protected Graphics() {
+    }
+
+    // Public methods
+
+    /**
+     * Creates a copy of the Graphics object with a new origin and a new
+     * specified clip area. The new clip area is the rectangle defined by the
+     * origin point with coordinates X,Y and the given width and height. The
+     * coordinates of all subsequent rendering operations will be computed with
+     * respect to the new origin and can be performed only within the range of
+     * the clipping area dimensions.
+     * 
+     * @param x
+     *            the X coordinate of the original point.
+     * @param y
+     *            the Y coordinate of the original point.
+     * @param width
+     *            the width of clipping area.
+     * @param height
+     *            the height of clipping area.
+     * @return the Graphics object with new origin point and clipping area.
+     */
+    public Graphics create(int x, int y, int width, int height) {
+        Graphics res = create();
+        res.translate(x, y);
+        res.clipRect(0, 0, width, height);
+        return res;
+    }
+
+    /**
+     * Draws the highlighted outline of a rectangle.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle's top left corner.
+     * @param y
+     *            the Y coordinate of the rectangle's top left corner.
+     * @param width
+     *            the width of rectangle.
+     * @param height
+     *            the height of rectangle.
+     * @param raised
+     *            a boolean value that determines whether the rectangle is drawn
+     *            as raised or indented.
+     */
+    public void draw3DRect(int x, int y, int width, int height, boolean raised) {
+        // Note: lighter/darker colors should be used to draw 3d rect.
+        // The resulting rect is (width+1)x(height+1). Stroke and paint
+        // attributes of
+        // the Graphics2D should be reset to the default values.
+        // fillRect is used instead of drawLine to bypass stroke
+        // reset/set and rasterization.
+
+        Color color = getColor();
+        Color colorUp, colorDown;
+        if (raised) {
+            colorUp = color.brighter();
+            colorDown = color.darker();
+        } else {
+            colorUp = color.darker();
+            colorDown = color.brighter();
+        }
+
+        setColor(colorUp);
+        fillRect(x, y, width, 1);
+        fillRect(x, y + 1, 1, height);
+
+        setColor(colorDown);
+        fillRect(x + width, y, 1, height);
+        fillRect(x + 1, y + height, width, 1);
+    }
+
+    /**
+     * Draws the text represented by byte array. This method uses the current
+     * font and color for rendering.
+     * 
+     * @param bytes
+     *            the byte array which contains the text to be drawn.
+     * @param off
+     *            the offset within the byte array of the text to be drawn.
+     * @param len
+     *            the number of bytes of text to draw.
+     * @param x
+     *            the X coordinate where the text is to be drawn.
+     * @param y
+     *            the Y coordinate where the text is to be drawn.
+     */
+    public void drawBytes(byte[] bytes, int off, int len, int x, int y) {
+        drawString(new String(bytes, off, len), x, y);
+    }
+
+    /**
+     * Draws the text represented by character array. This method uses the
+     * current font and color for rendering.
+     * 
+     * @param chars
+     *            the character array.
+     * @param off
+     *            the offset within the character array of the text to be drawn.
+     * @param len
+     *            the number of characters which will be drawn.
+     * @param x
+     *            the X coordinate where the text is to be drawn.
+     * @param y
+     *            the Y coordinate where the text is to be drawn.
+     */
+    public void drawChars(char[] chars, int off, int len, int x, int y) {
+        drawString(new String(chars, off, len), x, y);
+    }
+
+    /**
+     * Draws the outline of a polygon which is defined by Polygon object.
+     * 
+     * @param p
+     *            the Polygon object.
+     */
+    public void drawPolygon(Polygon p) {
+        drawPolygon(p.xpoints, p.ypoints, p.npoints);
+    }
+
+    /**
+     * Draws the rectangle with the specified width and length and top left
+     * corner coordinates.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle's top left corner.
+     * @param y
+     *            the Y coordinate of the rectangle's top left corner.
+     * @param width
+     *            the width of the rectangle.
+     * @param height
+     *            the height of the rectangle.
+     */
+    public void drawRect(int x, int y, int width, int height) {
+        int[] xpoints = {
+                x, x, x + width, x + width
+        };
+        int[] ypoints = {
+                y, y + height, y + height, y
+        };
+
+        drawPolygon(xpoints, ypoints, 4);
+    }
+
+    /**
+     * Fills the highlighted outline of a rectangle.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle's top left corner.
+     * @param y
+     *            the Y coordinate of the rectangle's top left corner.
+     * @param width
+     *            the width of the rectangle.
+     * @param height
+     *            the height of the rectangle.
+     * @param raised
+     *            a boolean value that determines whether the rectangle is drawn
+     *            as raised or indented.
+     */
+    public void fill3DRect(int x, int y, int width, int height, boolean raised) {
+        // Note: lighter/darker colors should be used to draw 3d rect.
+        // The resulting rect is (width)x(height), same as fillRect.
+        // Stroke and paint attributes of the Graphics2D should be reset
+        // to the default values. fillRect is used instead of drawLine to
+        // bypass stroke reset/set and line rasterization.
+
+        Color color = getColor();
+        Color colorUp, colorDown;
+        if (raised) {
+            colorUp = color.brighter();
+            colorDown = color.darker();
+            setColor(color);
+        } else {
+            colorUp = color.darker();
+            colorDown = color.brighter();
+            setColor(colorUp);
+        }
+
+        width--;
+        height--;
+        fillRect(x + 1, y + 1, width - 1, height - 1);
+
+        setColor(colorUp);
+        fillRect(x, y, width, 1);
+        fillRect(x, y + 1, 1, height);
+
+        setColor(colorDown);
+        fillRect(x + width, y, 1, height);
+        fillRect(x + 1, y + height, width, 1);
+    }
+
+    /**
+     * Fills the polygon with the current color.
+     * 
+     * @param p
+     *            the Polygon object.
+     */
+    public void fillPolygon(Polygon p) {
+        fillPolygon(p.xpoints, p.ypoints, p.npoints);
+    }
+
+    /**
+     * Disposes of the Graphics.
+     */
+    @Override
+    public void finalize() {
+    }
+
+    /**
+     * Gets the bounds of the current clipping area as a rectangle and copies it
+     * to an existing rectangle.
+     * 
+     * @param r
+     *            a Rectangle object where the current clipping area bounds are
+     *            to be copied.
+     * @return the bounds of the current clipping area.
+     */
+    public Rectangle getClipBounds(Rectangle r) {
+        Shape clip = getClip();
+
+        if (clip != null) {
+            // TODO: Can we get shape bounds without creating Rectangle object?
+            Rectangle b = clip.getBounds();
+            r.x = b.x;
+            r.y = b.y;
+            r.width = b.width;
+            r.height = b.height;
+        }
+
+        return r;
+    }
+
+    /**
+     * Gets the bounds of the current clipping area as a rectangle.
+     * 
+     * @return a Rectangle object.
+     * @deprecated Use {@link #getClipBounds()}
+     */
+    @Deprecated
+    public Rectangle getClipRect() {
+        return getClipBounds();
+    }
+
+    /**
+     * Gets the font metrics of the current font. The font metrics object
+     * contains information about the rendering of a particular font.
+     * 
+     * @return the font metrics of current font.
+     */
+    public FontMetrics getFontMetrics() {
+        return getFontMetrics(getFont());
+    }
+
+    /**
+     * Determines whether or not the specified rectangle intersects the current
+     * clipping area.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle.
+     * @param y
+     *            the Y coordinate of the rectangle.
+     * @param width
+     *            the width of the rectangle.
+     * @param height
+     *            the height of the rectangle.
+     * @return true, if the specified rectangle intersects the current clipping
+     *         area, false otherwise.
+     */
+    public boolean hitClip(int x, int y, int width, int height) {
+        // TODO: Create package private method Rectangle.intersects(int, int,
+        // int, int);
+        return getClipBounds().intersects(new Rectangle(x, y, width, height));
+    }
+
+    /**
+     * Returns string which represents this Graphics object.
+     * 
+     * @return the string which represents this Graphics object.
+     */
+    @Override
+    public String toString() {
+        // TODO: Think about string representation of Graphics.
+        return "Graphics"; //$NON-NLS-1$
+    }
+
+    // Abstract methods
+
+    /**
+     * Clears the specified rectangle. This method fills specified rectangle
+     * with background color.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle.
+     * @param y
+     *            the Y coordinate of the rectangle.
+     * @param width
+     *            the width of the rectangle.
+     * @param height
+     *            the height of the rectangle.
+     */
+    public abstract void clearRect(int x, int y, int width, int height);
+
+    /**
+     * Intersects the current clipping area with a new rectangle. If the current
+     * clipping area is not defined, the rectangle becomes a new clipping area.
+     * Rendering operations are only allowed within the new the clipping area.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle for intersection.
+     * @param y
+     *            the Y coordinate of the rectangle for intersection.
+     * @param width
+     *            the width of the rectangle for intersection.
+     * @param height
+     *            the height of the rectangle for intersection.
+     */
+    public abstract void clipRect(int x, int y, int width, int height);
+
+    /**
+     * Copies the rectangle area to another area specified by a distance (dx,
+     * dy) from the original rectangle's location. Positive dx and dy values
+     * give a new location defined by translation to the right and down from the
+     * original location, negative dx and dy values - to the left and up.
+     * 
+     * @param sx
+     *            the X coordinate of the rectangle which will be copied.
+     * @param sy
+     *            the Y coordinate of the rectangle which will be copied.
+     * @param width
+     *            the width of the rectangle which will be copied.
+     * @param height
+     *            the height of the rectangle which will be copied.
+     * @param dx
+     *            the horizontal distance from the source rectangle's location
+     *            to the copy's location.
+     * @param dy
+     *            the vertical distance from the source rectangle's location to
+     *            the copy's location.
+     */
+    public abstract void copyArea(int sx, int sy, int width, int height, int dx, int dy);
+
+    /**
+     * Creates a new copy of this Graphics.
+     * 
+     * @return a new Graphics context which is a copy of this Graphics.
+     */
+    public abstract Graphics create();
+
+    /**
+     * Disposes of the Graphics. This Graphics object can not be used after
+     * calling this method.
+     */
+    public abstract void dispose();
+
+    /**
+     * Draws the arc covering the specified rectangle and using the current
+     * color. The rectangle is defined by the origin point (X, Y) and dimensions
+     * (width and height). The arc center is the the center of specified
+     * rectangle. The angle origin is 3 o'clock position, the positive angle is
+     * counted as a counter-clockwise rotation, the negative angle is counted as
+     * clockwise rotation.
+     * 
+     * @param x
+     *            the X origin coordinate of the rectangle which scales the arc.
+     * @param y
+     *            the Y origin coordinate of the rectangle which scales the arc.
+     * @param width
+     *            the width of the rectangle which scales the arc.
+     * @param height
+     *            the height of the rectangle which scales the arc.
+     * @param sa
+     *            start angle - the origin angle of arc.
+     * @param ea
+     *            arc angle - the angular arc value relative to the start angle.
+     */
+    public abstract void drawArc(int x, int y, int width, int height, int sa, int ea);
+
+    /**
+     * Draws the specified image with the defined background color. The top left
+     * corner of image will be drawn at point (x, y) in current coordinate
+     * system. The image loading process notifies the specified Image Observer.
+     * This method returns true if the image has loaded, otherwise it returns
+     * false.
+     * 
+     * @param img
+     *            the image which will be drawn.
+     * @param x
+     *            the X coordinate of the image top left corner.
+     * @param y
+     *            the Y coordinate of the image top left corner.
+     * @param bgcolor
+     *            the background color.
+     * @param observer
+     *            the ImageObserver object which should be notified about image
+     *            loading process.
+     * @return true, if loading image is successful or image is null, false
+     *         otherwise.
+     */
+    public abstract boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer);
+
+    /**
+     * Draws the specified image. The top left corner of image will be drawn at
+     * point (x, y) in current coordinate system. The image loading process
+     * notifies the specified Image Observer. This method returns true if the
+     * image has loaded, otherwise it returns false.
+     * 
+     * @param img
+     *            the image which will be drawn.
+     * @param x
+     *            the X coordinate of the image top left corner.
+     * @param y
+     *            the Y coordinate of the image top left corner.
+     * @param observer
+     *            the ImageObserver object which should be notified about image
+     *            loading process.
+     * @return true, if loading image is successful or image is null, otherwise
+     *         false.
+     */
+    public abstract boolean drawImage(Image img, int x, int y, ImageObserver observer);
+
+    /**
+     * Scales the specified image to fit in the specified rectangle and draws it
+     * with the defined background color. The top left corner of the image will
+     * be drawn at the point (x, y) in current coordinate system. The non-opaque
+     * pixels will be drawn in the background color. The image loading process
+     * notifies the specified Image Observer. This method returns true if the
+     * image has loaded, otherwise it returns false.
+     * 
+     * @param img
+     *            the image which will be drawn.
+     * @param x
+     *            the X coordinate of the image's top left corner.
+     * @param y
+     *            the Y coordinate of the image's top left corner.
+     * @param width
+     *            the width of rectangle which scales the image.
+     * @param height
+     *            the height of rectangle which scales the image.
+     * @param bgcolor
+     *            the background color.
+     * @param observer
+     *            the ImageObserver object which should be notified about image
+     *            loading process.
+     * @return true, if loading image is successful or image is null, otherwise
+     *         false.
+     */
+    public abstract boolean drawImage(Image img, int x, int y, int width, int height,
+            Color bgcolor, ImageObserver observer);
+
+    /**
+     * Scales the specified image to fit in the specified rectangle and draws
+     * it. The top left corner of the image will be drawn at the point (x, y) in
+     * current coordinate system. The image loading process notifies the
+     * specified Image Observer. This method returns true if the image has
+     * loaded, otherwise it returns false.
+     * 
+     * @param img
+     *            the image which will be drawn.
+     * @param x
+     *            the X coordinate of the image top left corner.
+     * @param y
+     *            the Y coordinate of the image top left corner.
+     * @param width
+     *            the width of rectangle which scales the image.
+     * @param height
+     *            the height of rectangle which scales the image.
+     * @param observer
+     *            the ImageObserver object which should be notified about image
+     *            loading process.
+     * @return true, if loading image is successful or image is null, otherwise
+     *         false.
+     */
+    public abstract boolean drawImage(Image img, int x, int y, int width, int height,
+            ImageObserver observer);
+
+    /**
+     * Scales the specified area of the specified image to fit in the rectangle
+     * area defined by its corners coordinates and draws the sub-image with the
+     * specified background color. The sub-image to be drawn is defined by its
+     * top left corner coordinates (sx1, sy1) and bottom right corner
+     * coordinates (sx2, sy2) computed with respect to the origin (top left
+     * corner) of the source image. The non opaque pixels will be drawn in the
+     * background color. The image loading process notifies specified Image
+     * Observer. This method returns true if the image has loaded, otherwise it
+     * returns false.
+     * 
+     * @param img
+     *            the image which will be drawn.
+     * @param dx1
+     *            the X top left corner coordinate of the destination rectangle
+     *            area.
+     * @param dy1
+     *            the Y top left corner coordinate of the destination rectangle
+     *            area.
+     * @param dx2
+     *            the X bottom right corner coordinate of the destination
+     *            rectangle area.
+     * @param dy2
+     *            the Y bottom right corner coordinate of the destination
+     *            rectangle area.
+     * @param sx1
+     *            the X top left corner coordinate of the area to be drawn
+     *            within the source image.
+     * @param sy1
+     *            the Y top left corner coordinate of the area to be drawn
+     *            within the source image.
+     * @param sx2
+     *            the X bottom right corner coordinate of the area to be drawn
+     *            within the source image.
+     * @param sy2
+     *            the Y bottom right corner coordinate of the area to be drawn
+     *            within the source image.
+     * @param bgcolor
+     *            the background color.
+     * @param observer
+     *            the ImageObserver object which should be notified about image
+     *            loading process.
+     * @return true, if loading image is successful or image is null, false
+     *         otherwise.
+     */
+    public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1,
+            int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer);
+
+    /**
+     * Scales the specified area of the specified image to fit in the rectangle
+     * area defined by its corners coordinates and draws the sub-image. The
+     * sub-image to be drawn is defined by its top left corner coordinates (sx1,
+     * sy1) and bottom right corner coordinates (sx2, sy2) computed with respect
+     * to the origin (top left corner) of the source image. The image loading
+     * process notifies specified Image Observer. This method returns true if
+     * the image has loaded, otherwise it returns false.
+     * 
+     * @param img
+     *            the image which will be drawn.
+     * @param dx1
+     *            the X top left corner coordinate of the destination rectangle
+     *            area.
+     * @param dy1
+     *            the Y top left corner coordinate of the destination rectangle
+     *            area.
+     * @param dx2
+     *            the X bottom right corner coordinate of the destination
+     *            rectangle area.
+     * @param dy2
+     *            the Y bottom right corner coordinate of the destination
+     *            rectangle area.
+     * @param sx1
+     *            the X top left corner coordinate of the area to be drawn
+     *            within the source image.
+     * @param sy1
+     *            the Y top left corner coordinate of the area to be drawn
+     *            within the source image.
+     * @param sx2
+     *            the X bottom right corner coordinate of the area to be drawn
+     *            within the source image.
+     * @param sy2
+     *            the Y bottom right corner coordinate of the area to be drawn
+     *            within the source image.
+     * @param observer
+     *            the ImageObserver object which should be notified about image
+     *            loading process.
+     * @return true, if loading image is successful or image is null, false
+     *         otherwise.
+     */
+    public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1,
+            int sy1, int sx2, int sy2, ImageObserver observer);
+
+    /**
+     * Draws a line from the point (x1, y1) to the point (x2, y2). This method
+     * draws the line with current color which can be changed by setColor(Color
+     * c) method.
+     * 
+     * @param x1
+     *            the X coordinate of the first point.
+     * @param y1
+     *            the Y coordinate of the first point.
+     * @param x2
+     *            the X coordinate of the second point.
+     * @param y2
+     *            the Y coordinate of the second point.
+     */
+    public abstract void drawLine(int x1, int y1, int x2, int y2);
+
+    /**
+     * Draws the outline of an oval to fit in the rectangle defined by the given
+     * width, height, and top left corner.
+     * 
+     * @param x
+     *            the X top left corner oval coordinate.
+     * @param y
+     *            the Y top left corner oval coordinate.
+     * @param width
+     *            the oval width.
+     * @param height
+     *            the oval height.
+     */
+    public abstract void drawOval(int x, int y, int width, int height);
+
+    /**
+     * Draws the outline of a polygon. The polygon vertices are defined by
+     * points with xpoints[i], ypoints[i] as coordinates. The polygon edges are
+     * the lines from the points with (xpoints[i-1], ypoints[i-1]) coordinates
+     * to the points with (xpoints[i], ypoints[i]) coordinates, for 0 < i <
+     * npoints +1.
+     * 
+     * @param xpoints
+     *            the array of X coordinates of the polygon vertices.
+     * @param ypoints
+     *            the array of Y coordinates of the polygon vertices.
+     * @param npoints
+     *            the number of polygon vertices/points.
+     */
+    public abstract void drawPolygon(int[] xpoints, int[] ypoints, int npoints);
+
+    /**
+     * Draws a set of connected lines which are defined by the x and y
+     * coordinate arrays. The polyline is closed if coordinates of the first
+     * point are the same as coordinates of the last point.
+     * 
+     * @param xpoints
+     *            the array of X point coordinates.
+     * @param ypoints
+     *            the array of Y point coordinates.
+     * @param npoints
+     *            the number of points.
+     */
+    public abstract void drawPolyline(int[] xpoints, int[] ypoints, int npoints);
+
+    /**
+     * Draws the outline of a rectangle with round corners.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle's top left corner.
+     * @param y
+     *            the Y coordinate of the rectangle's top left corner.
+     * @param width
+     *            the width of the rectangle.
+     * @param height
+     *            the height of the rectangle.
+     * @param arcWidth
+     *            the arc width for the corners.
+     * @param arcHeight
+     *            the arc height for the corners.
+     */
+    public abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth,
+            int arcHeight);
+
+    /**
+     * Draws a text defined by an iterator. The iterator should specify the font
+     * for every character.
+     * 
+     * @param iterator
+     *            the iterator.
+     * @param x
+     *            the X coordinate of the first character.
+     * @param y
+     *            the Y coordinate of the first character.
+     */
+    public abstract void drawString(AttributedCharacterIterator iterator, int x, int y);
+
+    /**
+     * Draws a text defined by a string. This method draws the text with current
+     * font and color.
+     * 
+     * @param str
+     *            the string.
+     * @param x
+     *            the X coordinate of the first character.
+     * @param y
+     *            the Y coordinate of the first character.
+     */
+    public abstract void drawString(String str, int x, int y);
+
+    /**
+     * Fills the arc covering the rectangle and using the current color. The
+     * rectangle is defined by the origin point (X, Y) and dimensions (width and
+     * height). The arc center is the the center of specified rectangle. The
+     * angle origin is at the 3 o'clock position, and a positive angle gives
+     * counter-clockwise rotation, a negative angle gives clockwise rotation.
+     * 
+     * @param x
+     *            the X origin coordinate of the rectangle which scales the arc.
+     * @param y
+     *            the Y origin coordinate of the rectangle which scales the arc.
+     * @param width
+     *            the width of the rectangle which scales the arc.
+     * @param height
+     *            the height of the rectangle which scales the arc.
+     * @param sa
+     *            start angle - the origin angle of arc.
+     * @param ea
+     *            arc angle - the angular arc value relative to the start angle.
+     */
+    public abstract void fillArc(int x, int y, int width, int height, int sa, int ea);
+
+    /**
+     * Fills an oval with the current color where the oval is defined by the
+     * bounding rectangle with the given width, height, and top left corner.
+     * 
+     * @param x
+     *            the X top left corner oval coordinate.
+     * @param y
+     *            the Y top left corner oval coordinate.
+     * @param width
+     *            the oval width.
+     * @param height
+     *            the oval height.
+     */
+    public abstract void fillOval(int x, int y, int width, int height);
+
+    /**
+     * Fills a polygon with the current color. The polygon vertices are defined
+     * by the points with xpoints[i], ypoints[i] as coordinates. The polygon
+     * edges are the lines from the points with (xpoints[i-1], ypoints[i-1])
+     * coordinates to the points with (xpoints[i], ypoints[i]) coordinates, for
+     * 0 < i < npoints +1.
+     * 
+     * @param xpoints
+     *            the array of X coordinates of the polygon vertices.
+     * @param ypoints
+     *            the array of Y coordinates of the polygon vertices.
+     * @param npoints
+     *            the number of polygon vertices/points.
+     */
+    public abstract void fillPolygon(int[] xpoints, int[] ypoints, int npoints);
+
+    /**
+     * Fills a rectangle with the current color. The rectangle is defined by its
+     * width and length and top left corner coordinates.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle's top left corner.
+     * @param y
+     *            the Y coordinate of the rectangle's top left corner.
+     * @param width
+     *            the width of rectangle.
+     * @param height
+     *            the height of rectangle.
+     */
+    public abstract void fillRect(int x, int y, int width, int height);
+
+    /**
+     * Fills a round cornered rectangle with the current color.
+     * 
+     * @param x
+     *            the X coordinate of the top left corner of the bounding
+     *            rectangle.
+     * @param y
+     *            the Y coordinate of the top left corner of the bounding
+     *            rectangle.
+     * @param width
+     *            the width of the bounding rectangle.
+     * @param height
+     *            the height of the bounding rectangle.
+     * @param arcWidth
+     *            the arc width at the corners.
+     * @param arcHeight
+     *            the arc height at the corners.
+     */
+    public abstract void fillRoundRect(int x, int y, int width, int height, int arcWidth,
+            int arcHeight);
+
+    /**
+     * Gets the clipping area. <br>
+     * <br>
+     * 
+     * @return a Shape object of the clipping area or null if it is not set.
+     */
+    public abstract Shape getClip();
+
+    /**
+     * Gets the bounds of the current clipping area as a rectangle.
+     * 
+     * @return a Rectangle object which represents the bounds of the current
+     *         clipping area.
+     */
+    public abstract Rectangle getClipBounds();
+
+    /**
+     * Gets the current color of Graphics.
+     * 
+     * @return the current color.
+     */
+    public abstract Color getColor();
+
+    /**
+     * Gets the current font of Graphics.
+     * 
+     * @return the current font.
+     */
+    public abstract Font getFont();
+
+    /**
+     * Gets the font metrics of the specified font. The font metrics object
+     * contains information about the rendering of a particular font.
+     * 
+     * @param font
+     *            the specified font.
+     * @return the font metrics for the specified font.
+     */
+    public abstract FontMetrics getFontMetrics(Font font);
+
+    /**
+     * Sets the new clipping area specified by rectangle. The new clipping area
+     * doesn't depend on the window's visibility. Rendering operations can't be
+     * performed outside new clipping area.
+     * 
+     * @param x
+     *            the X coordinate of the new clipping rectangle.
+     * @param y
+     *            the Y coordinate of the new clipping rectangle.
+     * @param width
+     *            the width of the new clipping rectangle.
+     * @param height
+     *            the height of the new clipping rectangle.
+     */
+    public abstract void setClip(int x, int y, int width, int height);
+
+    /**
+     * Sets the new clipping area to be the area specified by Shape object. The
+     * new clipping area doesn't depend on the window's visibility. Rendering
+     * operations can't be performed outside new clipping area.
+     * 
+     * @param clip
+     *            the Shape object which represents new clipping area.
+     */
+    public abstract void setClip(Shape clip);
+
+    /**
+     * Sets the current Graphics color. All rendering operations with this
+     * Graphics will use this color.
+     * 
+     * @param c
+     *            the new color.
+     */
+    public abstract void setColor(Color c);
+
+    /**
+     * Sets the current Graphics font. All rendering operations with this
+     * Graphics will use this font.
+     * 
+     * @param font
+     *            the new font.
+     */
+    public abstract void setFont(Font font);
+
+    /**
+     * Sets the paint mode for the Graphics which overwrites all rendering
+     * operations with the current color.
+     */
+    public abstract void setPaintMode();
+
+    /**
+     * Sets the XOR mode for the Graphics which changes a pixel from the current
+     * color to the specified XOR color. <br>
+     * <br>
+     * 
+     * @param color
+     *            the new XOR mode.
+     */
+    public abstract void setXORMode(Color color);
+
+    /**
+     * Translates the origin of Graphics current coordinate system to the point
+     * with X, Y coordinates in the current coordinate system. All rendering
+     * operation in this Graphics will be related to the new origin.
+     * 
+     * @param x
+     *            the X coordinate of the origin.
+     * @param y
+     *            the Y coordinate of the origin.
+     */
+    public abstract void translate(int x, int y);
+}
diff --git a/awt/java/awt/Graphics2D.java b/awt/java/awt/Graphics2D.java
new file mode 100644
index 0000000..04a7319
--- /dev/null
+++ b/awt/java/awt/Graphics2D.java
@@ -0,0 +1,513 @@
+/*
+ *  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.
+ */
+
+package java.awt;
+
+import java.awt.font.GlyphVector;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ImageObserver;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.RenderableImage;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+/**
+ * The Graphics2D class extends Graphics class and provides more capabilities
+ * for rendering text, images, shapes. This provides methods to perform
+ * transformation of coordinate system, color management, and text layout. The
+ * following attributes exist for rendering:
+ * <ul>
+ * <li>Color - current Graphics2D color;</li>
+ * <li>Font - current Graphics2D font;</li>
+ * <li>Stroke - pen with a width of 1 pixel;</li>
+ * <li>Transform - current Graphics2D Transformation;</li>
+ * <li>Composite - alpha compositing rules for combining source and destination
+ * colors.</li>
+ * </ul>
+ * 
+ * @since Android 1.0
+ */
+public abstract class Graphics2D extends Graphics {
+
+    /**
+     * Instantiates a new Graphics2D object. This constructor should never be
+     * called directly.
+     */
+    protected Graphics2D() {
+        super();
+    }
+
+    /**
+     * Adds preferences for the rendering algorithms. The preferences are
+     * arbitrary and specified by Map objects. All specified by Map object
+     * preferences can be modified.
+     * 
+     * @param hints
+     *            the rendering hints.
+     */
+    public abstract void addRenderingHints(Map<?, ?> hints);
+
+    /**
+     * Intersects the current clipping area with the specified Shape and the
+     * result becomes a new clipping area. If current clipping area is not
+     * defined, the Shape becomes the new clipping area. No rendering operations
+     * are allowed outside the clipping area.
+     * 
+     * @param s
+     *            the specified Shape object which will be intersected with
+     *            current clipping area.
+     */
+    public abstract void clip(Shape s);
+
+    /**
+     * Draws the outline of the specified Shape.
+     * 
+     * @param s
+     *            the Shape which outline is drawn.
+     */
+    public abstract void draw(Shape s);
+
+    /**
+     * Draws the specified GlyphVector object's text at the point x, y.
+     * 
+     * @param g
+     *            the GlyphVector object to be drawn.
+     * @param x
+     *            the X position where the GlyphVector's text should be
+     *            rendered.
+     * @param y
+     *            the Y position where the GlyphVector's text should be
+     *            rendered.
+     */
+    public abstract void drawGlyphVector(GlyphVector g, float x, float y);
+
+    /**
+     * Draws the BufferedImage -- modified according to the operation
+     * BufferedImageOp -- at the point x, y.
+     * 
+     * @param img
+     *            the BufferedImage to be rendered.
+     * @param op
+     *            the filter to be applied to the image before rendering.
+     * @param x
+     *            the X coordinate of the point where the image's upper left
+     *            corner will be placed.
+     * @param y
+     *            the Y coordinate of the point where the image's upper left
+     *            corner will be placed.
+     */
+    public abstract void drawImage(BufferedImage img, BufferedImageOp op, int x, int y);
+
+    /**
+     * Draws BufferedImage transformed from image space into user space
+     * according to the AffineTransform xform and notifies the ImageObserver.
+     * 
+     * @param img
+     *            the BufferedImage to be rendered.
+     * @param xform
+     *            the affine transformation from the image to the user space.
+     * @param obs
+     *            the ImageObserver to be notified about the image conversion.
+     * @return true, if the image is successfully loaded and rendered, or it's
+     *         null, otherwise false.
+     */
+    public abstract boolean drawImage(Image img, AffineTransform xform, ImageObserver obs);
+
+    /**
+     * Draws a RenderableImage which is transformed from image space into user
+     * according to the AffineTransform xform.
+     * 
+     * @param img
+     *            the RenderableImage to be rendered.
+     * @param xform
+     *            the affine transformation from image to user space.
+     */
+    public abstract void drawRenderableImage(RenderableImage img, AffineTransform xform);
+
+    /**
+     * Draws a RenderedImage which is transformed from image space into user
+     * according to the AffineTransform xform.
+     * 
+     * @param img
+     *            the RenderedImage to be rendered.
+     * @param xform
+     *            the affine transformation from image to user space.
+     */
+    public abstract void drawRenderedImage(RenderedImage img, AffineTransform xform);
+
+    /**
+     * Draws the string specified by the AttributedCharacterIterator. The first
+     * character's position is specified by the X, Y parameters.
+     * 
+     * @param iterator
+     *            whose text is drawn.
+     * @param x
+     *            the X position where the first character is drawn.
+     * @param y
+     *            the Y position where the first character is drawn.
+     */
+    public abstract void drawString(AttributedCharacterIterator iterator, float x, float y);
+
+    /**
+     * Draws the string specified by the AttributedCharacterIterator. The first
+     * character's position is specified by the X, Y parameters.
+     * 
+     * @param iterator
+     *            whose text is drawn.
+     * @param x
+     *            the X position where the first character is drawn.
+     * @param y
+     *            the Y position where the first character is drawn.
+     * @see java.awt.Graphics#drawString(AttributedCharacterIterator, int, int)
+     */
+    @Override
+    public abstract void drawString(AttributedCharacterIterator iterator, int x, int y);
+
+    /**
+     * Draws the String whose the first character position is specified by the
+     * parameters X, Y.
+     * 
+     * @param s
+     *            the String to be drawn.
+     * @param x
+     *            the X position of the first character.
+     * @param y
+     *            the Y position of the first character.
+     */
+    public abstract void drawString(String s, float x, float y);
+
+    /**
+     * Draws the String whose the first character coordinates are specified by
+     * the parameters X, Y.
+     * 
+     * @param str
+     *            the String to be drawn.
+     * @param x
+     *            the X coordinate of the first character.
+     * @param y
+     *            the Y coordinate of the first character.
+     * @see java.awt.Graphics#drawString(String, int, int)
+     */
+    @Override
+    public abstract void drawString(String str, int x, int y);
+
+    /**
+     * Fills the interior of the specified Shape.
+     * 
+     * @param s
+     *            the Shape to be filled.
+     */
+    public abstract void fill(Shape s);
+
+    /**
+     * Gets the background color.
+     * 
+     * @return the current background color.
+     */
+    public abstract Color getBackground();
+
+    /**
+     * Gets the current composite of the Graphics2D.
+     * 
+     * @return the current composite which specifies the compositing style.
+     */
+    public abstract Composite getComposite();
+
+    /**
+     * Gets the device configuration.
+     * 
+     * @return the device configuration.
+     */
+    public abstract GraphicsConfiguration getDeviceConfiguration();
+
+    /**
+     * Gets the rendering context of the Font.
+     * 
+     * @return the FontRenderContext.
+     */
+    public abstract FontRenderContext getFontRenderContext();
+
+    /**
+     * Gets the current Paint of Graphics2D.
+     * 
+     * @return the current Paint of Graphics2D.
+     */
+    public abstract Paint getPaint();
+
+    /**
+     * Gets the value of single preference for specified key.
+     * 
+     * @param key
+     *            the specified key of the rendering hint.
+     * @return the value of rendering hint for specified key.
+     */
+    public abstract Object getRenderingHint(RenderingHints.Key key);
+
+    /**
+     * Gets the set of the rendering preferences as a collection of key/value
+     * pairs.
+     * 
+     * @return the RenderingHints which contains the rendering preferences.
+     */
+    public abstract RenderingHints getRenderingHints();
+
+    /**
+     * Gets current stroke of the Graphics2D.
+     * 
+     * @return current stroke of the Graphics2D.
+     */
+    public abstract Stroke getStroke();
+
+    /**
+     * Gets current affine transform of the Graphics2D.
+     * 
+     * @return current AffineTransform of the Graphics2D.
+     */
+    public abstract AffineTransform getTransform();
+
+    /**
+     * Determines whether or not the specified Shape intersects the specified
+     * Rectangle. If the onStroke parameter is true, this method checks whether
+     * or not the specified Shape outline intersects the specified Rectangle,
+     * otherwise this method checks whether or not the specified Shape's
+     * interior intersects the specified Rectangle.
+     * 
+     * @param rect
+     *            the specified Rectangle.
+     * @param s
+     *            the Shape to check for intersection.
+     * @param onStroke
+     *            the parameter determines whether or not this method checks for
+     *            intersection of the Shape outline or of the Shape interior
+     *            with the Rectangle.
+     * @return true, if there is a hit, false otherwise.
+     */
+    public abstract boolean hit(Rectangle rect, Shape s, boolean onStroke);
+
+    /**
+     * Performs a rotation transform relative to current Graphics2D Transform.
+     * The coordinate system is rotated by the specified angle in radians
+     * relative to current origin.
+     * 
+     * @param theta
+     *            the angle of rotation in radians.
+     */
+    public abstract void rotate(double theta);
+
+    /**
+     * Performs a translated rotation transform relative to current Graphics2D
+     * Transform. The coordinate system is rotated by the specified angle in
+     * radians relative to current origin and then moved to point (x, y). Is
+     * this right?
+     * 
+     * @param theta
+     *            the angle of rotation in radians.
+     * @param x
+     *            the X coordinate.
+     * @param y
+     *            the Y coordinate.
+     */
+    public abstract void rotate(double theta, double x, double y);
+
+    /**
+     * Performs a linear scale transform relative to current Graphics2D
+     * Transform. The coordinate system is rescaled vertically and horizontally
+     * by the specified parameters.
+     * 
+     * @param sx
+     *            the scaling factor by which the X coordinate is multiplied.
+     * @param sy
+     *            the scaling factor by which the Y coordinate is multiplied.
+     */
+    public abstract void scale(double sx, double sy);
+
+    /**
+     * Sets a new background color for clearing rectangular areas. The clearRect
+     * method uses the current background color.
+     * 
+     * @param color
+     *            the new background color.
+     */
+    public abstract void setBackground(Color color);
+
+    /**
+     * Sets the current composite for Graphics2D.
+     * 
+     * @param comp
+     *            the Composite object.
+     */
+    public abstract void setComposite(Composite comp);
+
+    /**
+     * Sets the paint for Graphics2D.
+     * 
+     * @param paint
+     *            the Paint object.
+     */
+    public abstract void setPaint(Paint paint);
+
+    /**
+     * Sets a key-value pair in the current RenderingHints map.
+     * 
+     * @param key
+     *            the key of the rendering hint to set.
+     * @param value
+     *            the value to set for the rendering hint.
+     */
+    public abstract void setRenderingHint(RenderingHints.Key key, Object value);
+
+    /**
+     * Replaces the current rendering hints with the specified rendering
+     * preferences.
+     * 
+     * @param hints
+     *            the new Map of rendering hints.
+     */
+    public abstract void setRenderingHints(Map<?, ?> hints);
+
+    /**
+     * Sets the stroke for the Graphics2D.
+     * 
+     * @param s
+     *            the Stroke object.
+     */
+    public abstract void setStroke(Stroke s);
+
+    /**
+     * Overwrite the current Transform of the Graphics2D. The specified
+     * Transform should be received from the getTransform() method and should be
+     * used only for restoring the original Graphics2D transform after calling
+     * draw or fill methods.
+     * 
+     * @param Tx
+     *            the specified Transform.
+     */
+    public abstract void setTransform(AffineTransform Tx);
+
+    /**
+     * Performs a shear transform relative to current Graphics2D Transform. The
+     * coordinate system is shifted by the specified multipliers relative to
+     * current position.
+     * 
+     * @param shx
+     *            the multiplier by which the X coordinates shift position along
+     *            X axis as a function of Y coordinates.
+     * @param shy
+     *            the multiplier by which the Y coordinates shift position along
+     *            Y axis as a function of X coordinates.
+     */
+    public abstract void shear(double shx, double shy);
+
+    /**
+     * Concatenates the AffineTransform object with current Transform of this
+     * Graphics2D. The transforms are applied in reverse order with the last
+     * specified transform applied first and the next transformation applied to
+     * the result of previous transformation. More precisely, if Cx is the
+     * current Graphics2D transform, the transform method's result with Tx as
+     * the parameter is the transformation Rx, where Rx(p) = Cx(Tx(p)), for p -
+     * a point in current coordinate system. Rx becomes the current Transform
+     * for this Graphics2D.
+     * 
+     * @param Tx
+     *            the AffineTransform object to be concatenated with current
+     *            Transform.
+     */
+    public abstract void transform(AffineTransform Tx);
+
+    /**
+     * Performs a translate transform relative to current Graphics2D Transform.
+     * The coordinate system is moved by the specified distance relative to
+     * current position.
+     * 
+     * @param tx
+     *            the translation distance along the X axis.
+     * @param ty
+     *            the translation distance along the Y axis.
+     */
+    public abstract void translate(double tx, double ty);
+
+    /**
+     * Moves the origin Graphics2D Transform to the point with x, y coordinates
+     * in current coordinate system. The new origin of coordinate system is
+     * moved to the (x, y) point accordingly. All rendering and transform
+     * operations are performed relative to this new origin.
+     * 
+     * @param x
+     *            the X coordinate.
+     * @param y
+     *            the Y coordinate.
+     * @see java.awt.Graphics#translate(int, int)
+     */
+    @Override
+    public abstract void translate(int x, int y);
+
+    /**
+     * Fills a 3D rectangle with the current color. The rectangle is specified
+     * by its width, height, and top left corner coordinates.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle's top left corner.
+     * @param y
+     *            the Y coordinate of the rectangle's top left corner.
+     * @param width
+     *            the width of rectangle.
+     * @param height
+     *            the height of rectangle.
+     * @param raised
+     *            a boolean value that determines whether the rectangle is drawn
+     *            as raised or indented.
+     * @see java.awt.Graphics#fill3DRect(int, int, int, int, boolean)
+     */
+    @Override
+    public void fill3DRect(int x, int y, int width, int height, boolean raised) {
+        // According to the spec, color should be used instead of paint,
+        // so Graphics.fill3DRect resets paint and
+        // it should be restored after the call
+        Paint savedPaint = getPaint();
+        super.fill3DRect(x, y, width, height, raised);
+        setPaint(savedPaint);
+    }
+
+    /**
+     * Draws the highlighted outline of a rectangle.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle's top left corner.
+     * @param y
+     *            the Y coordinate of the rectangle's top left corner.
+     * @param width
+     *            the width of rectangle.
+     * @param height
+     *            the height of rectangle.
+     * @param raised
+     *            a boolean value that determines whether the rectangle is drawn
+     *            as raised or indented.
+     * @see java.awt.Graphics#draw3DRect(int, int, int, int, boolean)
+     */
+    @Override
+    public void draw3DRect(int x, int y, int width, int height, boolean raised) {
+        // According to the spec, color should be used instead of paint,
+        // so Graphics.draw3DRect resets paint and
+        // it should be restored after the call
+        Paint savedPaint = getPaint();
+        super.draw3DRect(x, y, width, height, raised);
+        setPaint(savedPaint);
+    }
+}
\ No newline at end of file
diff --git a/awt/java/awt/GraphicsConfiguration.java b/awt/java/awt/GraphicsConfiguration.java
new file mode 100644
index 0000000..d59e896
--- /dev/null
+++ b/awt/java/awt/GraphicsConfiguration.java
@@ -0,0 +1,226 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.VolatileImage;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GraphicsConfiguration class contains the characteristics of graphics
+ * devices such as a printer or monitor, and represents device's capabilities
+ * and modes. Many GraphicsConfiguration objects can be associated with single
+ * graphics device.
+ * 
+ * @since Android 1.0
+ */
+public abstract class GraphicsConfiguration {
+
+    /**
+     * Constructor could not be used directly and should be obtained in extended
+     * classes.
+     */
+    protected GraphicsConfiguration() {
+    }
+
+    /**
+     * Creates BufferedImage image object with a data layout and color model
+     * compatible with this GraphicsConfiguration with specified width and
+     * height parameters.
+     * 
+     * @param width
+     *            the width of BufferedImage.
+     * @param height
+     *            the height of BufferedImage.
+     * @return the BufferedImage object with specified width and height
+     *         parameters.
+     */
+    public abstract BufferedImage createCompatibleImage(int width, int height);
+
+    /**
+     * Creates a BufferedImage that has the specified width, height,
+     * transparency and has a data layout and color model compatible with this
+     * GraphicsConfiguration.
+     * 
+     * @param width
+     *            the width of image.
+     * @param height
+     *            the height of image.
+     * @param transparency
+     *            the transparency mode.
+     * @return the BufferedImage object.
+     */
+    public abstract BufferedImage createCompatibleImage(int width, int height, int transparency);
+
+    /**
+     * Creates a VolatileImage that has the specified width and height and has a
+     * data layout and color model compatible with this GraphicsConfiguration.
+     * 
+     * @param width
+     *            the width of image.
+     * @param height
+     *            the height of image.
+     * @return the VolatileImage object.
+     */
+    public abstract VolatileImage createCompatibleVolatileImage(int width, int height);
+
+    /**
+     * Creates a VolatileImage that supports the specified width, height,
+     * transparency and has a data layout and color model compatible with this
+     * GraphicsConfiguration.
+     * 
+     * @param width
+     *            the width of image.
+     * @param height
+     *            the height of image.
+     * @param transparency
+     *            the transparency mode.
+     * @return the VolatileImage object.
+     */
+    public abstract VolatileImage createCompatibleVolatileImage(int width, int height,
+            int transparency);
+
+    /**
+     * Gets the bounds of area covered by the GraphicsConfiguration in the
+     * device coordinates space.
+     * 
+     * @return the Rectangle of GraphicsConfiguration's bounds.
+     */
+    public abstract Rectangle getBounds();
+
+    /**
+     * Gets the ColorModel of the GraphicsConfiguration.
+     * 
+     * @return the ColorModel object of the GraphicsConfiguration.
+     */
+    public abstract ColorModel getColorModel();
+
+    /**
+     * Gets the ColorModel of the GraphicsConfiguration which supports specified
+     * Transparency.
+     * 
+     * @param transparency
+     *            the Transparency mode: OPAQUE, BITMASK, or TRANSLUCENT.
+     * @return the ColorModel of the GraphicsConfiguration which supports
+     *         specified Transparency.
+     */
+    public abstract ColorModel getColorModel(int transparency);
+
+    /**
+     * Gets the default AffineTransform of the GraphicsConfiguration. This
+     * method translates user coordinates to device coordinates.
+     * 
+     * @return the default AffineTransform of the GraphicsConfiguration.
+     */
+    public abstract AffineTransform getDefaultTransform();
+
+    /**
+     * Gets the GraphicsDevice of the GraphicsConfiguration.
+     * 
+     * @return the GraphicsDevice of the GraphicsConfiguration.
+     */
+    public abstract GraphicsDevice getDevice();
+
+    /**
+     * Gets the normalizing AffineTransform of the GraphicsConfiguration.
+     * 
+     * @return the normalizing AffineTransform of the GraphicsConfiguration.
+     */
+    public abstract AffineTransform getNormalizingTransform();
+
+    /**
+     * Creates VolatileImage with specified width, height, ImageCapabilities; a
+     * data layout and color model compatible with this GraphicsConfiguration.
+     * 
+     * @param width
+     *            the width of image.
+     * @param height
+     *            the height of image.
+     * @param caps
+     *            the ImageCapabilities object.
+     * @return the VolatileImage which data layout and color model compatible
+     *         with this GraphicsConfiguration.
+     * @throws AWTException
+     *             if ImageCapabilities is not supported by the
+     *             GraphicsConfiguration.
+     */
+    public VolatileImage createCompatibleVolatileImage(int width, int height, ImageCapabilities caps)
+            throws AWTException {
+        VolatileImage res = createCompatibleVolatileImage(width, height);
+        if (!res.getCapabilities().equals(caps)) {
+            // awt.14A=Can not create VolatileImage with specified capabilities
+            throw new AWTException(Messages.getString("awt.14A")); //$NON-NLS-1$
+        }
+        return res;
+    }
+
+    /**
+     * Creates a VolatileImage with specified width, height, transparency and
+     * ImageCapabilities; a data layout and color model compatible with this
+     * GraphicsConfiguration.
+     * 
+     * @param width
+     *            the width of image.
+     * @param height
+     *            the height of image.
+     * @param caps
+     *            the ImageCapabilities object.
+     * @param transparency
+     *            the Transparency mode: OPAQUE, BITMASK, or TRANSLUCENT.
+     * @return the VolatileImage which data layout and color model compatible
+     *         with this GraphicsConfiguration.
+     * @throws AWTException
+     *             if ImageCapabilities is not supported by the
+     *             GraphicsConfiguration.
+     */
+    public VolatileImage createCompatibleVolatileImage(int width, int height,
+            ImageCapabilities caps, int transparency) throws AWTException {
+        VolatileImage res = createCompatibleVolatileImage(width, height, transparency);
+        if (!res.getCapabilities().equals(caps)) {
+            // awt.14A=Can not create VolatileImage with specified capabilities
+            throw new AWTException(Messages.getString("awt.14A")); //$NON-NLS-1$
+        }
+        return res;
+    }
+
+    /**
+     * Gets the buffering capabilities of the GraphicsConfiguration.
+     * 
+     * @return the BufferCapabilities object.
+     */
+    public BufferCapabilities getBufferCapabilities() {
+        return new BufferCapabilities(new ImageCapabilities(false), new ImageCapabilities(false),
+                BufferCapabilities.FlipContents.UNDEFINED);
+    }
+
+    /**
+     * Gets the image capabilities of the GraphicsConfiguration.
+     * 
+     * @return the ImageCapabilities object.
+     */
+    public ImageCapabilities getImageCapabilities() {
+        return new ImageCapabilities(false);
+    }
+}
diff --git a/awt/java/awt/GraphicsDevice.java b/awt/java/awt/GraphicsDevice.java
new file mode 100644
index 0000000..9eda4e0
--- /dev/null
+++ b/awt/java/awt/GraphicsDevice.java
@@ -0,0 +1,196 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GraphicsDevice class describes the graphics devices (such as screens or
+ * printers) which are available in a particular graphics environment. Many
+ * GraphicsDevice instances can be associated with a single GraphicsEnvironment.
+ * Each GraphicsDevice has one or more GraphicsConfiguration objects which
+ * specify the different configurations and modes of GraphicsDevice.
+ * 
+ * @since Android 1.0
+ */
+public abstract class GraphicsDevice {
+
+    /**
+     * The display mode.
+     */
+    private DisplayMode displayMode;
+
+    // ???AWT
+    // private Window fullScreenWindow = null;
+
+    /**
+     * The Constant TYPE_IMAGE_BUFFER indicates a image buffer device.
+     */
+
+    public static final int TYPE_IMAGE_BUFFER = 2;
+
+    /**
+     * The Constant TYPE_PRINTER indicates a printer device.
+     */
+    public static final int TYPE_PRINTER = 1;
+
+    /**
+     * The Constant TYPE_RASTER_SCREEN indicates a raster screen device.
+     */
+    public static final int TYPE_RASTER_SCREEN = 0;
+
+    /**
+     * Constructor is not to be used directly as this class is abstract.
+     */
+    protected GraphicsDevice() {
+        displayMode = new DisplayMode(0, 0, DisplayMode.BIT_DEPTH_MULTI,
+                DisplayMode.REFRESH_RATE_UNKNOWN);
+    }
+
+    /**
+     * Returns an array of GraphicsConfiguration objects associated with the
+     * GraphicsDevice.
+     * 
+     * @return an array of GraphicsConfiguration objects associated with the
+     *         GraphicsDevice.
+     */
+    public abstract GraphicsConfiguration[] getConfigurations();
+
+    /**
+     * Gets the default configuration for the GraphicsDevice.
+     * 
+     * @return the default GraphicsConfiguration object for the GraphicsDevice.
+     */
+    public abstract GraphicsConfiguration getDefaultConfiguration();
+
+    /**
+     * Gets the String identifier which associated with the GraphicsDevice in
+     * the GraphicsEnvironment.
+     * 
+     * @return the String identifier of the GraphicsDevice in the
+     *         GraphicsEnvironment.
+     */
+    public abstract String getIDstring();
+
+    /**
+     * Gets the type of this GraphicsDevice: TYPE_IMAGE_BUFFER, TYPE_PRINTER or
+     * TYPE_RASTER_SCREEN.
+     * 
+     * @return the type of this GraphicsDevice: TYPE_IMAGE_BUFFER, TYPE_PRINTER
+     *         or TYPE_RASTER_SCREEN.
+     */
+    public abstract int getType();
+
+    /**
+     * Returns the number of bytes available in accelerated memory on this
+     * device.
+     * 
+     * @return the number of bytes available accelerated memory.
+     */
+    public int getAvailableAcceleratedMemory() {
+        return 0;
+    }
+
+    /*
+     * ???AWT public GraphicsConfiguration
+     * getBestConfiguration(GraphicsConfigTemplate gct) { return
+     * gct.getBestConfiguration(getConfigurations()); }
+     */
+
+    /**
+     * Gets the current display mode of the GraphicsDevice.
+     * 
+     * @return the current display mode of the GraphicsDevice.
+     */
+    public DisplayMode getDisplayMode() {
+        return displayMode;
+    }
+
+    /**
+     * Gets an array of display modes available in this GraphicsDevice.
+     * 
+     * @return an array of display modes available in this GraphicsDevice.
+     */
+    public DisplayMode[] getDisplayModes() {
+        DisplayMode[] dms = {
+            displayMode
+        };
+        return dms;
+    }
+
+    /*
+     * ???AWT public Window getFullScreenWindow() { return fullScreenWindow; }
+     */
+
+    /**
+     * Returns true if this GraphicsDevice supports low-level display changes.
+     * 
+     * @return true, if this GraphicsDevice supports low-level display changes;
+     *         false otherwise.
+     */
+    public boolean isDisplayChangeSupported() {
+        return false;
+    }
+
+    /**
+     * Returns true if this GraphicsDevice supports full screen mode.
+     * 
+     * @return true, if this GraphicsDevice supports full screen mode, false
+     *         otherwise.
+     */
+    public boolean isFullScreenSupported() {
+        return false;
+    }
+
+    // an array of display modes available in this GraphicsDevice.
+
+    /**
+     * Sets the display mode of this GraphicsDevice.
+     * 
+     * @param dm
+     *            the new display mode of this GraphicsDevice.
+     */
+    public void setDisplayMode(DisplayMode dm) {
+        if (!isDisplayChangeSupported()) {
+            // awt.122=Does not support display mode changes
+            throw new UnsupportedOperationException(Messages.getString("awt.122")); //$NON-NLS-1$
+        }
+
+        DisplayMode[] dms = getDisplayModes();
+        for (DisplayMode element : dms) {
+            if (element.equals(dm)) {
+                displayMode = dm;
+                return;
+            }
+        }
+        // awt.123=Unsupported display mode: {0}
+        throw new IllegalArgumentException(Messages.getString("awt.123", dm)); //$NON-NLS-1$
+    }
+
+    /*
+     * ???AWT public void setFullScreenWindow(Window w) { if (w == null) {
+     * fullScreenWindow = null; return; } fullScreenWindow = w; if
+     * (isFullScreenSupported()) { w.enableInputMethods(false); } else {
+     * w.setSize(displayMode.getWidth(), displayMode.getHeight());
+     * w.setLocation(0, 0); } w.setVisible(true); w.setAlwaysOnTop(true); }
+     */
+}
diff --git a/awt/java/awt/GraphicsEnvironment.java b/awt/java/awt/GraphicsEnvironment.java
new file mode 100644
index 0000000..d527417
--- /dev/null
+++ b/awt/java/awt/GraphicsEnvironment.java
@@ -0,0 +1,212 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.image.BufferedImage;
+import java.util.Locale;
+
+import org.apache.harmony.awt.ContextStorage;
+import org.apache.harmony.awt.gl.CommonGraphics2DFactory;
+
+/**
+ * The GraphicsEnvironment class defines a collection of GraphicsDevice objects
+ * and Font objects which are available for Java application on current
+ * platform.
+ * 
+ * @since Android 1.0
+ */
+public abstract class GraphicsEnvironment {
+
+    /**
+     * Constructor could not be used directly and should be obtained in extended
+     * classes.
+     */
+    protected GraphicsEnvironment() {
+    }
+
+    /**
+     * Gets the local GraphicsEnvironment.
+     * 
+     * @return the local GraphicsEnvironment.
+     */
+    public static GraphicsEnvironment getLocalGraphicsEnvironment() {
+        synchronized (ContextStorage.getContextLock()) {
+            if (ContextStorage.getGraphicsEnvironment() == null) {
+                if (isHeadless()) {
+                    ContextStorage.setGraphicsEnvironment(new HeadlessGraphicsEnvironment());
+                } else {
+                    CommonGraphics2DFactory g2df = (CommonGraphics2DFactory)Toolkit
+                            .getDefaultToolkit().getGraphicsFactory();
+
+                    ContextStorage.setGraphicsEnvironment(g2df
+                            .createGraphicsEnvironment(ContextStorage.getWindowFactory()));
+                }
+            }
+
+            return ContextStorage.getGraphicsEnvironment();
+        }
+    }
+
+    /**
+     * Returns whether or not a display, keyboard, and mouse are supported in
+     * this graphics environment.
+     * 
+     * @return true, if HeadlessException will be thrown from areas of the
+     *         graphics environment that are dependent on a display, keyboard,
+     *         or mouse, false otherwise.
+     */
+    public boolean isHeadlessInstance() {
+        return false;
+    }
+
+    /**
+     * Checks whether or not a display, keyboard, and mouse are supported in
+     * this environment.
+     * 
+     * @return true, if a HeadlessException is thrown from areas of the Toolkit
+     *         and GraphicsEnvironment that are dependent on a display,
+     *         keyboard, or mouse, false otherwise.
+     */
+    public static boolean isHeadless() {
+        return "true".equals(System.getProperty("java.awt.headless"));
+    }
+
+    /**
+     * Gets the maximum bounds of system centered windows.
+     * 
+     * @return the maximum bounds of system centered windows.
+     * @throws HeadlessException
+     *             if isHeadless() method returns true.
+     */
+    public Rectangle getMaximumWindowBounds() throws HeadlessException {
+        return getDefaultScreenDevice().getDefaultConfiguration().getBounds();
+    }
+
+    /**
+     * Gets the Point which should defines the center of system window.
+     * 
+     * @return the Point where the system window should be centered.
+     * @throws HeadlessException
+     *             if isHeadless() method returns true.
+     */
+    public Point getCenterPoint() throws HeadlessException {
+        Rectangle mwb = getMaximumWindowBounds();
+        return new Point(mwb.width >> 1, mwb.height >> 1);
+    }
+
+    /**
+     * Indicates that the primary font should be used. Primary font is specified
+     * by initial system locale or default encoding).
+     */
+    public void preferLocaleFonts() {
+        // Note: API specification says following:
+        // "The actual change in font rendering behavior resulting
+        // from a call to this method is implementation dependent;
+        // it may have no effect at all." So, doing nothing is an
+        // acceptable behavior for this method.
+
+        // For now FontManager uses 1.4 font.properties scheme for font mapping,
+        // so
+        // this method doesn't make any sense. The implementation of this method
+        // which will influence font mapping is postponed until
+        // 1.5 mapping scheme not implemented.
+
+        // todo - Implement non-default behavior with 1.5 font mapping scheme
+    }
+
+    /**
+     * Indicates that a proportional preference of the font should be used.
+     */
+    public void preferProportionalFonts() {
+        // Note: API specification says following:
+        // "The actual change in font rendering behavior resulting
+        // from a call to this method is implementation dependent;
+        // it may have no effect at all." So, doing nothing is an
+        // acceptable behavior for this method.
+
+        // For now FontManager uses 1.4 font.properties scheme for font mapping,
+        // so
+        // this method doesn't make any sense. The implementation of this method
+        // which will influence font mapping is postponed until
+        // 1.5 mapping scheme not implemented.
+
+        // todo - Implement non-default behavior with 1.5 font mapping scheme
+    }
+
+    /**
+     * Creates the Graphics2D object for rendering to the specified
+     * BufferedImage.
+     * 
+     * @param bufferedImage
+     *            the BufferedImage object.
+     * @return the Graphics2D object which allows to render to the specified
+     *         BufferedImage.
+     */
+    public abstract Graphics2D createGraphics(BufferedImage bufferedImage);
+
+    /**
+     * Gets the array of all available fonts instances in this
+     * GraphicsEnviroments.
+     * 
+     * @return the array of all available fonts instances in this
+     *         GraphicsEnviroments.
+     */
+    public abstract Font[] getAllFonts();
+
+    /**
+     * Gets the array of all available font family names.
+     * 
+     * @return the array of all available font family names.
+     */
+    public abstract String[] getAvailableFontFamilyNames();
+
+    /**
+     * Gets the array of all available font family names for the specified
+     * locale.
+     * 
+     * @param locale
+     *            the Locale object which represents geographical region. The
+     *            default locale is used if locale is null.
+     * @return the array of available font family names for the specified
+     *         locale.
+     */
+    public abstract String[] getAvailableFontFamilyNames(Locale locale);
+
+    /**
+     * Gets the default screen device as GraphicDevice object.
+     * 
+     * @return the GraphicDevice object which represents default screen device.
+     * @throws HeadlessException
+     *             if isHeadless() returns true.
+     */
+    public abstract GraphicsDevice getDefaultScreenDevice() throws HeadlessException;
+
+    /**
+     * Gets an array of all available screen devices.
+     * 
+     * @return the array of GraphicsDevice objects which represents all
+     *         available screen devices.
+     * @throws HeadlessException
+     *             if isHeadless() returns true.
+     */
+    public abstract GraphicsDevice[] getScreenDevices() throws HeadlessException;
+}
diff --git a/awt/java/awt/HeadlessException.java b/awt/java/awt/HeadlessException.java
new file mode 100644
index 0000000..ec111f1
--- /dev/null
+++ b/awt/java/awt/HeadlessException.java
@@ -0,0 +1,54 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+/**
+ * The HeadlessException class provides notifications and error messages when
+ * code that is dependent on a keyboard, display, or mouse is called in an
+ * environment that does not support a keyboard, display, or mouse.
+ * 
+ * @since Android 1.0
+ */
+public class HeadlessException extends UnsupportedOperationException {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 167183644944358563L;
+
+    /**
+     * Instantiates a new headless exception.
+     */
+    public HeadlessException() {
+        super();
+    }
+
+    /**
+     * Instantiates a new headless exception with the specified message.
+     * 
+     * @param msg
+     *            the String which represents error message.
+     */
+    public HeadlessException(String msg) {
+        super(msg);
+    }
+}
diff --git a/awt/java/awt/HeadlessGraphicsEnvironment.java b/awt/java/awt/HeadlessGraphicsEnvironment.java
new file mode 100644
index 0000000..306393f
--- /dev/null
+++ b/awt/java/awt/HeadlessGraphicsEnvironment.java
@@ -0,0 +1,72 @@
+/*
+ *  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.
+ */
+
+package java.awt;
+
+import java.awt.GraphicsDevice;
+import java.awt.HeadlessException;
+
+import org.apache.harmony.awt.gl.CommonGraphicsEnvironment;
+
+/**
+ * The HeadlessGraphicsEnvironment class is the CommonGraphicsEnvironment
+ * implementation to use in the case where the environment lacks display,
+ * keyboard, and mouse support.
+ * 
+ * @since Android 1.0
+ */
+public class HeadlessGraphicsEnvironment extends CommonGraphicsEnvironment {
+
+    /**
+     * Returns whether or not a display, keyboard, and mouse are supported in
+     * this graphics environment.
+     * 
+     * @return true, if HeadlessException will be thrown from areas of the
+     *         graphics environment that are dependent on a display, keyboard,
+     *         or mouse, false otherwise.
+     */
+    @Override
+    public boolean isHeadlessInstance() {
+        return true;
+    }
+
+    /**
+     * Gets the default screen device as GraphicDevice object.
+     * 
+     * @return the GraphicDevice object which represents default screen device.
+     * @throws HeadlessException
+     *             if isHeadless() returns true.
+     */
+    @Override
+    public GraphicsDevice getDefaultScreenDevice() throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    /**
+     * Gets an array of all available screen devices.
+     * 
+     * @return the array of GraphicsDevice objects which represents all
+     *         available screen devices.
+     * @throws HeadlessException
+     *             if isHeadless() returns true.
+     */
+    @Override
+    public GraphicsDevice[] getScreenDevices() throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+}
diff --git a/awt/java/awt/HeadlessToolkit.java b/awt/java/awt/HeadlessToolkit.java
new file mode 100644
index 0000000..c64a85a
--- /dev/null
+++ b/awt/java/awt/HeadlessToolkit.java
@@ -0,0 +1,226 @@
+/*
+ *  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.
+ */
+
+package java.awt;
+
+//???AWT
+//import java.awt.datatransfer.Clipboard;
+//import java.awt.dnd.DragGestureEvent;
+//import java.awt.dnd.DragGestureListener;
+//import java.awt.dnd.DragGestureRecognizer;
+//import java.awt.dnd.DragSource;
+//import java.awt.dnd.InvalidDnDOperationException;
+//import java.awt.dnd.peer.DragSourceContextPeer;
+import java.awt.im.InputMethodHighlight;
+import java.awt.image.ColorModel; //import java.awt.peer.*;
+//import java.beans.PropertyChangeSupport;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.harmony.awt.ComponentInternals; //import org.apache.harmony.awt.datatransfer.DTK;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+import org.apache.harmony.awt.wtk.WindowFactory;
+
+/**
+ * The HeadlessToolkit class is a subclass of ToolkitImpl to be used for
+ * graphical environments that lack keyboard and mouse capabilities.
+ * 
+ * @since Android 1.0
+ */
+public final class HeadlessToolkit extends ToolkitImpl {
+
+    // ???AWT
+    /*
+     * @Override protected ButtonPeer createButton(Button a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected CheckboxPeer createCheckbox(Checkbox a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected CheckboxMenuItemPeer
+     * createCheckboxMenuItem(CheckboxMenuItem a0) throws HeadlessException {
+     * throw new HeadlessException(); }
+     * @Override protected ChoicePeer createChoice(Choice a0) throws
+     * HeadlessException { throw new HeadlessException(); } public Cursor
+     * createCustomCursor(Image img, Point hotSpot, String name) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected DialogPeer createDialog(Dialog a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override public <T extends DragGestureRecognizer> T
+     * createDragGestureRecognizer( Class<T> recognizerAbstractClass, DragSource
+     * ds, Component c, int srcActions, DragGestureListener dgl) { return null;
+     * }
+     * @Override public DragSourceContextPeer
+     * createDragSourceContextPeer(DragGestureEvent dge) throws
+     * InvalidDnDOperationException { throw new InvalidDnDOperationException();
+     * }
+     * @Override protected FileDialogPeer createFileDialog(FileDialog a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected FramePeer createFrame(Frame a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected LabelPeer createLabel(Label a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected ListPeer createList(List a0) throws HeadlessException
+     * { throw new HeadlessException(); }
+     * @Override protected MenuPeer createMenu(Menu a0) throws HeadlessException
+     * { throw new HeadlessException(); }
+     * @Override protected MenuBarPeer createMenuBar(MenuBar a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected MenuItemPeer createMenuItem(MenuItem a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected PopupMenuPeer createPopupMenu(PopupMenu a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected ScrollbarPeer createScrollbar(Scrollbar a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected ScrollPanePeer createScrollPane(ScrollPane a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected TextAreaPeer createTextArea(TextArea a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected TextFieldPeer createTextField(TextField a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     * @Override protected WindowPeer createWindow(Window a0) throws
+     * HeadlessException { throw new HeadlessException(); }
+     */
+
+    @Override
+    public Dimension getBestCursorSize(int prefWidth, int prefHeight) throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    public ColorModel getColorModel() throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    public GraphicsFactory getGraphicsFactory() throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    public boolean getLockingKeyState(int keyCode) throws UnsupportedOperationException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    public int getMaximumCursorColors() throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    public int getMenuShortcutKeyMask() throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    // ???AWT
+    /*
+     * @Override NativeEventQueue getNativeEventQueue() throws HeadlessException
+     * { throw new HeadlessException(); }
+     * @Override public PrintJob getPrintJob(Frame frame, String jobtitle,
+     * JobAttributes jobAttributes, PageAttributes pageAttributes) throws
+     * IllegalArgumentException { throw new IllegalArgumentException(); }
+     * @Override public PrintJob getPrintJob(Frame frame, String jobtitle,
+     * Properties props) throws NullPointerException { throw new
+     * NullPointerException(); }
+     */
+
+    @Override
+    public Insets getScreenInsets(GraphicsConfiguration gc) throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    public int getScreenResolution() throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    public Dimension getScreenSize() throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    // ???AWT
+    /*
+     * @Override public Clipboard getSystemClipboard() throws HeadlessException
+     * { throw new HeadlessException(); }
+     * @Override public Clipboard getSystemSelection() throws HeadlessException
+     * { throw new HeadlessException(); }
+     * @Override WindowFactory getWindowFactory() throws HeadlessException {
+     * throw new HeadlessException(); }
+     */
+
+    @Override
+    protected void init() {
+        lockAWT();
+        try {
+            ComponentInternals.setComponentInternals(new ComponentInternalsImpl());
+            // ???AWT: new EventQueue(this); // create the system EventQueue
+            // ???AWT: dispatcher = new Dispatcher(this);
+            desktopProperties = new HashMap<String, Object>();
+            // ???AWT: desktopPropsSupport = new PropertyChangeSupport(this);
+            // ???AWT: awtEventsManager = new AWTEventsManager();
+            // ???AWT: dispatchThread = new HeadlessEventDispatchThread(this,
+            // dispatcher);
+            // ???AWT: dtk = DTK.getDTK();
+            dispatchThread.start();
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @Override
+    public boolean isDynamicLayoutActive() throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    protected boolean isDynamicLayoutSet() throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    public boolean isFrameStateSupported(int state) throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    protected void loadSystemColors(int[] systemColors) throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    public Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlight(
+            InputMethodHighlight highlight) throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlightImpl(InputMethodHighlight highlight)
+            throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    public void setDynamicLayout(boolean dynamic) throws HeadlessException {
+        throw new HeadlessException();
+    }
+
+    @Override
+    public void setLockingKeyState(int keyCode, boolean on) throws UnsupportedOperationException {
+        throw new HeadlessException();
+    }
+}
diff --git a/awt/java/awt/IllegalComponentStateException.java b/awt/java/awt/IllegalComponentStateException.java
new file mode 100644
index 0000000..bed1729
--- /dev/null
+++ b/awt/java/awt/IllegalComponentStateException.java
@@ -0,0 +1,55 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+/**
+ * The IllegalComponentStateException class is used to provide notification that
+ * AWT component is not in an appropriate state for the requested operation.
+ * 
+ * @since Android 1.0
+ */
+public class IllegalComponentStateException extends IllegalStateException {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -1889339587208144238L;
+
+    /**
+     * Instantiates a new IllegalComponentStateException with the specified
+     * message.
+     * 
+     * @param s
+     *            the String message which describes the exception.
+     */
+    public IllegalComponentStateException(String s) {
+        super(s);
+    }
+
+    /**
+     * Instantiates a new IllegalComponentStateException without detailed
+     * message.
+     */
+    public IllegalComponentStateException() {
+    }
+
+}
diff --git a/awt/java/awt/Image.java b/awt/java/awt/Image.java
new file mode 100644
index 0000000..7ae3ed8
--- /dev/null
+++ b/awt/java/awt/Image.java
@@ -0,0 +1,205 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.image.AreaAveragingScaleFilter;
+import java.awt.image.FilteredImageSource;
+import java.awt.image.ImageFilter;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.ReplicateScaleFilter;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Image abstract class represents the graphic images.
+ * 
+ * @since Android 1.0
+ */
+public abstract class Image {
+
+    /**
+     * The UndefinedProperty object should be returned if property is not
+     * defined for a particular image.
+     */
+    public static final Object UndefinedProperty = new Object(); // $NON-LOCK-1$
+
+    /**
+     * The Constant SCALE_DEFAULT indicates the default image scaling algorithm.
+     */
+    public static final int SCALE_DEFAULT = 1;
+
+    /**
+     * The Constant SCALE_FAST indicates an image scaling algorithm which places
+     * a higher priority on scaling speed than on the image's smoothness.
+     */
+    public static final int SCALE_FAST = 2;
+
+    /**
+     * The Constant SCALE_SMOOTH indicates an image scaling algorithm which
+     * places a higher priority on image smoothness than on scaling speed.
+     */
+    public static final int SCALE_SMOOTH = 4;
+
+    /**
+     * The Constant SCALE_REPLICATE indicates the image scaling algorithm in the
+     * ReplicateScaleFilter class.
+     */
+    public static final int SCALE_REPLICATE = 8;
+
+    /**
+     * The Constant SCALE_AREA_AVERAGING indicates the area averaging image
+     * scaling algorithm.
+     */
+    public static final int SCALE_AREA_AVERAGING = 16;
+
+    /**
+     * The acceleration priority indicates image acceleration.
+     */
+    protected float accelerationPriority = 0.5f;
+
+    /**
+     * The Constant capabilities.
+     */
+    private static final ImageCapabilities capabilities = new ImageCapabilities(false);
+
+    /**
+     * Gets the image property with the specified name. The UndefinedProperty
+     * object should be return if the property is not specified for this image.
+     * The return value should be null if the property is currently unknown yet
+     * and the specified ImageObserver is to be notified later.
+     * 
+     * @param name
+     *            the name of image's property.
+     * @param observer
+     *            the ImageObserver.
+     * @return the Object which represents value of the specified property.
+     */
+    public abstract Object getProperty(String name, ImageObserver observer);
+
+    /**
+     * Gets the ImageProducer object which represents data of this Image.
+     * 
+     * @return the ImageProducer object which represents data of this Image.
+     */
+    public abstract ImageProducer getSource();
+
+    /**
+     * Gets the width of this image. The specified ImageObserver object is
+     * notified when the width of this image is available.
+     * 
+     * @param observer
+     *            the ImageObserver object which is is notified when the width
+     *            of this image is available.
+     * @return the width of image, or -1 if the width of this image is not
+     *         available.
+     */
+    public abstract int getWidth(ImageObserver observer);
+
+    /**
+     * Gets the height of this image. The specified ImageObserver object is
+     * notified when the height of this image is available.
+     * 
+     * @param observer
+     *            the ImageObserver object which is is notified when the height
+     *            of this image is available.
+     * @return the height of image, or -1 if the height of this image is not
+     *         available.
+     */
+    public abstract int getHeight(ImageObserver observer);
+
+    /**
+     * Gets the scaled instance of this Image. This method returns an Image
+     * object constructed from the source of this image with the specified
+     * width, height, and applied scaling algorithm.
+     * 
+     * @param width
+     *            the width of scaled Image.
+     * @param height
+     *            the height of scaled Image.
+     * @param hints
+     *            the constant which indicates scaling algorithm.
+     * @return the scaled Image.
+     */
+    public Image getScaledInstance(int width, int height, int hints) {
+        ImageFilter filter;
+        if ((hints & (SCALE_SMOOTH | SCALE_AREA_AVERAGING)) != 0) {
+            filter = new AreaAveragingScaleFilter(width, height);
+        } else {
+            filter = new ReplicateScaleFilter(width, height);
+        }
+        ImageProducer producer = new FilteredImageSource(getSource(), filter);
+        return Toolkit.getDefaultToolkit().createImage(producer);
+    }
+
+    /**
+     * Gets a Graphics object for rendering this image. This method can be used
+     * for off-screen images.
+     * 
+     * @return a Graphics object for rendering to this image.
+     */
+    public abstract Graphics getGraphics();
+
+    /**
+     * Flushes resources which are used by this Image object. This method resets
+     * the image to the reconstructed state from the image's source.
+     */
+    public abstract void flush();
+
+    /**
+     * Gets the acceleration priority of this image.
+     * 
+     * @return the acceleration priority of this image.
+     */
+    public float getAccelerationPriority() {
+        return accelerationPriority;
+    }
+
+    /**
+     * Sets the acceleration priority for this image.
+     * 
+     * @param priority
+     *            the new acceleration priority (value in the range 0-1).
+     */
+    public void setAccelerationPriority(float priority) {
+        if (priority < 0 || priority > 1) {
+            // awt.10A=Priority must be a value between 0 and 1, inclusive
+            throw new IllegalArgumentException(Messages.getString("awt.10A")); //$NON-NLS-1$
+        }
+        accelerationPriority = priority;
+    }
+
+    /**
+     * Gets an ImageCapabilities object of this Image object for the specified
+     * GraphicsConfiguration.
+     * 
+     * @param gc
+     *            the specified GraphicsConfiguration object (null value means
+     *            default GraphicsConfiguration).
+     * @return an ImageCapabilities object of this Image object for the
+     *         specified GraphicsConfiguration.
+     */
+    public ImageCapabilities getCapabilities(GraphicsConfiguration gc) {
+        // Note: common image is not accelerated.
+        return capabilities;
+    }
+}
diff --git a/awt/java/awt/ImageCapabilities.java b/awt/java/awt/ImageCapabilities.java
new file mode 100644
index 0000000..c6d5946
--- /dev/null
+++ b/awt/java/awt/ImageCapabilities.java
@@ -0,0 +1,78 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+/**
+ * The ImageCapabilities class gives information about an image's capabilities.
+ * 
+ * @since Android 1.0
+ */
+public class ImageCapabilities implements Cloneable {
+
+    /**
+     * The accelerated.
+     */
+    private final boolean accelerated;
+
+    /**
+     * Instantiates a new ImageCapabilities with the specified acceleration flag
+     * which indicates whether acceleration is desired or not.
+     * 
+     * @param accelerated
+     *            the accelerated flag.
+     */
+    public ImageCapabilities(boolean accelerated) {
+        this.accelerated = accelerated;
+    }
+
+    /**
+     * Returns a copy of this ImageCapabilities object.
+     * 
+     * @return the copy of this ImageCapabilities object.
+     */
+    @Override
+    public Object clone() {
+        return new ImageCapabilities(accelerated);
+    }
+
+    /**
+     * Returns true if the Image of this ImageCapabilities is or can be
+     * accelerated.
+     * 
+     * @return true, if the Image of this ImageCapabilities is or can be
+     *         accelerated, false otherwise.
+     */
+    public boolean isAccelerated() {
+        return accelerated;
+    }
+
+    /**
+     * Returns true if this ImageCapabilities applies to the VolatileImage which
+     * can lose its surfaces.
+     * 
+     * @return true if this ImageCapabilities applies to the VolatileImage which
+     *         can lose its surfaces, false otherwise.
+     */
+    public boolean isTrueVolatile() {
+        return true;
+    }
+}
diff --git a/awt/java/awt/Insets.java b/awt/java/awt/Insets.java
new file mode 100644
index 0000000..04f198c
--- /dev/null
+++ b/awt/java/awt/Insets.java
@@ -0,0 +1,179 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.io.Serializable;
+
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Insets class represents the borders of a container. This class describes
+ * the space that a container should leave at each edge: the top, the bottom,
+ * the right side, and the left side. The space can be filled with a border, a
+ * blank space, or a title.
+ * 
+ * @since Android 1.0
+ */
+public class Insets implements Cloneable, Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -2272572637695466749L;
+
+    /**
+     * The top inset indicates the size of the space added to the top of the
+     * rectangle.
+     */
+    public int top;
+
+    /**
+     * The left inset indicates the size of the space added to the left side of
+     * the rectangle.
+     */
+    public int left;
+
+    /**
+     * The bottom inset indicates the size of the space subtracted from the
+     * bottom of the rectangle.
+     */
+    public int bottom;
+
+    /**
+     * The right inset indicates the size of the space subtracted from the right
+     * side of the rectangle.
+     */
+    public int right;
+
+    /**
+     * Instantiates a new Inset object with the specified top, left, bottom,
+     * right parameters.
+     * 
+     * @param top
+     *            the top inset.
+     * @param left
+     *            the left inset.
+     * @param bottom
+     *            the bottom inset.
+     * @param right
+     *            the right inset.
+     */
+    public Insets(int top, int left, int bottom, int right) {
+        setValues(top, left, bottom, right);
+    }
+
+    /**
+     * Returns a hash code of the Insets object.
+     * 
+     * @return a hash code of the Insets object.
+     */
+    @Override
+    public int hashCode() {
+        int hashCode = HashCode.EMPTY_HASH_CODE;
+        hashCode = HashCode.combine(hashCode, top);
+        hashCode = HashCode.combine(hashCode, left);
+        hashCode = HashCode.combine(hashCode, bottom);
+        hashCode = HashCode.combine(hashCode, right);
+        return hashCode;
+    }
+
+    /**
+     * Returns a copy of this Insets object.
+     * 
+     * @return a copy of this Insets object.
+     */
+    @Override
+    public Object clone() {
+        return new Insets(top, left, bottom, right);
+    }
+
+    /**
+     * Checks if this Insets object is equal to the specified object.
+     * 
+     * @param o
+     *            the Object to be compared.
+     * @return true, if the object is an Insets object whose data values are
+     *         equal to those of this object, false otherwise.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (o instanceof Insets) {
+            Insets i = (Insets)o;
+            return ((i.left == left) && (i.bottom == bottom) && (i.right == right) && (i.top == top));
+        }
+        return false;
+    }
+
+    /**
+     * Returns a String representation of this Insets object.
+     * 
+     * @return a String representation of this Insets object.
+     */
+    @Override
+    public String toString() {
+        /*
+         * The format is based on 1.5 release behavior which can be revealed by
+         * the following code: System.out.println(new Insets(1, 2, 3, 4));
+         */
+
+        return (getClass().getName() + "[left=" + left + ",top=" + top + //$NON-NLS-1$ //$NON-NLS-2$
+                ",right=" + right + ",bottom=" + bottom + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+
+    /**
+     * Sets top, left, bottom, and right insets to the specified values.
+     * 
+     * @param top
+     *            the top inset.
+     * @param left
+     *            the left inset.
+     * @param bottom
+     *            the bottom inset.
+     * @param right
+     *            the right inset.
+     */
+    public void set(int top, int left, int bottom, int right) {
+        setValues(top, left, bottom, right);
+    }
+
+    /**
+     * Sets the values.
+     * 
+     * @param top
+     *            the top.
+     * @param left
+     *            the left.
+     * @param bottom
+     *            the bottom.
+     * @param right
+     *            the right.
+     */
+    private void setValues(int top, int left, int bottom, int right) {
+        this.top = top;
+        this.left = left;
+        this.bottom = bottom;
+        this.right = right;
+    }
+}
diff --git a/awt/java/awt/ItemSelectable.java b/awt/java/awt/ItemSelectable.java
new file mode 100644
index 0000000..212cf70
--- /dev/null
+++ b/awt/java/awt/ItemSelectable.java
@@ -0,0 +1,59 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.event.ItemListener;
+
+/**
+ * The ItemSelectable interface represents a set of items which can be selected.
+ * 
+ * @since Android 1.0
+ */
+public interface ItemSelectable {
+
+    /**
+     * Adds an ItemListener for receiving item events when the state of an item
+     * is changed by the user.
+     * 
+     * @param l
+     *            the ItemListener.
+     */
+    public void addItemListener(ItemListener l);
+
+    /**
+     * Gets an array of the selected objects or null if there is no selected
+     * object.
+     * 
+     * @return an array of the selected objects or null if there is no selected
+     *         object.
+     */
+    public Object[] getSelectedObjects();
+
+    /**
+     * Removes the specified ItemListener.
+     * 
+     * @param l
+     *            the ItemListener which will be removed.
+     */
+    public void removeItemListener(ItemListener l);
+
+}
diff --git a/awt/java/awt/MenuComponent.java b/awt/java/awt/MenuComponent.java
new file mode 100644
index 0000000..9c1b120
--- /dev/null
+++ b/awt/java/awt/MenuComponent.java
@@ -0,0 +1,783 @@
+/*
+ *  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.
+ */
+
+package java.awt;
+
+import java.awt.event.FocusListener;
+import java.awt.event.MouseEvent;
+import java.awt.peer.MenuComponentPeer;
+import java.io.Serializable;
+import java.util.Locale; //import javax.accessibility.Accessible;
+//import javax.accessibility.AccessibleComponent;
+//import javax.accessibility.AccessibleContext;
+//import javax.accessibility.AccessibleRole;
+//import javax.accessibility.AccessibleSelection;
+//import javax.accessibility.AccessibleStateSet;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.state.MenuItemState;
+import org.apache.harmony.awt.state.MenuState;
+import org.apache.harmony.luni.util.NotImplementedException;
+
+/**
+ * The MenuComponent abstract class is the superclass for menu components. Menu
+ * components receive and process AWT events.
+ * 
+ * @since Android 1.0
+ */
+public abstract class MenuComponent implements Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -4536902356223894379L;
+
+    /**
+     * The name.
+     */
+    private String name;
+
+    /**
+     * The font.
+     */
+    private Font font;
+
+    /**
+     * The parent.
+     */
+    MenuContainer parent;
+
+    /**
+     * The deprecated event handler.
+     */
+    boolean deprecatedEventHandler = true;
+
+    /**
+     * The selected item index.
+     */
+    private int selectedItemIndex;
+
+    // ???AWT: private AccessibleContext accessibleContext;
+
+    /**
+     * The toolkit.
+     */
+    final Toolkit toolkit = Toolkit.getDefaultToolkit();
+
+    // ???AWT
+    /*
+     * protected abstract class AccessibleAWTMenuComponent extends
+     * AccessibleContext implements Serializable, AccessibleComponent,
+     * AccessibleSelection { private static final long serialVersionUID =
+     * -4269533416223798698L; public void addFocusListener(FocusListener
+     * listener) { } public boolean contains(Point pt) { return false; } public
+     * Accessible getAccessibleAt(Point pt) { return null; } public Color
+     * getBackground() { return null; } public Rectangle getBounds() { return
+     * null; } public Cursor getCursor() { return null; } public Font getFont()
+     * { return MenuComponent.this.getFont(); } public FontMetrics
+     * getFontMetrics(Font font) { return null; } public Color getForeground() {
+     * return null; } public Point getLocation() { return null; } public Point
+     * getLocationOnScreen() { return null; } public Dimension getSize() {
+     * return null; } public boolean isEnabled() { return true; // always
+     * enabled } public boolean isFocusTraversable() { return true; // always
+     * focus traversable } public boolean isShowing() { return true;// always
+     * showing } public boolean isVisible() { return true; // always visible }
+     * public void removeFocusListener(FocusListener listener) { } public void
+     * requestFocus() { } public void setBackground(Color color) { } public void
+     * setBounds(Rectangle rect) { } public void setCursor(Cursor cursor) { }
+     * public void setEnabled(boolean enabled) { } public void setFont(Font
+     * font) { MenuComponent.this.setFont(font); } public void
+     * setForeground(Color color) { } public void setLocation(Point pt) { }
+     * public void setSize(Dimension pt) { } public void setVisible(boolean
+     * visible) { } public void addAccessibleSelection(int index) { } public
+     * void clearAccessibleSelection() { } public Accessible
+     * getAccessibleSelection(int index) { return null; } public int
+     * getAccessibleSelectionCount() { return 0; } public boolean
+     * isAccessibleChildSelected(int index) { return false; } public void
+     * removeAccessibleSelection(int index) { } public void
+     * selectAllAccessibleSelection() { }
+     * @Override public Accessible getAccessibleChild(int index) { return null;
+     * }
+     * @Override public int getAccessibleChildrenCount() { return 0; }
+     * @Override public AccessibleComponent getAccessibleComponent() { return
+     * this; }
+     * @Override public String getAccessibleDescription() { return
+     * super.getAccessibleDescription(); }
+     * @Override public int getAccessibleIndexInParent() { toolkit.lockAWT();
+     * try { Accessible aParent = getAccessibleParent(); int aIndex = -1; if
+     * (aParent instanceof MenuComponent) { MenuComponent parent =
+     * (MenuComponent) aParent; int count = parent.getItemCount(); for (int i =
+     * 0; i < count; i++) { MenuComponent comp = parent.getItem(i); if (comp
+     * instanceof Accessible) { aIndex++; if (comp == MenuComponent.this) {
+     * return aIndex; } } } } return -1; } finally { toolkit.unlockAWT(); } }
+     * @Override public String getAccessibleName() { return
+     * super.getAccessibleName(); }
+     * @Override public Accessible getAccessibleParent() { toolkit.lockAWT();
+     * try { Accessible aParent = super.getAccessibleParent(); if (aParent !=
+     * null) { return aParent; } MenuContainer parent = getParent(); if (parent
+     * instanceof Accessible) { aParent = (Accessible) parent; } return aParent;
+     * } finally { toolkit.unlockAWT(); } }
+     * @Override public AccessibleRole getAccessibleRole() { return
+     * AccessibleRole.AWT_COMPONENT; }
+     * @Override public AccessibleSelection getAccessibleSelection() { return
+     * this; }
+     * @Override public AccessibleStateSet getAccessibleStateSet() { return new
+     * AccessibleStateSet(); }
+     * @Override public Locale getLocale() { return Locale.getDefault(); } }
+     */
+
+    /**
+     * The accessor to MenuComponent internal state, utilized by the visual
+     * theme.
+     * 
+     * @throws HeadlessException
+     *             the headless exception.
+     */
+    // ???AWT
+    /*
+     * class State implements MenuState { Dimension size; Dimension getSize() {
+     * if (size == null) { calculate(); } return size; } public int getWidth() {
+     * return getSize().width; } public int getHeight() { return
+     * getSize().height; } public Font getFont() { return
+     * MenuComponent.this.getFont(); } public int getItemCount() { return
+     * MenuComponent.this.getItemCount(); } public int getSelectedItemIndex() {
+     * return MenuComponent.this.getSelectedItemIndex(); } public boolean
+     * isFontSet() { return MenuComponent.this.isFontSet(); }
+     * @SuppressWarnings("deprecation") public FontMetrics getFontMetrics(Font
+     * f) { return MenuComponent.this.toolkit.getFontMetrics(f); } public Point
+     * getLocation() { return MenuComponent.this.getLocation(); } public
+     * MenuItemState getItem(int index) { MenuItem item =
+     * MenuComponent.this.getItem(index); return item.itemState; } public void
+     * setSize(int w, int h) { this.size = new Dimension(w, h); } void
+     * calculate() { size = new Dimension();
+     * size.setSize(toolkit.theme.calculateMenuSize(this)); } void reset() { for
+     * (int i = 0; i < getItemCount(); i++) { ((MenuItem.State)
+     * getItem(i)).reset(); } } }
+     */
+
+    /**
+     * Pop-up box for menu. It transfers the paint events, keyboard and mouse
+     * events to the menu component itself.
+     */
+    // ???AWT
+    /*
+     * class MenuPopupBox extends PopupBox { private final Point lastMousePos =
+     * new Point();
+     * @Override boolean isMenu() { return true; }
+     * @Override void paint(Graphics gr) { MenuComponent.this.paint(gr); }
+     * @Override void onKeyEvent(int eventId, int vKey, long when, int
+     * modifiers) { MenuComponent.this.onKeyEvent(eventId, vKey, when,
+     * modifiers); }
+     * @Override void onMouseEvent(int eventId, Point where, int mouseButton,
+     * long when, int modifiers, int wheelRotation) { // prevent conflict of
+     * mouse and keyboard // when sub-menu drops down due to keyboard navigation
+     * if (lastMousePos.equals(where) && (eventId == MouseEvent.MOUSE_MOVED ||
+     * eventId == MouseEvent.MOUSE_ENTERED)) { return; }
+     * lastMousePos.setLocation(where); MenuComponent.this.onMouseEvent(eventId,
+     * where, mouseButton, when, modifiers); } }
+     */
+
+    /**
+     * Instantiates a new MenuComponent object.
+     * 
+     * @throws HeadlessException
+     *             if the graphical interface environment can't support
+     *             MenuComponents.
+     */
+    public MenuComponent() throws HeadlessException {
+        toolkit.lockAWT();
+        try {
+            Toolkit.checkHeadless();
+            name = autoName();
+            selectedItemIndex = -1;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the name of the MenuComponent object.
+     * 
+     * @return the name of the MenuComponent object.
+     */
+    public String getName() {
+        toolkit.lockAWT();
+        try {
+            return name;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Returns a String representation of the MenuComponent object.
+     * 
+     * @return a String representation of the MenuComponent object.
+     */
+    @Override
+    public String toString() {
+        toolkit.lockAWT();
+        try {
+            return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the parent menu container.
+     * 
+     * @return the parent.
+     */
+    public MenuContainer getParent() {
+        toolkit.lockAWT();
+        try {
+            return parent;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the name of the MenuComponent to the specified string.
+     * 
+     * @param name
+     *            the new name of the MenuComponent object.
+     */
+    public void setName(String name) {
+        toolkit.lockAWT();
+        try {
+            this.name = name;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Dispatches AWT event.
+     * 
+     * @param event
+     *            the AWTEvent.
+     */
+    public final void dispatchEvent(AWTEvent event) {
+        toolkit.lockAWT();
+        try {
+            processEvent(event);
+            if (deprecatedEventHandler) {
+                postDeprecatedEvent(event);
+            }
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Post deprecated event.
+     * 
+     * @param event
+     *            the event.
+     */
+    void postDeprecatedEvent(AWTEvent event) {
+        Event evt = event.getEvent();
+        if (evt != null) {
+            postEvent(evt);
+        }
+    }
+
+    /**
+     * Gets the peer of the MenuComponent; an application must not use this
+     * method directly.
+     * 
+     * @return the MenuComponentPeer object.
+     * @throws NotImplementedException
+     *             if this method is not implemented by a subclass.
+     * @deprecated an application must not use this method directly.
+     */
+    @Deprecated
+    public MenuComponentPeer getPeer() throws org.apache.harmony.luni.util.NotImplementedException {
+        toolkit.lockAWT();
+        try {
+        } finally {
+            toolkit.unlockAWT();
+        }
+        if (true) {
+            throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$
+        }
+        return null;
+    }
+
+    /**
+     * Gets the locking object of this MenuComponent.
+     * 
+     * @return the locking object of this MenuComponent.
+     */
+    protected final Object getTreeLock() {
+        return toolkit.awtTreeLock;
+    }
+
+    /**
+     * Posts the Event to the MenuComponent.
+     * 
+     * @param e
+     *            the Event.
+     * @return true, if the event is posted successfully, false otherwise.
+     * @deprecated Replaced dispatchEvent method.
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    public boolean postEvent(Event e) {
+        toolkit.lockAWT();
+        try {
+            if (parent != null) {
+                return parent.postEvent(e);
+            }
+            return false;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Returns the string representation of the MenuComponent state.
+     * 
+     * @return returns the string representation of the MenuComponent state.
+     */
+    protected String paramString() {
+        toolkit.lockAWT();
+        try {
+            return getName();
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    // ???AWT
+    /*
+     * public AccessibleContext getAccessibleContext() { toolkit.lockAWT(); try
+     * { if (accessibleContext == null) { accessibleContext =
+     * createAccessibleContext(); } return accessibleContext; } finally {
+     * toolkit.unlockAWT(); } }
+     */
+
+    /**
+     * Gets the font of the MenuComponent object.
+     * 
+     * @return the Font of the MenuComponent object.
+     */
+    public Font getFont() {
+        toolkit.lockAWT();
+        try {
+            if (font == null && hasDefaultFont()) {
+                return toolkit.getDefaultFont();
+            }
+            if (font == null && parent != null) {
+                return parent.getFont();
+            }
+            return font;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Checks if is font set.
+     * 
+     * @return true, if is font set
+     */
+    boolean isFontSet() {
+        return font != null
+                || ((parent instanceof MenuComponent) && ((MenuComponent)parent).isFontSet());
+    }
+
+    /**
+     * Checks for default font.
+     * 
+     * @return true, if successful.
+     */
+    boolean hasDefaultFont() {
+        return false;
+    }
+
+    /**
+     * Processes an AWTEevent on this menu component.
+     * 
+     * @param event
+     *            the AWTEvent.
+     */
+    protected void processEvent(AWTEvent event) {
+        toolkit.lockAWT();
+        try {
+            // do nothing
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Removes the peer of the MenuComponent.
+     */
+    public void removeNotify() {
+        toolkit.lockAWT();
+        try {
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the Font for this MenuComponent object.
+     * 
+     * @param font
+     *            the new Font to be used for this MenuComponent.
+     */
+    public void setFont(Font font) {
+        toolkit.lockAWT();
+        try {
+            this.font = font;
+        } finally {
+            toolkit.unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the parent.
+     * 
+     * @param parent
+     *            the new parent.
+     */
+    void setParent(MenuContainer parent) {
+        this.parent = parent;
+    }
+
+    /**
+     * Gets the location.
+     * 
+     * @return the location.
+     */
+    Point getLocation() {
+        // to be overridden
+        return new Point(0, 0);
+    }
+
+    /**
+     * Gets the width.
+     * 
+     * @return the width.
+     */
+    int getWidth() {
+        // to be overridden
+        return 1;
+    }
+
+    /**
+     * Gets the height.
+     * 
+     * @return the height.
+     */
+    int getHeight() {
+        // to be overridden
+        return 1;
+    }
+
+    /**
+     * Recursively find the menu item for a menu shortcut.
+     * 
+     * @param gr
+     *            the gr.
+     * @return the menu item; or null if the item is not available for this
+     *         shortcut.
+     */
+    // ???AWT
+    /*
+     * MenuItem getShortcutMenuItemImpl(MenuShortcut ms) { if (ms == null) {
+     * return null; } for (int i = 0; i < getItemCount(); i++) { MenuItem mi =
+     * getItem(i); if (mi instanceof Menu) { mi = ((Menu)
+     * mi).getShortcutMenuItemImpl(ms); if (mi != null) { return mi; } } else if
+     * (ms.equals(mi.getShortcut())) { return mi; } } return null; }
+     */
+
+    void paint(Graphics gr) {
+        gr.setColor(Color.LIGHT_GRAY);
+        gr.fillRect(0, 0, getWidth(), getHeight());
+        gr.setColor(Color.BLACK);
+    }
+
+    /**
+     * Mouse events handler.
+     * 
+     * @param eventId
+     *            one of the MouseEvent.MOUSE_* constants.
+     * @param where
+     *            mouse location.
+     * @param mouseButton
+     *            mouse button that was pressed or released.
+     * @param when
+     *            event time.
+     * @param modifiers
+     *            input event modifiers.
+     */
+    void onMouseEvent(int eventId, Point where, int mouseButton, long when, int modifiers) {
+        // to be overridden
+    }
+
+    /**
+     * Keyboard event handler.
+     * 
+     * @param eventId
+     *            one of the KeyEvent.KEY_* constants.
+     * @param vKey
+     *            the key code.
+     * @param when
+     *            event time.
+     * @param modifiers
+     *            input event modifiers.
+     */
+    void onKeyEvent(int eventId, int vKey, long when, int modifiers) {
+        // to be overridden
+    }
+
+    /**
+     * Post the ActionEvent or ItemEvent, depending on type of the menu item.
+     * 
+     * @param index
+     *            the index.
+     * @return the item rect.
+     */
+    // ???AWT
+    /*
+     * void fireItemAction(int item, long when, int modifiers) { MenuItem mi =
+     * getItem(item); mi.itemSelected(when, modifiers); } MenuItem getItem(int
+     * index) { // to be overridden return null; } int getItemCount() { return
+     * 0; }
+     */
+
+    /**
+     * @return The sub-menu of currently selecetd item, or null if such a
+     *         sub-menu is not available.
+     */
+    // ???AWT
+    /*
+     * Menu getSelectedSubmenu() { if (selectedItemIndex < 0) { return null; }
+     * MenuItem item = getItem(selectedItemIndex); return (item instanceof Menu)
+     * ? (Menu) item : null; }
+     */
+
+    /**
+     * Convenience method for selectItem(index, true).
+     */
+    // ???AWT
+    /*
+     * void selectItem(int index) { selectItem(index, true); }
+     */
+
+    /**
+     * Change the selection in the menu.
+     * 
+     * @param index
+     *            new selecetd item's index.
+     * @param showSubMenu
+     *            if new selected item has a sub-menu, should that sub-menu be
+     *            displayed.
+     */
+    // ???AWT
+    /*
+     * void selectItem(int index, boolean showSubMenu) { if (selectedItemIndex
+     * == index) { return; } if (selectedItemIndex >= 0 &&
+     * getItem(selectedItemIndex) instanceof Menu) { ((Menu)
+     * getItem(selectedItemIndex)).hide(); } MultiRectArea clip =
+     * getUpdateClip(index, selectedItemIndex); selectedItemIndex = index;
+     * Graphics gr = getGraphics(clip); if (gr != null) { paint(gr); } if
+     * (showSubMenu) { showSubMenu(selectedItemIndex); } }
+     */
+
+    /**
+     * Change the selected item to the next one in the requested direction
+     * moving cyclically, skipping separators
+     * 
+     * @param forward
+     *            the direction to move the selection.
+     * @param showSubMenu
+     *            if new selected item has a sub-menu, should that sub-menu be
+     *            displayed.
+     */
+    // ???AWT
+    /*
+     * void selectNextItem(boolean forward, boolean showSubMenu) { int selected
+     * = getSelectedItemIndex(); int count = getItemCount(); if (count == 0) {
+     * return; } if (selected < 0) { selected = (forward ? count - 1 : 0); } int
+     * i = selected; do { i = (forward ? (i + 1) : (i + count - 1)) % count; i
+     * %= count; MenuItem item = getItem(i); if (!"-".equals(item.getLabel())) {
+     * //$NON-NLS-1$ selectItem(i, showSubMenu); return; } } while (i !=
+     * selected); } void showSubMenu(int index) { if ((index < 0) ||
+     * !isActive()) { return; } MenuItem item = getItem(index); if (item
+     * instanceof Menu) { Menu menu = ((Menu) getItem(index)); if
+     * (menu.getItemCount() == 0) { return; } Point location =
+     * getSubmenuLocation(index); menu.show(location.x, location.y, false); } }
+     */
+
+    /**
+     * @return the menu bar which is the root of current menu's hierarchy; or
+     *         null if the hierarchy root is not a menu bar.
+     */
+    // ???AWT
+    /*
+     * MenuBar getMenuBar() { if (parent instanceof MenuBar) { return (MenuBar)
+     * parent; } if (parent instanceof MenuComponent) { return ((MenuComponent)
+     * parent).getMenuBar(); } return null; } PopupBox getPopupBox() { return
+     * null; }
+     */
+
+    Rectangle getItemRect(int index) {
+        // to be overridden
+        return null;
+    }
+
+    /**
+     * Determine the clip region when menu selection is changed from index1 to
+     * index2.
+     * 
+     * @param index1
+     *            old selected item.
+     * @param index2
+     *            new selected item.
+     * @return the region to repaint.
+     */
+    final MultiRectArea getUpdateClip(int index1, int index2) {
+        MultiRectArea clip = new MultiRectArea();
+        if (index1 >= 0) {
+            clip.add(getItemRect(index1));
+        }
+        if (index2 >= 0) {
+            clip.add(getItemRect(index2));
+        }
+        return clip;
+    }
+
+    /**
+     * Gets the submenu location.
+     * 
+     * @param index
+     *            the index.
+     * @return the submenu location.
+     */
+    Point getSubmenuLocation(int index) {
+        // to be overridden
+        return new Point(0, 0);
+    }
+
+    /**
+     * Gets the selected item index.
+     * 
+     * @return the selected item index.
+     */
+    int getSelectedItemIndex() {
+        return selectedItemIndex;
+    }
+
+    /**
+     * Hide.
+     */
+    void hide() {
+        selectedItemIndex = -1;
+        if (parent instanceof MenuComponent) {
+            ((MenuComponent)parent).itemHidden(this);
+        }
+    }
+
+    /**
+     * Item hidden.
+     * 
+     * @param mc
+     *            the mc.
+     */
+    void itemHidden(MenuComponent mc) {
+        // to be overridden
+    }
+
+    /**
+     * Checks if is visible.
+     * 
+     * @return true, if is visible.
+     */
+    boolean isVisible() {
+        return true;
+    }
+
+    /**
+     * Checks if is active.
+     * 
+     * @return true, if is active.
+     */
+    boolean isActive() {
+        return true;
+    }
+
+    /**
+     * Hide all menu hierarchy.
+     */
+    void endMenu() {
+        // ???AWT: toolkit.dispatcher.popupDispatcher.deactivateAll();
+    }
+
+    /**
+     * Handle the mouse click or Enter key event on a menu's item.
+     * 
+     * @param when
+     *            the event time.
+     * @param modifiers
+     *            input event modifiers.
+     */
+    void itemSelected(long when, int modifiers) {
+        endMenu();
+    }
+
+    /**
+     * Auto name.
+     * 
+     * @return the string.
+     */
+    String autoName() {
+        String name = getClass().getName();
+        if (name.indexOf("$") != -1) { //$NON-NLS-1$
+            return null;
+        }
+        // ???AWT: int number = toolkit.autoNumber.nextMenuComponent++;
+        int number = 0;
+        name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$
+        return name;
+    }
+
+    /**
+     * Creates the Graphics object for the pop-up box of this menu component.
+     * 
+     * @param clip
+     *            the clip to set on this Graphics.
+     * @return the created Graphics object, or null if such object is not
+     *         available.
+     */
+    Graphics getGraphics(MultiRectArea clip) {
+        // to be overridden
+        return null;
+    }
+
+    /**
+     * @return accessible context specific for particular menu component.
+     */
+    // ???AWT
+    /*
+     * AccessibleContext createAccessibleContext() { return null; }
+     */
+}
diff --git a/awt/java/awt/MenuContainer.java b/awt/java/awt/MenuContainer.java
new file mode 100644
index 0000000..e509a1b
--- /dev/null
+++ b/awt/java/awt/MenuContainer.java
@@ -0,0 +1,57 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+/**
+ * The MenuContainer interface represents all menu containers.
+ * 
+ * @since Android 1.0
+ */
+public interface MenuContainer {
+
+    /**
+     * Removes the specified MenuComponent from the MenuContainer.
+     * 
+     * @param c
+     *            the MenuComponent.
+     */
+    public void remove(MenuComponent c);
+
+    /**
+     * Gets the Font of the MenuContainer.
+     * 
+     * @return the font of the MenuContainer.
+     */
+    public Font getFont();
+
+    /**
+     * Posts an Event.
+     * 
+     * @param e
+     *            the Event.
+     * @return true if the event is posted successfully, false otherwise.
+     * @deprecated Replaced by dispatchEvent method.
+     */
+    @Deprecated
+    public boolean postEvent(Event e);
+
+}
diff --git a/awt/java/awt/ModalContext.java b/awt/java/awt/ModalContext.java
new file mode 100644
index 0000000..32a5912
--- /dev/null
+++ b/awt/java/awt/ModalContext.java
@@ -0,0 +1,64 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ *
+ * The context for nested event loop. It can be dialog, popup menu etc.
+ */
+class ModalContext {
+
+    private boolean running = false;
+
+    private final Toolkit toolkit;
+
+    ModalContext() {
+        toolkit = Toolkit.getDefaultToolkit();
+    }
+
+    /**
+     * Set up and run modal loop in this context
+     *
+     */
+    void runModalLoop() {
+        running = true;
+        toolkit.dispatchThread.runModalLoop(this);
+    }
+
+    /**
+     * Leave the modal loop running in this context
+     * This method doesn't stops the loop immediately,
+     * it just sets the flag that says the modal loop to stop
+     *
+     */
+    void endModalLoop() {
+        running = false;
+    }
+
+    /**
+     *
+     * @return modal loop is currently running in this context
+     */
+    boolean isModalLoopRunning() {
+        return running;
+    }
+
+}
diff --git a/awt/java/awt/MouseDispatcher.java b/awt/java/awt/MouseDispatcher.java
new file mode 100644
index 0000000..df48f9d
--- /dev/null
+++ b/awt/java/awt/MouseDispatcher.java
@@ -0,0 +1,418 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev, Michael Danilov, Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.awt.Dispatcher.MouseGrabManager;
+import java.util.EventListener;
+
+import org.apache.harmony.awt.wtk.NativeEvent;
+import org.apache.harmony.awt.wtk.NativeWindow;
+
+
+class MouseDispatcher {
+
+    // Fields for synthetic mouse click events generation
+    private static final int clickDelta = 5;
+    private final long[] lastPressTime = new long[] {0l, 0l, 0l};
+    private final Point[] lastPressPos = new Point[] {null, null, null};
+    private final boolean[] buttonPressed = new boolean[] {false, false, false};
+    private final int[] clickCount = new int[] {0, 0, 0};
+
+    // Fields for mouse entered/exited support
+    private Component lastUnderPointer = null;
+    private final Point lastScreenPos = new Point(-1, -1);
+
+    // Fields for redundant mouse moved/dragged filtering
+    private Component lastUnderMotion = null;
+    private Point lastLocalPos = new Point(-1, -1);
+
+    private final MouseGrabManager mouseGrabManager;
+    private final Toolkit toolkit;
+
+    static Point convertPoint(Component src, int x, int y, Component dest) {
+        Point srcPoint = getAbsLocation(src);
+        Point destPoint = getAbsLocation(dest);
+
+        return new Point(x + (srcPoint.x - destPoint.x),
+                         y + (srcPoint.y - destPoint.y));
+    }
+
+    static Point convertPoint(Component src, Point p, Component dst) {
+        return convertPoint(src, p.x, p.y, dst);
+    }
+
+    private static Point getAbsLocation(Component comp) {
+        Point location = new Point(0, 0);
+// BEGIN android-changed: AWT components not supported
+//        for (Component parent = comp; parent != null; parent = parent.parent) {
+//            Point parentPos = (parent instanceof EmbeddedWindow ?
+//                               parent.getNativeWindow().getScreenPos() :
+//                               parent.getLocation());
+//
+//            location.translate(parentPos.x, parentPos.y);
+//
+//            if (parent instanceof Window) {
+//                break;
+//            }
+//        }
+// END android-changed
+
+        return location;
+    }
+
+    MouseDispatcher(MouseGrabManager mouseGrabManager,
+                    Toolkit toolkit) {
+        this.mouseGrabManager = mouseGrabManager;
+        this.toolkit = toolkit;
+    }
+
+    Point getPointerPos() {
+        return lastScreenPos;
+    }
+
+    boolean dispatch(Component src, NativeEvent event) {
+        int id = event.getEventId();
+
+        lastScreenPos.setLocation(event.getScreenPos());
+        checkMouseEnterExit(event.getInputModifiers(), event.getTime());
+
+        if (id == MouseEvent.MOUSE_WHEEL) {
+// BEGIN android-changed: AWT components not supported
+//            dispatchWheelEvent(src, event);
+// END android-changed
+        } else if ((id != MouseEvent.MOUSE_ENTERED) &&
+                   (id != MouseEvent.MOUSE_EXITED)) {
+            PointerInfo info = new PointerInfo(src, event.getLocalPos());
+
+            mouseGrabManager.preprocessEvent(event);
+            findEventSource(info);
+            if ((id == MouseEvent.MOUSE_PRESSED) ||
+                (id == MouseEvent.MOUSE_RELEASED)) {
+
+                dispatchButtonEvent(info, event);
+            } else if ((id == MouseEvent.MOUSE_MOVED) ||
+                       (id == MouseEvent.MOUSE_DRAGGED)) {
+
+                dispatchMotionEvent(info, event);
+            }
+        }
+
+        return false;
+    }
+
+    private void checkMouseEnterExit(int modifiers, long when) {
+// BEGIN android-changed: AWT components not supported
+//        PointerInfo info = findComponentUnderPointer();
+//        Component curUnderPointer =
+//                propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK,
+//                               MouseListener.class, false).src;
+//
+//        if (curUnderPointer != lastUnderPointer) {
+//            Point pos = info.position;
+//            if ((lastUnderPointer != null) &&
+//                 lastUnderPointer.isMouseExitedExpected()) {
+//
+//                Point exitPos = convertPoint(null, lastScreenPos.x,
+//                                             lastScreenPos.y, lastUnderPointer);
+//
+//                postMouseEnterExit(MouseEvent.MOUSE_EXITED, modifiers, when,
+//                                   exitPos.x, exitPos.y, lastUnderPointer);
+//            }
+//            setCursor(curUnderPointer);
+//            if (curUnderPointer != null) {
+//                postMouseEnterExit(MouseEvent.MOUSE_ENTERED, modifiers, when,
+//                                   pos.x, pos.y, curUnderPointer);
+//            }
+//            lastUnderPointer = curUnderPointer;
+//        }
+// END android-changed
+    }
+
+    private void setCursor(Component comp) {
+        if (comp == null) {
+            return;
+        }
+        Component grabOwner = mouseGrabManager.getSyntheticGrabOwner();
+        Component cursorComp = ((grabOwner != null) &&
+                                 grabOwner.isShowing() ? grabOwner : comp);
+        cursorComp.setCursor();
+    }
+
+    private void postMouseEnterExit(int id, int mod, long when,
+                                    int x, int y, Component comp) {
+        if (comp.isIndirectlyEnabled()) {
+            toolkit.getSystemEventQueueImpl().postEvent(
+                    new MouseEvent(comp, id, when, mod, x, y, 0, false));
+            comp.setMouseExitedExpected(id == MouseEvent.MOUSE_ENTERED);
+        } else {
+            comp.setMouseExitedExpected(false);
+        }
+    }
+
+ // BEGIN android-changed: AWT components not supported
+//    private PointerInfo findComponentUnderPointer() {
+//        NativeWindow nativeWindow = toolkit.getWindowFactory().
+//        getWindowFromPoint(lastScreenPos);
+//
+//        if (nativeWindow != null) {
+//            Component comp = toolkit.getComponentById(nativeWindow.getId());
+//
+//            if (comp != null) {
+//                Window window = comp.getWindowAncestor();
+//                Point pointerPos = convertPoint(null, lastScreenPos.x,
+//                                                lastScreenPos.y, window);
+//
+//                if (window.getClient().contains(pointerPos)) {
+//                    PointerInfo info = new PointerInfo(window, pointerPos);
+//
+//                    fall2Child(info);
+//
+//                    return info;
+//                }
+//            }
+//        }
+//
+//        return new PointerInfo(null, null);
+//    }
+// END android-changed
+    
+    private void findEventSource(PointerInfo info) {
+        Component grabOwner = mouseGrabManager.getSyntheticGrabOwner();
+
+        if (grabOwner != null && grabOwner.isShowing()) {
+            info.position = convertPoint(info.src, info.position, grabOwner);
+            info.src = grabOwner;
+        } else {
+            //???AWT: rise2TopLevel(info);
+            //???AWT: fall2Child(info);
+        }
+    }
+
+ // BEGIN android-changed: AWT components not supported
+//    private void rise2TopLevel(PointerInfo info) {
+//        while (!(info.src instanceof Window)) {
+//            info.position.translate(info.src.x, info.src.y);
+//            info.src = info.src.parent;
+//        }
+//    }
+//
+//    private void fall2Child(PointerInfo info) {
+//        Insets insets = info.src.getInsets();
+//
+//        final Point pos = info.position;
+//        final int x = pos.x;
+//        final int y = pos.y;
+//        if ((x >= insets.left) && (y >= insets.top) &&
+//                (x < (info.src.w - insets.right)) &&
+//                (y < (info.src.h - insets.bottom)))
+//        {
+//            Component[] children = ((Container) info.src).getComponents();
+//
+//            for (Component child : children) {
+//                if (child.isShowing()) {
+//                    if (child.contains(x - child.getX(),
+//                            y - child.getY()))
+//                    {
+//                        info.src = child;
+//                        pos.translate(-child.x, -child.y);
+//
+//                        if (child instanceof Container) {
+//                            fall2Child(info);
+//                        }
+//
+//                        return;
+//                    }
+//                }
+//            }
+//        }
+//    }
+// END android-changed
+
+    private void dispatchButtonEvent(PointerInfo info, NativeEvent event) {
+        int button = event.getMouseButton();
+        long time = event.getTime();
+        int id = event.getEventId();
+        int index = button - 1;
+        boolean clickRequired = false;
+
+        propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK,
+                       MouseListener.class, false);
+        if (id == MouseEvent.MOUSE_PRESSED) {
+            int clickInterval = toolkit.dispatcher.clickInterval;
+            mouseGrabManager.onMousePressed(info.src);
+            buttonPressed[index] = true;
+            clickCount[index] = (!deltaExceeded(index, info) &&
+                    ((time - lastPressTime[index]) <= clickInterval)) ?
+                    clickCount[index] + 1 : 1;
+            lastPressTime[index] = time;
+            lastPressPos[index] = info.position;
+        } else {
+            mouseGrabManager.onMouseReleased(info.src);
+            // set cursor back on synthetic mouse grab end:
+// BEGIN android-changed: AWT components not supported
+//            setCursor(findComponentUnderPointer().src);
+// END android-changed
+            if (buttonPressed[index]) {
+                buttonPressed[index] = false;
+                clickRequired = !deltaExceeded(index, info);
+            } else {
+                clickCount[index] = 0;
+            }
+        }
+        if (info.src.isIndirectlyEnabled()) {
+            final Point pos = info.position;
+            final int mod = event.getInputModifiers();
+            toolkit.getSystemEventQueueImpl().postEvent(
+                            new MouseEvent(info.src, id, time, mod, pos.x,
+                            pos.y, clickCount[index],
+                            event.getTrigger(), button));
+            if (clickRequired) {
+                toolkit.getSystemEventQueueImpl().postEvent(
+                            new MouseEvent(info.src,
+                            MouseEvent.MOUSE_CLICKED,
+                            time, mod, pos.x, pos.y,
+                            clickCount[index], false,
+                            button));
+            }
+        }
+    }
+
+    private boolean deltaExceeded(int index, PointerInfo info) {
+        final Point lastPos = lastPressPos[index];
+        if (lastPos == null) {
+            return true;
+        }
+        return ((Math.abs(lastPos.x - info.position.x) > clickDelta) ||
+                (Math.abs(lastPos.y - info.position.y) > clickDelta));
+    }
+
+    private void dispatchMotionEvent(PointerInfo info, NativeEvent event) {
+        propagateEvent(info, AWTEvent.MOUSE_MOTION_EVENT_MASK,
+                       MouseMotionListener.class, false);
+        final Point pos = info.position;
+        if ((lastUnderMotion != info.src) ||
+            !lastLocalPos.equals(pos)) {
+
+            lastUnderMotion = info.src;
+            lastLocalPos = pos;
+
+            if (info.src.isIndirectlyEnabled()) {
+                toolkit.getSystemEventQueueImpl().postEvent(
+                            new MouseEvent(info.src, event.getEventId(),
+                            event.getTime(),
+                            event.getInputModifiers(),
+                            pos.x, pos.y, 0, false));
+            }
+        }
+    }
+
+    MouseWheelEvent createWheelEvent(Component src, NativeEvent event,
+                                     Point where) {
+
+        Integer scrollAmountProperty =
+            (Integer)toolkit.getDesktopProperty("awt.wheelScrollingSize"); //$NON-NLS-1$
+        int amount = 1;
+        int type = MouseWheelEvent.WHEEL_UNIT_SCROLL;
+
+        if (scrollAmountProperty != null) {
+            amount = scrollAmountProperty.intValue();
+            if (amount == -1) {
+                type = MouseWheelEvent.WHEEL_BLOCK_SCROLL;
+                amount = 1;
+            }
+        }
+        return new MouseWheelEvent(src, event.getEventId(),
+                event.getTime(), event.getInputModifiers(),
+                where.x, where.y, 0, false, type, amount,
+                event.getWheelRotation());
+    }
+
+// BEGIN android-changed: AWT components not supported
+//    private void dispatchWheelEvent(Component src, NativeEvent event) {
+//        PointerInfo info = findComponentUnderPointer();
+//
+//        if (info.src == null) {
+//            info.src = src;
+//            info.position = event.getLocalPos();
+//        }
+//
+//        propagateEvent(info, AWTEvent.MOUSE_WHEEL_EVENT_MASK,
+//                       MouseWheelListener.class, true);
+//        if ((info.src != null) && info.src.isIndirectlyEnabled()) {
+//            toolkit.getSystemEventQueueImpl().postEvent(
+//                    createWheelEvent(info.src, event, info.position));
+//        }
+//    }
+// END android-changed
+
+    private PointerInfo propagateEvent(PointerInfo info, long mask,
+                                       Class<? extends EventListener> type, boolean pierceHW) {
+        Component src = info.src;
+        while ((src != null) &&
+               (src.isLightweight() || pierceHW) &&
+              !(src.isMouseEventEnabled(mask) ||
+               (src.getListeners(type).length > 0))) {
+
+            info.position.translate(src.x, src.y);
+// BEGIN android-changed: AWT components not supported
+//            src = src.parent;
+// END android-changed
+            info.src = src;
+        }
+
+        return info;
+    }
+
+// BEGIN android-changed: AWT components not supported
+//    Window findWindowAt(Point p) {
+//        NativeWindow nativeWindow =
+//            toolkit.getWindowFactory().getWindowFromPoint(p);
+//
+//        Window window = null;
+//        if (nativeWindow != null) {
+//            Component comp = toolkit.getComponentById(nativeWindow.getId());
+//
+//            if (comp != null) {
+//                window = comp.getWindowAncestor();
+//            }
+//        }
+//        return window;
+//    }
+// END android-changed
+
+    private class PointerInfo {
+
+        Component src;
+        Point position;
+
+        PointerInfo(Component src, Point position) {
+            this.src = src;
+            this.position = position;
+        }
+
+    }
+
+}
diff --git a/awt/java/awt/Paint.java b/awt/java/awt/Paint.java
new file mode 100644
index 0000000..dfea3a7
--- /dev/null
+++ b/awt/java/awt/Paint.java
@@ -0,0 +1,57 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+
+/**
+ * The Paint interface provides possibility of generating color patterns in
+ * device space for fill, draw, or stroke operations in a Graphics2D.
+ * 
+ * @since Android 1.0
+ */
+public interface Paint extends Transparency {
+
+    /**
+     * Creates the PaintContext which is used to generate color patterns for
+     * rendering operations of Graphics2D.
+     * 
+     * @param cm
+     *            the ColorModel object, or null.
+     * @param deviceBounds
+     *            the Rectangle represents the bounding box of device space for
+     *            the graphics rendering operations.
+     * @param userBounds
+     *            the Rectangle represents bounding box of user space for the
+     *            graphics rendering operations.
+     * @param xform
+     *            the AffineTransform for translation from user space to device
+     *            space.
+     * @param hints
+     *            the RenderingHints preferences.
+     * @return the PaintContext for generating color patterns.
+     */
+    PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds,
+            AffineTransform xform, RenderingHints hints);
+}
diff --git a/awt/java/awt/PaintContext.java b/awt/java/awt/PaintContext.java
new file mode 100644
index 0000000..966b6ca
--- /dev/null
+++ b/awt/java/awt/PaintContext.java
@@ -0,0 +1,69 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+
+/**
+ * The PaintContext interface determines the specific environment for generating
+ * color patterns in device space for fill, draw, or stroke rendering operations
+ * using Graphics2D. This interface provides colors through the Raster object
+ * associated with the specific ColorModel for Graphics2D rendering operations.
+ * 
+ * @since Android 1.0
+ */
+public interface PaintContext {
+
+    /**
+     * Releases the resources allocated for the operation.
+     */
+    void dispose();
+
+    /**
+     * Gets the color model.
+     * 
+     * @return the ColorModel object.
+     */
+    ColorModel getColorModel();
+
+    /**
+     * Gets the Raster which defines the colors of the specified rectangular
+     * area for Graphics2D rendering operations.
+     * 
+     * @param x
+     *            the X coordinate of the device space area for which colors are
+     *            generated.
+     * @param y
+     *            the Y coordinate of the device space area for which colors are
+     *            generated.
+     * @param w
+     *            the width of the device space area for which colors are
+     *            generated.
+     * @param h
+     *            the height of the device space area for which colors are
+     *            generated.
+     * @return the Raster object which contains the colors of the specified
+     *         rectangular area for Graphics2D rendering operations.
+     */
+    Raster getRaster(int x, int y, int w, int h);
+}
diff --git a/awt/java/awt/Point.java b/awt/java/awt/Point.java
new file mode 100644
index 0000000..8ec4241
--- /dev/null
+++ b/awt/java/awt/Point.java
@@ -0,0 +1,211 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.geom.Point2D;
+import java.io.Serializable;
+
+/**
+ * The Point class represents a point location with coordinates X, Y in current
+ * coordinate system.
+ * 
+ * @since Android 1.0
+ */
+public class Point extends Point2D implements Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -5276940640259749850L;
+
+    /**
+     * The X coordinate of Point.
+     */
+    public int x;
+
+    /**
+     * The Y coordinate of Point.
+     */
+    public int y;
+
+    /**
+     * Instantiates a new point with (0, O) coordinates, the origin of
+     * coordinate system.
+     */
+    public Point() {
+        setLocation(0, 0);
+    }
+
+    /**
+     * Instantiates a new point with (x, y) coordinates.
+     * 
+     * @param x
+     *            the X coordinate of Point.
+     * @param y
+     *            the Y coordinate of Point.
+     */
+    public Point(int x, int y) {
+        setLocation(x, y);
+    }
+
+    /**
+     * Instantiates a new point, giving it the same location as the parameter p.
+     * 
+     * @param p
+     *            the Point object giving the coordinates of the new point.
+     */
+    public Point(Point p) {
+        setLocation(p.x, p.y);
+    }
+
+    /**
+     * Compares current Point with the specified object.
+     * 
+     * @param obj
+     *            the Object to be compared.
+     * @return true, if the Object being compared is a Point whose coordinates
+     *         are equal to the coordinates of this Point, false otherwise.
+     * @see java.awt.geom.Point2D#equals(Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof Point) {
+            Point p = (Point)obj;
+            return x == p.x && y == p.y;
+        }
+        return false;
+    }
+
+    /**
+     * Returns string representation of the current Point object.
+     * 
+     * @return a string representation of the current Point object.
+     */
+    @Override
+    public String toString() {
+        return getClass().getName() + "[x=" + x + ",y=" + y + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+
+    /**
+     * Gets X coordinate of Point as a double.
+     * 
+     * @return X coordinate of the point as a double.
+     * @see java.awt.geom.Point2D#getX()
+     */
+    @Override
+    public double getX() {
+        return x;
+    }
+
+    /**
+     * Gets Y coordinate of Point as a double.
+     * 
+     * @return Y coordinate of the point as a double.
+     * @see java.awt.geom.Point2D#getY()
+     */
+    @Override
+    public double getY() {
+        return y;
+    }
+
+    /**
+     * Gets the location of the Point as a new Point object.
+     * 
+     * @return a copy of the Point.
+     */
+    public Point getLocation() {
+        return new Point(x, y);
+    }
+
+    /**
+     * Sets the location of the Point to the same coordinates as p.
+     * 
+     * @param p
+     *            the Point that gives the new location.
+     */
+    public void setLocation(Point p) {
+        setLocation(p.x, p.y);
+    }
+
+    /**
+     * Sets the location of the Point to the coordinates X, Y.
+     * 
+     * @param x
+     *            the X coordinate of the Point's new location.
+     * @param y
+     *            the Y coordinate of the Point's new location.
+     */
+    public void setLocation(int x, int y) {
+        this.x = x;
+        this.y = y;
+    }
+
+    /**
+     * Sets the location of Point to the specified double coordinates.
+     * 
+     * @param x
+     *            the X the Point's new location.
+     * @param y
+     *            the Y the Point's new location.
+     * @see java.awt.geom.Point2D#setLocation(double, double)
+     */
+    @Override
+    public void setLocation(double x, double y) {
+        x = x < Integer.MIN_VALUE ? Integer.MIN_VALUE : x > Integer.MAX_VALUE ? Integer.MAX_VALUE
+                : x;
+        y = y < Integer.MIN_VALUE ? Integer.MIN_VALUE : y > Integer.MAX_VALUE ? Integer.MAX_VALUE
+                : y;
+        setLocation((int)Math.round(x), (int)Math.round(y));
+    }
+
+    /**
+     * Moves the Point to the specified (x, y) location.
+     * 
+     * @param x
+     *            the X coordinate of the new location.
+     * @param y
+     *            the Y coordinate of the new location.
+     */
+    public void move(int x, int y) {
+        setLocation(x, y);
+    }
+
+    /**
+     * Translates current Point moving it from the position (x, y) to the new
+     * position given by (x+dx, x+dy) coordinates.
+     * 
+     * @param dx
+     *            the horizontal delta - the Point is moved to this distance
+     *            along X axis.
+     * @param dy
+     *            the vertical delta - the Point is moved to this distance along
+     *            Y axis.
+     */
+    public void translate(int dx, int dy) {
+        x += dx;
+        y += dy;
+    }
+
+}
diff --git a/awt/java/awt/Polygon.java b/awt/java/awt/Polygon.java
new file mode 100644
index 0000000..de31eb9
--- /dev/null
+++ b/awt/java/awt/Polygon.java
@@ -0,0 +1,515 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.io.Serializable;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.gl.*;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Polygon class defines an closed area specified by n vertices and n edges.
+ * The coordinates of the vertices are specified by x, y arrays. The edges are
+ * the line segments from the point (x[i], y[i]) to the point (x[i+1], y[i+1]),
+ * for -1 < i < (n-1) plus the line segment from the point (x[n-1], y[n-1]) to
+ * the point (x[0], y[0]) point. The Polygon is empty if the number of vertices
+ * is zero.
+ * 
+ * @since Android 1.0
+ */
+public class Polygon implements Shape, Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -6460061437900069969L;
+
+    /**
+     * The points buffer capacity.
+     */
+    private static final int BUFFER_CAPACITY = 4;
+
+    /**
+     * The number of Polygon vertices.
+     */
+    public int npoints;
+
+    /**
+     * The array of X coordinates of the vertices.
+     */
+    public int[] xpoints;
+
+    /**
+     * The array of Y coordinates of the vertices.
+     */
+    public int[] ypoints;
+
+    /**
+     * The smallest Rectangle that completely contains this Polygon.
+     */
+    protected Rectangle bounds;
+
+    /*
+     * Polygon path iterator
+     */
+    /**
+     * The internal Class Iterator.
+     */
+    class Iterator implements PathIterator {
+
+        /**
+         * The source Polygon object.
+         */
+        public Polygon p;
+
+        /**
+         * The path iterator transformation.
+         */
+        public AffineTransform t;
+
+        /**
+         * The current segment index.
+         */
+        public int index;
+
+        /**
+         * Constructs a new Polygon.Iterator for the given polygon and
+         * transformation
+         * 
+         * @param at
+         *            the AffineTransform object to apply rectangle path.
+         * @param p
+         *            the p.
+         */
+        public Iterator(AffineTransform at, Polygon p) {
+            this.p = p;
+            this.t = at;
+            if (p.npoints == 0) {
+                index = 1;
+            }
+        }
+
+        public int getWindingRule() {
+            return WIND_EVEN_ODD;
+        }
+
+        public boolean isDone() {
+            return index > p.npoints;
+        }
+
+        public void next() {
+            index++;
+        }
+
+        public int currentSegment(double[] coords) {
+            if (isDone()) {
+                // awt.110=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.110")); //$NON-NLS-1$
+            }
+            if (index == p.npoints) {
+                return SEG_CLOSE;
+            }
+            coords[0] = p.xpoints[index];
+            coords[1] = p.ypoints[index];
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, 1);
+            }
+            return index == 0 ? SEG_MOVETO : SEG_LINETO;
+        }
+
+        public int currentSegment(float[] coords) {
+            if (isDone()) {
+                // awt.110=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.110")); //$NON-NLS-1$
+            }
+            if (index == p.npoints) {
+                return SEG_CLOSE;
+            }
+            coords[0] = p.xpoints[index];
+            coords[1] = p.ypoints[index];
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, 1);
+            }
+            return index == 0 ? SEG_MOVETO : SEG_LINETO;
+        }
+    }
+
+    /**
+     * Instantiates a new empty polygon.
+     */
+    public Polygon() {
+        xpoints = new int[BUFFER_CAPACITY];
+        ypoints = new int[BUFFER_CAPACITY];
+    }
+
+    /**
+     * Instantiates a new polygon with the specified number of vertices, and the
+     * given arrays of x, y vertex coordinates. The length of each coordinate
+     * array may not be less than the specified number of vertices but may be
+     * greater. Only the first n elements are used from each coordinate array.
+     * 
+     * @param xpoints
+     *            the array of X vertex coordinates.
+     * @param ypoints
+     *            the array of Y vertex coordinates.
+     * @param npoints
+     *            the number vertices of the polygon.
+     * @throws IndexOutOfBoundsException
+     *             if the length of xpoints or ypoints is less than n.
+     * @throws NegativeArraySizeException
+     *             if n is negative.
+     */
+    public Polygon(int[] xpoints, int[] ypoints, int npoints) {
+        if (npoints > xpoints.length || npoints > ypoints.length) {
+            // awt.111=Parameter npoints is greater than array length
+            throw new IndexOutOfBoundsException(Messages.getString("awt.111")); //$NON-NLS-1$
+        }
+        if (npoints < 0) {
+            // awt.112=Negative number of points
+            throw new NegativeArraySizeException(Messages.getString("awt.112")); //$NON-NLS-1$
+        }
+        this.npoints = npoints;
+        this.xpoints = new int[npoints];
+        this.ypoints = new int[npoints];
+        System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
+        System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);
+    }
+
+    /**
+     * Resets the current Polygon to an empty Polygon. More precisely, the
+     * number of Polygon vertices is set to zero, but x, y coordinates arrays
+     * are not affected.
+     */
+    public void reset() {
+        npoints = 0;
+        bounds = null;
+    }
+
+    /**
+     * Invalidates the data that depends on the vertex coordinates. This method
+     * should be called after direct manipulations of the x, y vertex
+     * coordinates arrays to avoid unpredictable results of methods which rely
+     * on the bounding box.
+     */
+    public void invalidate() {
+        bounds = null;
+    }
+
+    /**
+     * Adds the point to the Polygon and updates the bounding box accordingly.
+     * 
+     * @param px
+     *            the X coordinate of the added vertex.
+     * @param py
+     *            the Y coordinate of the added vertex.
+     */
+    public void addPoint(int px, int py) {
+        if (npoints == xpoints.length) {
+            int[] tmp;
+
+            tmp = new int[xpoints.length + BUFFER_CAPACITY];
+            System.arraycopy(xpoints, 0, tmp, 0, xpoints.length);
+            xpoints = tmp;
+
+            tmp = new int[ypoints.length + BUFFER_CAPACITY];
+            System.arraycopy(ypoints, 0, tmp, 0, ypoints.length);
+            ypoints = tmp;
+        }
+
+        xpoints[npoints] = px;
+        ypoints[npoints] = py;
+        npoints++;
+
+        if (bounds != null) {
+            bounds.setFrameFromDiagonal(Math.min(bounds.getMinX(), px), Math.min(bounds.getMinY(),
+                    py), Math.max(bounds.getMaxX(), px), Math.max(bounds.getMaxY(), py));
+        }
+    }
+
+    /**
+     * Gets the bounding rectangle of the Polygon. The bounding rectangle is the
+     * smallest rectangle which contains the Polygon.
+     * 
+     * @return the bounding rectangle of the Polygon.
+     * @see java.awt.Shape#getBounds()
+     */
+    public Rectangle getBounds() {
+        if (bounds != null) {
+            return bounds;
+        }
+        if (npoints == 0) {
+            return new Rectangle();
+        }
+
+        int bx1 = xpoints[0];
+        int by1 = ypoints[0];
+        int bx2 = bx1;
+        int by2 = by1;
+
+        for (int i = 1; i < npoints; i++) {
+            int x = xpoints[i];
+            int y = ypoints[i];
+            if (x < bx1) {
+                bx1 = x;
+            } else if (x > bx2) {
+                bx2 = x;
+            }
+            if (y < by1) {
+                by1 = y;
+            } else if (y > by2) {
+                by2 = y;
+            }
+        }
+
+        return bounds = new Rectangle(bx1, by1, bx2 - bx1, by2 - by1);
+    }
+
+    /**
+     * Gets the bounding rectangle of the Polygon. The bounding rectangle is the
+     * smallest rectangle which contains the Polygon.
+     * 
+     * @return the bounding rectangle of the Polygon.
+     * @deprecated Use getBounds() method.
+     */
+    @Deprecated
+    public Rectangle getBoundingBox() {
+        return getBounds();
+    }
+
+    /**
+     * Gets the Rectangle2D which represents Polygon bounds. The bounding
+     * rectangle is the smallest rectangle which contains the Polygon.
+     * 
+     * @return the bounding rectangle of the Polygon.
+     * @see java.awt.Shape#getBounds2D()
+     */
+    public Rectangle2D getBounds2D() {
+        return getBounds().getBounds2D();
+    }
+
+    /**
+     * Translates all vertices of Polygon the specified distances along X, Y
+     * axis.
+     * 
+     * @param mx
+     *            the distance to translate horizontally.
+     * @param my
+     *            the distance to translate vertically.
+     */
+    public void translate(int mx, int my) {
+        for (int i = 0; i < npoints; i++) {
+            xpoints[i] += mx;
+            ypoints[i] += my;
+        }
+        if (bounds != null) {
+            bounds.translate(mx, my);
+        }
+    }
+
+    /**
+     * Checks whether or not the point given by the coordinates x, y lies inside
+     * the Polygon.
+     * 
+     * @param x
+     *            the X coordinate of the point to check.
+     * @param y
+     *            the Y coordinate of the point to check.
+     * @return true, if the specified point lies inside the Polygon, false
+     *         otherwise.
+     * @deprecated Use contains(int, int) method.
+     */
+    @Deprecated
+    public boolean inside(int x, int y) {
+        return contains((double)x, (double)y);
+    }
+
+    /**
+     * Checks whether or not the point given by the coordinates x, y lies inside
+     * the Polygon.
+     * 
+     * @param x
+     *            the X coordinate of the point to check.
+     * @param y
+     *            the Y coordinate of the point to check.
+     * @return true, if the specified point lies inside the Polygon, false
+     *         otherwise.
+     */
+    public boolean contains(int x, int y) {
+        return contains((double)x, (double)y);
+    }
+
+    /**
+     * Checks whether or not the point with specified double coordinates lies
+     * inside the Polygon.
+     * 
+     * @param x
+     *            the X coordinate of the point to check.
+     * @param y
+     *            the Y coordinate of the point to check.
+     * @return true, if the point given by the double coordinates lies inside
+     *         the Polygon, false otherwise.
+     * @see java.awt.Shape#contains(double, double)
+     */
+    public boolean contains(double x, double y) {
+        return Crossing.isInsideEvenOdd(Crossing.crossShape(this, x, y));
+    }
+
+    /**
+     * Checks whether or not the rectangle determined by the parameters [x, y,
+     * width, height] lies inside the Polygon.
+     * 
+     * @param x
+     *            the X coordinate of the rectangles's left upper corner as a
+     *            double.
+     * @param y
+     *            the Y coordinate of the rectangles's left upper corner as a
+     *            double.
+     * @param width
+     *            the width of rectangle as a double.
+     * @param height
+     *            the height of rectangle as a double.
+     * @return true, if the specified rectangle lies inside the Polygon, false
+     *         otherwise.
+     * @see java.awt.Shape#contains(double, double, double, double)
+     */
+    public boolean contains(double x, double y, double width, double height) {
+        int cross = Crossing.intersectShape(this, x, y, width, height);
+        return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross);
+    }
+
+    /**
+     * Checks whether or not the rectangle determined by the parameters [x, y,
+     * width, height] intersects the interior of the Polygon.
+     * 
+     * @param x
+     *            the X coordinate of the rectangles's left upper corner as a
+     *            double.
+     * @param y
+     *            the Y coordinate of the rectangles's left upper corner as a
+     *            double.
+     * @param width
+     *            the width of rectangle as a double.
+     * @param height
+     *            the height of rectangle as a double.
+     * @return true, if the specified rectangle intersects the interior of the
+     *         Polygon, false otherwise.
+     * @see java.awt.Shape#intersects(double, double, double, double)
+     */
+    public boolean intersects(double x, double y, double width, double height) {
+        int cross = Crossing.intersectShape(this, x, y, width, height);
+        return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross);
+    }
+
+    /**
+     * Checks whether or not the specified rectangle lies inside the Polygon.
+     * 
+     * @param rect
+     *            the Rectangle2D object.
+     * @return true, if the specified rectangle lies inside the Polygon, false
+     *         otherwise.
+     * @see java.awt.Shape#contains(java.awt.geom.Rectangle2D)
+     */
+    public boolean contains(Rectangle2D rect) {
+        return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+    }
+
+    /**
+     * Checks whether or not the specified Point lies inside the Polygon.
+     * 
+     * @param point
+     *            the Point object.
+     * @return true, if the specified Point lies inside the Polygon, false
+     *         otherwise.
+     */
+    public boolean contains(Point point) {
+        return contains(point.getX(), point.getY());
+    }
+
+    /**
+     * Checks whether or not the specified Point2D lies inside the Polygon.
+     * 
+     * @param point
+     *            the Point2D object.
+     * @return true, if the specified Point2D lies inside the Polygon, false
+     *         otherwise.
+     * @see java.awt.Shape#contains(java.awt.geom.Point2D)
+     */
+    public boolean contains(Point2D point) {
+        return contains(point.getX(), point.getY());
+    }
+
+    /**
+     * Checks whether or not the interior of rectangle specified by the
+     * Rectangle2D object intersects the interior of the Polygon.
+     * 
+     * @param rect
+     *            the Rectangle2D object.
+     * @return true, if the Rectangle2D intersects the interior of the Polygon,
+     *         false otherwise.
+     * @see java.awt.Shape#intersects(java.awt.geom.Rectangle2D)
+     */
+    public boolean intersects(Rectangle2D rect) {
+        return intersects(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+    }
+
+    /**
+     * Gets the PathIterator object which gives the coordinates of the polygon,
+     * transformed according to the specified AffineTransform.
+     * 
+     * @param t
+     *            the specified AffineTransform object or null.
+     * @return PathIterator object for the Polygon.
+     * @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform)
+     */
+    public PathIterator getPathIterator(AffineTransform t) {
+        return new Iterator(t, this);
+    }
+
+    /**
+     * Gets the PathIterator object which gives the coordinates of the polygon,
+     * transformed according to the specified AffineTransform. The flatness
+     * parameter is ignored.
+     * 
+     * @param t
+     *            the specified AffineTransform object or null.
+     * @param flatness
+     *            the maximum number of the control points for a given curve
+     *            which varies from colinear before a subdivided curve is
+     *            replaced by a straight line connecting the endpoints. This
+     *            parameter is ignored for the Polygon class.
+     * @return PathIterator object for the Polygon.
+     * @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform,
+     *      double)
+     */
+    public PathIterator getPathIterator(AffineTransform t, double flatness) {
+        return new Iterator(t, this);
+    }
+
+}
diff --git a/awt/java/awt/Rectangle.java b/awt/java/awt/Rectangle.java
new file mode 100644
index 0000000..d8ebb3a
--- /dev/null
+++ b/awt/java/awt/Rectangle.java
@@ -0,0 +1,723 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.geom.Rectangle2D;
+import java.io.Serializable;
+
+/**
+ * The Rectangle class defines the rectangular area in terms of its upper left
+ * corner coordinates [x,y], its width, and its height. A Rectangle specified by
+ * [x, y, width, height] parameters has an outline path with corners at [x, y],
+ * [x + width,y], [x + width,y + height], and [x, y + height]. <br>
+ * <br>
+ * The rectangle is empty if the width or height is negative or zero. In this
+ * case the isEmpty method returns true.
+ * 
+ * @since Android 1.0
+ */
+public class Rectangle extends Rectangle2D implements Shape, Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -4345857070255674764L;
+
+    /**
+     * The X coordinate of the rectangle's left upper corner.
+     */
+    public int x;
+
+    /**
+     * The Y coordinate of the rectangle's left upper corner.
+     */
+    public int y;
+
+    /**
+     * The width of rectangle.
+     */
+    public int width;
+
+    /**
+     * The height of rectangle.
+     */
+    public int height;
+
+    /**
+     * Instantiates a new rectangle with [0, 0] upper left corner coordinates,
+     * the width and the height are zero.
+     */
+    public Rectangle() {
+        setBounds(0, 0, 0, 0);
+    }
+
+    /**
+     * Instantiates a new rectangle whose upper left corner coordinates are
+     * given by the Point object (p.X and p.Y), and the width and the height are
+     * zero.
+     * 
+     * @param p
+     *            the Point specifies the upper left corner coordinates of the
+     *            rectangle.
+     */
+    public Rectangle(Point p) {
+        setBounds(p.x, p.y, 0, 0);
+    }
+
+    /**
+     * Instantiates a new rectangle whose upper left corner coordinates are
+     * given by the Point object (p.X and p.Y), and the width and the height are
+     * given by Dimension object (d.width and d.height).
+     * 
+     * @param p
+     *            the point specifies the upper left corner coordinates of the
+     *            rectangle.
+     * @param d
+     *            the dimension specifies the width and the height of the
+     *            rectangle.
+     */
+    public Rectangle(Point p, Dimension d) {
+        setBounds(p.x, p.y, d.width, d.height);
+    }
+
+    /**
+     * Instantiates a new rectangle determined by the upper left corner
+     * coordinates (x, y), width and height.
+     * 
+     * @param x
+     *            the X upper left corner coordinate of the rectangle.
+     * @param y
+     *            the Y upper left corner coordinate of the rectangle.
+     * @param width
+     *            the width of rectangle.
+     * @param height
+     *            the height of rectangle.
+     */
+    public Rectangle(int x, int y, int width, int height) {
+        setBounds(x, y, width, height);
+    }
+
+    /**
+     * Instantiates a new rectangle with [0, 0] as its upper left corner
+     * coordinates and the specified width and height.
+     * 
+     * @param width
+     *            the width of rectangle.
+     * @param height
+     *            the height of rectangle.
+     */
+    public Rectangle(int width, int height) {
+        setBounds(0, 0, width, height);
+    }
+
+    /**
+     * Instantiates a new rectangle with the same coordinates as the given
+     * source rectangle.
+     * 
+     * @param r
+     *            the Rectangle object which parameters will be used for
+     *            instantiating a new Rectangle.
+     */
+    public Rectangle(Rectangle r) {
+        setBounds(r.x, r.y, r.width, r.height);
+    }
+
+    /*
+     * public Rectangle(Dimension d) { setBounds(0, 0, d.width, d.height); }
+     */
+    /**
+     * Gets the X coordinate of bound as a double.
+     * 
+     * @return the X coordinate of bound as a double.
+     * @see java.awt.geom.RectangularShape#getX()
+     */
+    @Override
+    public double getX() {
+        return x;
+    }
+
+    /**
+     * Gets the Y coordinate of bound as a double.
+     * 
+     * @return the Y coordinate of bound as a double.
+     * @see java.awt.geom.RectangularShape#getY()
+     */
+    @Override
+    public double getY() {
+        return y;
+    }
+
+    /**
+     * Gets the height of the rectangle as a double.
+     * 
+     * @return the height of the rectangle as a double.
+     * @see java.awt.geom.RectangularShape#getHeight()
+     */
+    @Override
+    public double getHeight() {
+        return height;
+    }
+
+    /**
+     * Gets the width of the rectangle as a double.
+     * 
+     * @return the width of the rectangle as a double.
+     * @see java.awt.geom.RectangularShape#getWidth()
+     */
+    @Override
+    public double getWidth() {
+        return width;
+    }
+
+    /**
+     * Determines whether or not the rectangle is empty. The rectangle is empty
+     * if its width or height is negative or zero.
+     * 
+     * @return true, if the rectangle is empty, otherwise false.
+     * @see java.awt.geom.RectangularShape#isEmpty()
+     */
+    @Override
+    public boolean isEmpty() {
+        return width <= 0 || height <= 0;
+    }
+
+    /**
+     * Gets the size of a Rectangle as Dimension object.
+     * 
+     * @return a Dimension object which represents size of the rectangle.
+     */
+    public Dimension getSize() {
+        return new Dimension(width, height);
+    }
+
+    /**
+     * Sets the size of the Rectangle.
+     * 
+     * @param width
+     *            the new width of the rectangle.
+     * @param height
+     *            the new height of the rectangle.
+     */
+    public void setSize(int width, int height) {
+        this.width = width;
+        this.height = height;
+    }
+
+    /**
+     * Sets the size of a Rectangle specified as Dimension object.
+     * 
+     * @param d
+     *            a Dimension object which represents new size of a rectangle.
+     */
+    public void setSize(Dimension d) {
+        setSize(d.width, d.height);
+    }
+
+    /**
+     * Gets the location of a rectangle's upper left corner as a Point object.
+     * 
+     * @return the Point object with coordinates equal to the upper left corner
+     *         of the rectangle.
+     */
+    public Point getLocation() {
+        return new Point(x, y);
+    }
+
+    /**
+     * Sets the location of the rectangle in terms of its upper left corner
+     * coordinates X and Y.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle's upper left corner.
+     * @param y
+     *            the Y coordinate of the rectangle's upper left corner.
+     */
+    public void setLocation(int x, int y) {
+        this.x = x;
+        this.y = y;
+    }
+
+    /**
+     * Sets the location of a rectangle using a Point object to give the
+     * coordinates of the upper left corner.
+     * 
+     * @param p
+     *            the Point object which represents the new upper left corner
+     *            coordinates of rectangle.
+     */
+    public void setLocation(Point p) {
+        setLocation(p.x, p.y);
+    }
+
+    /**
+     * Moves a rectangle to the new location by moving its upper left corner to
+     * the point with coordinates X and Y.
+     * 
+     * @param x
+     *            the new X coordinate of the rectangle's upper left corner.
+     * @param y
+     *            the new Y coordinate of the rectangle's upper left corner.
+     * @deprecated Use setLocation(int, int) method.
+     */
+    @Deprecated
+    public void move(int x, int y) {
+        setLocation(x, y);
+    }
+
+    /**
+     * Sets the rectangle to be the nearest rectangle with integer coordinates
+     * bounding the rectangle defined by the double-valued parameters.
+     * 
+     * @param x
+     *            the X coordinate of the upper left corner of the double-valued
+     *            rectangle to be bounded.
+     * @param y
+     *            the Y coordinate of the upper left corner of the double-valued
+     *            rectangle to be bounded.
+     * @param width
+     *            the width of the rectangle to be bounded.
+     * @param height
+     *            the height of the rectangle to be bounded.
+     * @see java.awt.geom.Rectangle2D#setRect(double, double, double, double)
+     */
+    @Override
+    public void setRect(double x, double y, double width, double height) {
+        int x1 = (int)Math.floor(x);
+        int y1 = (int)Math.floor(y);
+        int x2 = (int)Math.ceil(x + width);
+        int y2 = (int)Math.ceil(y + height);
+        setBounds(x1, y1, x2 - x1, y2 - y1);
+    }
+
+    /**
+     * Sets a new size for the rectangle.
+     * 
+     * @param width
+     *            the rectangle's new width.
+     * @param height
+     *            the rectangle's new height.
+     * @deprecated use the setSize(int, int) method.
+     */
+    @Deprecated
+    public void resize(int width, int height) {
+        setBounds(x, y, width, height);
+    }
+
+    /**
+     * Resets the bounds of a rectangle to the specified x, y, width and height
+     * parameters.
+     * 
+     * @param x
+     *            the new X coordinate of the upper left corner.
+     * @param y
+     *            the new Y coordinate of the upper left corner.
+     * @param width
+     *            the new width of rectangle.
+     * @param height
+     *            the new height of rectangle.
+     * @deprecated use setBounds(int, int, int, int) method
+     */
+    @Deprecated
+    public void reshape(int x, int y, int width, int height) {
+        setBounds(x, y, width, height);
+    }
+
+    /**
+     * Gets bounds of the rectangle as a new Rectangle object.
+     * 
+     * @return the Rectangle object with the same bounds as the original
+     *         rectangle.
+     * @see java.awt.geom.RectangularShape#getBounds()
+     */
+    @Override
+    public Rectangle getBounds() {
+        return new Rectangle(x, y, width, height);
+    }
+
+    /**
+     * Gets the bounds of the original rectangle as a Rectangle2D object.
+     * 
+     * @return the Rectangle2D object which represents the bounds of the
+     *         original rectangle.
+     * @see java.awt.geom.Rectangle2D#getBounds2D()
+     */
+    @Override
+    public Rectangle2D getBounds2D() {
+        return getBounds();
+    }
+
+    /**
+     * Sets the bounds of a rectangle to the specified x, y, width, and height
+     * parameters.
+     * 
+     * @param x
+     *            the X coordinate of the upper left corner.
+     * @param y
+     *            the Y coordinate of the upper left corner.
+     * @param width
+     *            the width of rectangle.
+     * @param height
+     *            the height of rectangle.
+     */
+    public void setBounds(int x, int y, int width, int height) {
+        this.x = x;
+        this.y = y;
+        this.height = height;
+        this.width = width;
+    }
+
+    /**
+     * Sets the bounds of the rectangle to match the bounds of the Rectangle
+     * object sent as a parameter.
+     * 
+     * @param r
+     *            the Rectangle object which specifies the new bounds.
+     */
+    public void setBounds(Rectangle r) {
+        setBounds(r.x, r.y, r.width, r.height);
+    }
+
+    /**
+     * Enlarges the rectangle by moving each corner outward from the center by a
+     * distance of dx horizonally and a distance of dy vertically. Specifically,
+     * changes a rectangle with [x, y, width, height] parameters to a rectangle
+     * with [x-dx, y-dy, width+2*dx, height+2*dy] parameters.
+     * 
+     * @param dx
+     *            the horizontal distance to move each corner coordinate.
+     * @param dy
+     *            the vertical distance to move each corner coordinate.
+     */
+    public void grow(int dx, int dy) {
+        x -= dx;
+        y -= dy;
+        width += dx + dx;
+        height += dy + dy;
+    }
+
+    /**
+     * Moves a rectangle a distance of mx along the x coordinate axis and a
+     * distance of my along y coordinate axis.
+     * 
+     * @param mx
+     *            the horizontal translation increment.
+     * @param my
+     *            the vertical translation increment.
+     */
+    public void translate(int mx, int my) {
+        x += mx;
+        y += my;
+    }
+
+    /**
+     * Enlarges the rectangle to cover the specified point.
+     * 
+     * @param px
+     *            the X coordinate of the new point to be covered by the
+     *            rectangle.
+     * @param py
+     *            the Y coordinate of the new point to be covered by the
+     *            rectangle.
+     */
+    public void add(int px, int py) {
+        int x1 = Math.min(x, px);
+        int x2 = Math.max(x + width, px);
+        int y1 = Math.min(y, py);
+        int y2 = Math.max(y + height, py);
+        setBounds(x1, y1, x2 - x1, y2 - y1);
+    }
+
+    /**
+     * Enlarges the rectangle to cover the specified point with the new point
+     * given as a Point object.
+     * 
+     * @param p
+     *            the Point object that specifies the new point to be covered by
+     *            the rectangle.
+     */
+    public void add(Point p) {
+        add(p.x, p.y);
+    }
+
+    /**
+     * Adds a new rectangle to the original rectangle, the result is an union of
+     * the specified specified rectangle and original rectangle.
+     * 
+     * @param r
+     *            the Rectangle which is added to the original rectangle.
+     */
+    public void add(Rectangle r) {
+        int x1 = Math.min(x, r.x);
+        int x2 = Math.max(x + width, r.x + r.width);
+        int y1 = Math.min(y, r.y);
+        int y2 = Math.max(y + height, r.y + r.height);
+        setBounds(x1, y1, x2 - x1, y2 - y1);
+    }
+
+    /**
+     * Determines whether or not the point with specified coordinates [px, py]
+     * is within the bounds of the rectangle.
+     * 
+     * @param px
+     *            the X coordinate of point.
+     * @param py
+     *            the Y coordinate of point.
+     * @return true, if the point with specified coordinates [px, py] is within
+     *         the bounds of the rectangle, false otherwise.
+     */
+    public boolean contains(int px, int py) {
+        if (isEmpty()) {
+            return false;
+        }
+        if (px < x || py < y) {
+            return false;
+        }
+        px -= x;
+        py -= y;
+        return px < width && py < height;
+    }
+
+    /**
+     * Determines whether or not the point given as a Point object is within the
+     * bounds of the rectangle.
+     * 
+     * @param p
+     *            the Point object
+     * @return true, if the point p is within the bounds of the rectangle,
+     *         otherwise false.
+     */
+    public boolean contains(Point p) {
+        return contains(p.x, p.y);
+    }
+
+    /**
+     * Determines whether or not the rectangle specified by [rx, ry, rw, rh]
+     * parameters is located inside the original rectangle.
+     * 
+     * @param rx
+     *            the X coordinate of the rectangle to compare.
+     * @param ry
+     *            the Y coordinate of the rectangle to compare.
+     * @param rw
+     *            the width of the rectangle to compare.
+     * @param rh
+     *            the height of the rectangle to compare.
+     * @return true, if a rectangle with [rx, ry, rw, rh] parameters is entirely
+     *         contained in the original rectangle, false otherwise.
+     */
+    public boolean contains(int rx, int ry, int rw, int rh) {
+        return contains(rx, ry) && contains(rx + rw - 1, ry + rh - 1);
+    }
+
+    /**
+     * Compares whether or not the rectangle specified by the Rectangle object
+     * is located inside the original rectangle.
+     * 
+     * @param r
+     *            the Rectangle object.
+     * @return true, if the rectangle specified by Rectangle object is entirely
+     *         contained in the original rectangle, false otherwise.
+     */
+    public boolean contains(Rectangle r) {
+        return contains(r.x, r.y, r.width, r.height);
+    }
+
+    /**
+     * Compares whether or not a point with specified coordinates [px, py]
+     * belongs to a rectangle.
+     * 
+     * @param px
+     *            the X coordinate of a point.
+     * @param py
+     *            the Y coordinate of a point.
+     * @return true, if a point with specified coordinates [px, py] belongs to a
+     *         rectangle, otherwise false.
+     * @deprecated use contains(int, int) method.
+     */
+    @Deprecated
+    public boolean inside(int px, int py) {
+        return contains(px, py);
+    }
+
+    /**
+     * Returns the intersection of the original rectangle with the specified
+     * Rectangle2D.
+     * 
+     * @param r
+     *            the Rectangle2D object.
+     * @return the Rectangle2D object that is the result of intersecting the
+     *         original rectangle with the specified Rectangle2D.
+     * @see java.awt.geom.Rectangle2D#createIntersection(java.awt.geom.Rectangle2D)
+     */
+    @Override
+    public Rectangle2D createIntersection(Rectangle2D r) {
+        if (r instanceof Rectangle) {
+            return intersection((Rectangle)r);
+        }
+        Rectangle2D dst = new Rectangle2D.Double();
+        Rectangle2D.intersect(this, r, dst);
+        return dst;
+    }
+
+    /**
+     * Returns the intersection of the original rectangle with the specified
+     * rectangle. An empty rectangle is returned if there is no intersection.
+     * 
+     * @param r
+     *            the Rectangle object.
+     * @return the Rectangle object is result of the original rectangle with the
+     *         specified rectangle.
+     */
+    public Rectangle intersection(Rectangle r) {
+        int x1 = Math.max(x, r.x);
+        int y1 = Math.max(y, r.y);
+        int x2 = Math.min(x + width, r.x + r.width);
+        int y2 = Math.min(y + height, r.y + r.height);
+        return new Rectangle(x1, y1, x2 - x1, y2 - y1);
+    }
+
+    /**
+     * Determines whether or not the original rectangle intersects the specified
+     * rectangle.
+     * 
+     * @param r
+     *            the Rectangle object.
+     * @return true, if the two rectangles overlap, false otherwise.
+     */
+    public boolean intersects(Rectangle r) {
+        return !intersection(r).isEmpty();
+    }
+
+    /**
+     * Determines where the specified Point is located with respect to the
+     * rectangle. This method computes whether the point is to the right or to
+     * the left of the rectangle and whether it is above or below the rectangle,
+     * and packs the result into an integer by using a binary OR operation with
+     * the following masks:
+     * <ul>
+     *<li>Rectangle2D.OUT_LEFT</li>
+     *<li>Rectangle2D.OUT_TOP</li>
+     *<li>Rectangle2D.OUT_RIGHT</li>
+     *<li>Rectangle2D.OUT_BOTTOM</li>
+     *</ul>
+     * If the rectangle is empty, all masks are set, and if the point is inside
+     * the rectangle, none are set.
+     * 
+     * @param px
+     *            the X coordinate of the specified point.
+     * @param py
+     *            the Y coordinate of the specified point.
+     * @return the location of the Point relative to the rectangle as the result
+     *         of logical OR operation with all out masks.
+     * @see java.awt.geom.Rectangle2D#outcode(double, double)
+     */
+    @Override
+    public int outcode(double px, double py) {
+        int code = 0;
+
+        if (width <= 0) {
+            code |= OUT_LEFT | OUT_RIGHT;
+        } else if (px < x) {
+            code |= OUT_LEFT;
+        } else if (px > x + width) {
+            code |= OUT_RIGHT;
+        }
+
+        if (height <= 0) {
+            code |= OUT_TOP | OUT_BOTTOM;
+        } else if (py < y) {
+            code |= OUT_TOP;
+        } else if (py > y + height) {
+            code |= OUT_BOTTOM;
+        }
+
+        return code;
+    }
+
+    /**
+     * Enlarges the rectangle to cover the specified Rectangle2D.
+     * 
+     * @param r
+     *            the Rectangle2D object.
+     * @return the union of the original and the specified Rectangle2D.
+     * @see java.awt.geom.Rectangle2D#createUnion(java.awt.geom.Rectangle2D)
+     */
+    @Override
+    public Rectangle2D createUnion(Rectangle2D r) {
+        if (r instanceof Rectangle) {
+            return union((Rectangle)r);
+        }
+        Rectangle2D dst = new Rectangle2D.Double();
+        Rectangle2D.union(this, r, dst);
+        return dst;
+    }
+
+    /**
+     * Enlarges the rectangle to cover the specified rectangle.
+     * 
+     * @param r
+     *            the Rectangle.
+     * @return the union of the original and the specified rectangle.
+     */
+    public Rectangle union(Rectangle r) {
+        Rectangle dst = new Rectangle(this);
+        dst.add(r);
+        return dst;
+    }
+
+    /**
+     * Compares the original Rectangle with the specified object.
+     * 
+     * @param obj
+     *            the specified Object for comparison.
+     * @return true, if the specified Object is a rectangle with the same
+     *         dimensions as the original rectangle, false otherwise.
+     * @see java.awt.geom.Rectangle2D#equals(Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof Rectangle) {
+            Rectangle r = (Rectangle)obj;
+            return r.x == x && r.y == y && r.width == width && r.height == height;
+        }
+        return false;
+    }
+
+    /**
+     * Returns a string representation of the rectangle; the string contains [x,
+     * y, width, height] parameters of the rectangle.
+     * 
+     * @return the string representation of the rectangle.
+     */
+    @Override
+    public String toString() {
+        // The output format based on 1.5 release behaviour. It could be
+        // obtained in the following way
+        // System.out.println(new Rectangle().toString())
+        return getClass().getName() + "[x=" + x + ",y=" + y + //$NON-NLS-1$ //$NON-NLS-2$
+                ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+
+}
diff --git a/awt/java/awt/RenderingHints.java b/awt/java/awt/RenderingHints.java
new file mode 100644
index 0000000..acf6fa1
--- /dev/null
+++ b/awt/java/awt/RenderingHints.java
@@ -0,0 +1,606 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The RenderingHints class represents preferences for the rendering algorithms.
+ * The preferences are arbitrary and can be specified by Map objects or by
+ * key-value pairs.
+ * 
+ * @since Android 1.0
+ */
+public class RenderingHints implements Map<Object, Object>, Cloneable {
+
+    /**
+     * The Constant KEY_ALPHA_INTERPOLATION - alpha interpolation rendering hint
+     * key.
+     */
+    public static final Key KEY_ALPHA_INTERPOLATION = new KeyImpl(1);
+
+    /**
+     * The Constant VALUE_ALPHA_INTERPOLATION_DEFAULT - alpha interpolation
+     * rendering hint value.
+     */
+    public static final Object VALUE_ALPHA_INTERPOLATION_DEFAULT = new KeyValue(
+            KEY_ALPHA_INTERPOLATION);
+
+    /**
+     * The Constant VALUE_ALPHA_INTERPOLATION_SPEED - alpha interpolation
+     * rendering hint value.
+     */
+    public static final Object VALUE_ALPHA_INTERPOLATION_SPEED = new KeyValue(
+            KEY_ALPHA_INTERPOLATION);
+
+    /**
+     * The Constant VALUE_ALPHA_INTERPOLATION_QUALITY - alpha interpolation
+     * rendering hint value.
+     */
+    public static final Object VALUE_ALPHA_INTERPOLATION_QUALITY = new KeyValue(
+            KEY_ALPHA_INTERPOLATION);
+
+    /**
+     * The Constant KEY_ANTIALIASING - antialiasing rendering hint key.
+     */
+    public static final Key KEY_ANTIALIASING = new KeyImpl(2);
+
+    /**
+     * The Constant VALUE_ANTIALIAS_DEFAULT - antialiasing rendering hint value.
+     */
+    public static final Object VALUE_ANTIALIAS_DEFAULT = new KeyValue(KEY_ANTIALIASING);
+
+    /**
+     * The Constant VALUE_ANTIALIAS_ON - antialiasing rendering hint value.
+     */
+    public static final Object VALUE_ANTIALIAS_ON = new KeyValue(KEY_ANTIALIASING);
+
+    /**
+     * The Constant VALUE_ANTIALIAS_OFF - antialiasing rendering hint value.
+     */
+    public static final Object VALUE_ANTIALIAS_OFF = new KeyValue(KEY_ANTIALIASING);
+
+    /**
+     * The Constant KEY_COLOR_RENDERING - color rendering hint key.
+     */
+    public static final Key KEY_COLOR_RENDERING = new KeyImpl(3);
+
+    /**
+     * The Constant VALUE_COLOR_RENDER_DEFAULT - color rendering hint value.
+     */
+    public static final Object VALUE_COLOR_RENDER_DEFAULT = new KeyValue(KEY_COLOR_RENDERING);
+
+    /**
+     * The Constant VALUE_COLOR_RENDER_SPEED - color rendering hint value.
+     */
+    public static final Object VALUE_COLOR_RENDER_SPEED = new KeyValue(KEY_COLOR_RENDERING);
+
+    /**
+     * The Constant VALUE_COLOR_RENDER_QUALITY - color rendering hint value.
+     */
+    public static final Object VALUE_COLOR_RENDER_QUALITY = new KeyValue(KEY_COLOR_RENDERING);
+
+    /**
+     * The Constant KEY_DITHERING - dithering rendering hint key.
+     */
+    public static final Key KEY_DITHERING = new KeyImpl(4);
+
+    /**
+     * The Constant VALUE_DITHER_DEFAULT - dithering rendering hint value.
+     */
+    public static final Object VALUE_DITHER_DEFAULT = new KeyValue(KEY_DITHERING);
+
+    /**
+     * The Constant VALUE_DITHER_DISABLE - dithering rendering hint value.
+     */
+    public static final Object VALUE_DITHER_DISABLE = new KeyValue(KEY_DITHERING);
+
+    /**
+     * The Constant VALUE_DITHER_DISABLE - dithering rendering hint value.
+     */
+    public static final Object VALUE_DITHER_ENABLE = new KeyValue(KEY_DITHERING);
+
+    /**
+     * The Constant KEY_FRACTIONALMETRICS - fractional metrics rendering hint
+     * key.
+     */
+    public static final Key KEY_FRACTIONALMETRICS = new KeyImpl(5);
+
+    /**
+     * The Constant VALUE_FRACTIONALMETRICS_DEFAULT - fractional metrics
+     * rendering hint value.
+     */
+    public static final Object VALUE_FRACTIONALMETRICS_DEFAULT = new KeyValue(KEY_FRACTIONALMETRICS);
+
+    /**
+     * The Constant VALUE_FRACTIONALMETRICS_ON - fractional metrics rendering
+     * hint value.
+     */
+    public static final Object VALUE_FRACTIONALMETRICS_ON = new KeyValue(KEY_FRACTIONALMETRICS);
+
+    /**
+     * The Constant VALUE_FRACTIONALMETRICS_OFF - fractional metrics rendering
+     * hint value.
+     */
+    public static final Object VALUE_FRACTIONALMETRICS_OFF = new KeyValue(KEY_FRACTIONALMETRICS);
+
+    /**
+     * The Constant KEY_INTERPOLATION - interpolation rendering hint key.
+     */
+    public static final Key KEY_INTERPOLATION = new KeyImpl(6);
+
+    /**
+     * The Constant VALUE_INTERPOLATION_BICUBIC - interpolation rendering hint
+     * value.
+     */
+    public static final Object VALUE_INTERPOLATION_BICUBIC = new KeyValue(KEY_INTERPOLATION);
+
+    /**
+     * The Constant VALUE_INTERPOLATION_BILINEAR - interpolation rendering hint
+     * value.
+     */
+    public static final Object VALUE_INTERPOLATION_BILINEAR = new KeyValue(KEY_INTERPOLATION);
+
+    /**
+     * The Constant VALUE_INTERPOLATION_NEAREST_NEIGHBOR - interpolation
+     * rendering hint value.
+     */
+    public static final Object VALUE_INTERPOLATION_NEAREST_NEIGHBOR = new KeyValue(
+            KEY_INTERPOLATION);
+
+    /**
+     * The Constant KEY_RENDERING - rendering hint key.
+     */
+    public static final Key KEY_RENDERING = new KeyImpl(7);
+
+    /**
+     * The Constant VALUE_RENDER_DEFAULT - rendering hint value.
+     */
+    public static final Object VALUE_RENDER_DEFAULT = new KeyValue(KEY_RENDERING);
+
+    /**
+     * The Constant VALUE_RENDER_SPEED - rendering hint value.
+     */
+    public static final Object VALUE_RENDER_SPEED = new KeyValue(KEY_RENDERING);
+
+    /**
+     * The Constant VALUE_RENDER_QUALITY - rendering hint value.
+     */
+    public static final Object VALUE_RENDER_QUALITY = new KeyValue(KEY_RENDERING);
+
+    /**
+     * The Constant KEY_STROKE_CONTROL - stroke control hint key.
+     */
+    public static final Key KEY_STROKE_CONTROL = new KeyImpl(8);
+
+    /**
+     * The Constant VALUE_STROKE_DEFAULT - stroke hint value.
+     */
+    public static final Object VALUE_STROKE_DEFAULT = new KeyValue(KEY_STROKE_CONTROL);
+
+    /**
+     * The Constant VALUE_STROKE_NORMALIZE - stroke hint value.
+     */
+    public static final Object VALUE_STROKE_NORMALIZE = new KeyValue(KEY_STROKE_CONTROL);
+
+    /**
+     * The Constant VALUE_STROKE_PURE - stroke hint value.
+     */
+    public static final Object VALUE_STROKE_PURE = new KeyValue(KEY_STROKE_CONTROL);
+
+    /**
+     * The Constant KEY_TEXT_ANTIALIASING - text antialiasing hint key.
+     */
+    public static final Key KEY_TEXT_ANTIALIASING = new KeyImpl(9);
+
+    /**
+     * The Constant VALUE_TEXT_ANTIALIAS_DEFAULT - text antialiasing hint key.
+     */
+    public static final Object VALUE_TEXT_ANTIALIAS_DEFAULT = new KeyValue(KEY_TEXT_ANTIALIASING);
+
+    /**
+     * The Constant VALUE_TEXT_ANTIALIAS_ON - text antialiasing hint key.
+     */
+    public static final Object VALUE_TEXT_ANTIALIAS_ON = new KeyValue(KEY_TEXT_ANTIALIASING);
+
+    /**
+     * The Constant VALUE_TEXT_ANTIALIAS_OFF - text antialiasing hint key.
+     */
+    public static final Object VALUE_TEXT_ANTIALIAS_OFF = new KeyValue(KEY_TEXT_ANTIALIASING);
+
+    /** The map. */
+    private HashMap<Object, Object> map = new HashMap<Object, Object>();
+
+    /**
+     * Instantiates a new rendering hints object from specified Map object with
+     * defined key/value pairs or null for empty RenderingHints.
+     * 
+     * @param map
+     *            the Map object with defined key/value pairs or null for empty
+     *            RenderingHints.
+     */
+    public RenderingHints(Map<Key, ?> map) {
+        super();
+        if (map != null) {
+            putAll(map);
+        }
+    }
+
+    /**
+     * Instantiates a new rendering hints object with the specified key/value
+     * pair.
+     * 
+     * @param key
+     *            the key of hint property.
+     * @param value
+     *            the value of hint property.
+     */
+    public RenderingHints(Key key, Object value) {
+        super();
+        put(key, value);
+    }
+
+    /**
+     * Adds the properties represented by key/value pairs from the specified
+     * RenderingHints object to current object.
+     * 
+     * @param hints
+     *            the RenderingHints to be added.
+     */
+    public void add(RenderingHints hints) {
+        map.putAll(hints.map);
+    }
+
+    /**
+     * Puts the specified value to the specified key. Neither the key nor the
+     * value can be null.
+     * 
+     * @param key
+     *            the rendering hint key.
+     * @param value
+     *            the rendering hint value.
+     * @return the previous rendering hint value assigned to the key or null.
+     */
+    public Object put(Object key, Object value) {
+        if (!((Key)key).isCompatibleValue(value)) {
+            throw new IllegalArgumentException();
+        }
+
+        return map.put(key, value);
+    }
+
+    /**
+     * Removes the specified key and corresponding value from the RenderingHints
+     * object.
+     * 
+     * @param key
+     *            the specified hint key to be removed.
+     * @return the object of previous rendering hint value which is assigned to
+     *         the specified key, or null.
+     */
+    public Object remove(Object key) {
+        return map.remove(key);
+    }
+
+    /**
+     * Gets the value assigned to the specified key.
+     * 
+     * @param key
+     *            the rendering hint key.
+     * @return the object assigned to the specified key.
+     */
+    public Object get(Object key) {
+        return map.get(key);
+    }
+
+    /**
+     * Returns a set of rendering hints keys for current RenderingHints object.
+     * 
+     * @return the set of rendering hints keys.
+     */
+    public Set<Object> keySet() {
+        return map.keySet();
+    }
+
+    /**
+     * Returns a set of Map.Entry objects which contain current RenderingHint
+     * key/value pairs.
+     * 
+     * @return the a set of mapped RenderingHint key/value pairs.
+     */
+    public Set<Map.Entry<Object, Object>> entrySet() {
+        return map.entrySet();
+    }
+
+    /**
+     * Puts all of the preferences from the specified Map into the current
+     * RenderingHints object. These mappings replace all existing preferences.
+     * 
+     * @param m
+     *            the specified Map of preferences.
+     */
+    public void putAll(Map<?, ?> m) {
+        if (m instanceof RenderingHints) {
+            map.putAll(((RenderingHints)m).map);
+        } else {
+            Set<?> entries = m.entrySet();
+
+            if (entries != null) {
+                Iterator<?> it = entries.iterator();
+                while (it.hasNext()) {
+                    Map.Entry<?, ?> entry = (Map.Entry<?, ?>)it.next();
+                    Key key = (Key)entry.getKey();
+                    Object val = entry.getValue();
+                    put(key, val);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a Collection of values contained in current RenderingHints
+     * object.
+     * 
+     * @return the Collection of RenderingHints's values.
+     */
+    public Collection<Object> values() {
+        return map.values();
+    }
+
+    /**
+     * Checks whether or not current RenderingHints object contains at least one
+     * the value which is equal to the specified Object.
+     * 
+     * @param value
+     *            the specified Object.
+     * @return true, if the specified object is assigned to at least one
+     *         RenderingHint's key, false otherwise.
+     */
+    public boolean containsValue(Object value) {
+        return map.containsValue(value);
+    }
+
+    /**
+     * Checks whether or not current RenderingHints object contains the key
+     * which is equal to the specified Object.
+     * 
+     * @param key
+     *            the specified Object.
+     * @return true, if the RenderingHints object contains the specified Object
+     *         as a key, false otherwise.
+     */
+    public boolean containsKey(Object key) {
+        if (key == null) {
+            throw new NullPointerException();
+        }
+
+        return map.containsKey(key);
+    }
+
+    /**
+     * Checks whether or not the RenderingHints object contains any key/value
+     * pairs.
+     * 
+     * @return true, if the RenderingHints object is empty, false otherwise.
+     */
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    /**
+     * Clears the RenderingHints of all key/value pairs.
+     */
+    public void clear() {
+        map.clear();
+    }
+
+    /**
+     * Returns the number of key/value pairs in the RenderingHints.
+     * 
+     * @return the number of key/value pairs.
+     */
+    public int size() {
+        return map.size();
+    }
+
+    /**
+     * Compares the RenderingHints object with the specified object.
+     * 
+     * @param o
+     *            the specified Object to be compared.
+     * @return true, if the Object is a Map whose key/value pairs match this
+     *         RenderingHints' key/value pairs, false otherwise.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof Map)) {
+            return false;
+        }
+
+        Map<?, ?> m = (Map<?, ?>)o;
+        Set<?> keys = keySet();
+        if (!keys.equals(m.keySet())) {
+            return false;
+        }
+
+        Iterator<?> it = keys.iterator();
+        while (it.hasNext()) {
+            Key key = (Key)it.next();
+            Object v1 = get(key);
+            Object v2 = m.get(key);
+            if (!(v1 == null ? v2 == null : v1.equals(v2))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns the hash code for this RenderingHints object.
+     * 
+     * @return the hash code for this RenderingHints object.
+     */
+    @Override
+    public int hashCode() {
+        return map.hashCode();
+    }
+
+    /**
+     * Returns the clone of the RenderingHints object with the same contents.
+     * 
+     * @return the clone of the RenderingHints instance.
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public Object clone() {
+        RenderingHints clone = new RenderingHints(null);
+        clone.map = (HashMap<Object, Object>)this.map.clone();
+        return clone;
+    }
+
+    /**
+     * Returns the string representation of the RenderingHints object.
+     * 
+     * @return the String object which represents RenderingHints object.
+     */
+    @Override
+    public String toString() {
+        return "RenderingHints[" + map.toString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+    /**
+     * The RenderingHints.Key class is abstract and defines a base type for all
+     * RenderingHints keys.
+     * 
+     * @since Android 1.0
+     */
+    public abstract static class Key {
+
+        /** The key. */
+        private final int key;
+
+        /**
+         * Instantiates a new key with unique integer identifier. No two objects
+         * of the same subclass with the same integer key can be instantiated.
+         * 
+         * @param key
+         *            the unique key.
+         */
+        protected Key(int key) {
+            this.key = key;
+        }
+
+        /**
+         * Compares the Key object with the specified object.
+         * 
+         * @param o
+         *            the specified Object to be compared.
+         * @return true, if the Key is equal to the specified object, false
+         *         otherwise.
+         */
+        @Override
+        public final boolean equals(Object o) {
+            return this == o;
+        }
+
+        /**
+         * Returns the hash code for this Key object.
+         * 
+         * @return the hash code for this Key object.
+         */
+        @Override
+        public final int hashCode() {
+            return System.identityHashCode(this);
+        }
+
+        /**
+         * Returns integer unique key with which this Key object has been
+         * instantiated.
+         * 
+         * @return the integer unique key with which this Key object has been
+         *         instantiated.
+         */
+        protected final int intKey() {
+            return key;
+        }
+
+        /**
+         * Checks whether or not specified value is compatible with the Key.
+         * 
+         * @param val
+         *            the Object.
+         * @return true, if the specified value is compatible with the Key,
+         *         false otherwise.
+         */
+        public abstract boolean isCompatibleValue(Object val);
+    }
+
+    /**
+     * Private implementation of Key class.
+     */
+    private static class KeyImpl extends Key {
+
+        /**
+         * Instantiates a new key implementation.
+         * 
+         * @param key
+         *            the key.
+         */
+        protected KeyImpl(int key) {
+            super(key);
+        }
+
+        @Override
+        public boolean isCompatibleValue(Object val) {
+            if (!(val instanceof KeyValue)) {
+                return false;
+            }
+
+            return ((KeyValue)val).key == this;
+        }
+    }
+
+    /**
+     * Private class KeyValue is used as value for Key class instance.
+     */
+    private static class KeyValue {
+
+        /**
+         * The key.
+         */
+        private final Key key;
+
+        /**
+         * Instantiates a new key value.
+         * 
+         * @param key
+         *            the key.
+         */
+        protected KeyValue(Key key) {
+            this.key = key;
+        }
+    }
+}
diff --git a/awt/java/awt/Shape.java b/awt/java/awt/Shape.java
new file mode 100644
index 0000000..59bc623
--- /dev/null
+++ b/awt/java/awt/Shape.java
@@ -0,0 +1,162 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The Shape interface defines a geometric shape defined by a boundary (outline)
+ * path. The path outline can be accessed through a PathIterator object. The
+ * Shape interface provides methods for obtaining the bounding box (which is the
+ * smallest rectangle containing the shape and for obtaining a PathIterator
+ * object for current Shape, as well as utility methods which determine if the
+ * Shape contains or intersects a Rectangle or contains a Point.
+ * 
+ * @since Android 1.0
+ */
+public interface Shape {
+
+    /**
+     * Checks whether or not the point with specified coordinates lies inside
+     * the Shape.
+     * 
+     * @param x
+     *            the X coordinate.
+     * @param y
+     *            the Y coordinate.
+     * @return true, if the specified coordinates lie inside the Shape, false
+     *         otherwise.
+     */
+    public boolean contains(double x, double y);
+
+    /**
+     * Checks whether or not the rectangle with specified [x, y, width, height]
+     * parameters lies inside the Shape.
+     * 
+     * @param x
+     *            the X double coordinate of the rectangle's upper left corner.
+     * @param y
+     *            the Y double coordinate of the rectangle's upper left corner.
+     * @param w
+     *            the width of rectangle.
+     * @param h
+     *            the height of rectangle.
+     * @return true, if the specified rectangle lies inside the Shape, false
+     *         otherwise.
+     */
+    public boolean contains(double x, double y, double w, double h);
+
+    /**
+     * Checks whether or not the specified Point2D lies inside the Shape.
+     * 
+     * @param point
+     *            the Point2D object.
+     * @return true, if the specified Point2D lies inside the Shape, false
+     *         otherwise.
+     */
+    public boolean contains(Point2D point);
+
+    /**
+     * Checks whether or not the specified rectangle lies inside the Shape.
+     * 
+     * @param r
+     *            the Rectangle2D object.
+     * @return true, if the specified rectangle lies inside the Shape, false
+     *         otherwise.
+     */
+    public boolean contains(Rectangle2D r);
+
+    /**
+     * Gets the bounding rectangle of the Shape. The bounding rectangle is the
+     * smallest rectangle which contains the Shape.
+     * 
+     * @return the bounding rectangle of the Shape.
+     */
+    public Rectangle getBounds();
+
+    /**
+     * Gets the Rectangle2D which represents Shape bounds. The bounding
+     * rectangle is the smallest rectangle which contains the Shape.
+     * 
+     * @return the bounding rectangle of the Shape.
+     */
+    public Rectangle2D getBounds2D();
+
+    /**
+     * Gets the PathIterator object of the Shape which provides access to the
+     * shape's boundary modified by the specified AffineTransform.
+     * 
+     * @param at
+     *            the specified AffineTransform object or null.
+     * @return PathIterator object for the Shape.
+     */
+    public PathIterator getPathIterator(AffineTransform at);
+
+    /**
+     * Gets the PathIterator object of the Shape which provides access to the
+     * coordinates of the shapes boundary modified by the specified
+     * AffineTransform. The flatness parameter defines the amount of subdivision
+     * of the curved segments and specifies the maximum distance which every
+     * point on the unflattened transformed curve can deviate from the returned
+     * flattened path segments.
+     * 
+     * @param at
+     *            the specified AffineTransform object or null.
+     * @param flatness
+     *            the maximum number of the control points for a given curve
+     *            which varies from colinear before a subdivided curve is
+     *            replaced by a straight line connecting the endpoints.
+     * @return PathIterator object for the Shape.
+     */
+    public PathIterator getPathIterator(AffineTransform at, double flatness);
+
+    /**
+     * Checks whether or not the interior of rectangular specified by [x, y,
+     * width, height] parameters intersects the interior of the Shape.
+     * 
+     * @param x
+     *            the X double coordinate of the rectangle's upper left corner.
+     * @param y
+     *            the Y double coordinate of the rectangle's upper left corner.
+     * @param w
+     *            the width of rectangle.
+     * @param h
+     *            the height of rectangle.
+     * @return true, if the rectangle specified by [x, y, width, height]
+     *         parameters intersects the interior of the Shape, false otherwise.
+     */
+    public boolean intersects(double x, double y, double w, double h);
+
+    /**
+     * Checks whether or not the interior of rectangle specified by Rectangle2D
+     * object intersects the interior of the Shape.
+     * 
+     * @param r
+     *            the Rectangle2D object.
+     * @return true, if the Rectangle2D intersects the interior of the Shape,
+     *         otherwise false.
+     */
+    public boolean intersects(Rectangle2D r);
+}
diff --git a/awt/java/awt/Stroke.java b/awt/java/awt/Stroke.java
new file mode 100644
index 0000000..6d17a23
--- /dev/null
+++ b/awt/java/awt/Stroke.java
@@ -0,0 +1,50 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt;
+
+/**
+ * The Stroke interface gives a pen style to be used by the Graphics2D
+ * interface. It provides a means for getting a stroked version of a shape,
+ * which is the version that is suitable for drawing via the Graphics2D
+ * interface. Stroking a shape gives the shape's outline a width or drawing
+ * style.
+ * <p>
+ * The Draw methods from Graphics2D interface should use the Stroke object for
+ * rendering the shape's outline. The stroke should be set by
+ * setStroke(java.awt.Stroke) method of the Graphics2D interface.
+ * 
+ * @see java.awt.Graphics2D#setStroke(java.awt.Stroke)
+ * @since Android 1.0
+ */
+public interface Stroke {
+
+    /**
+     * Creates the stroked shape, which is the version that is suitable for
+     * drawing via the Graphics2D interface. Stroking a shape gives the shape's
+     * outline a width or drawing style.
+     * 
+     * @param p
+     *            the original shape.
+     * @return the stroked shape.
+     */
+    public Shape createStrokedShape(Shape p);
+}
diff --git a/awt/java/awt/Toolkit.java b/awt/java/awt/Toolkit.java
new file mode 100644
index 0000000..e38d524
--- /dev/null
+++ b/awt/java/awt/Toolkit.java
@@ -0,0 +1,1444 @@
+/*
+ *  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.
+ */
+
+package java.awt;
+
+import java.awt.event.AWTEventListener;
+import java.awt.event.AWTEventListenerProxy;
+import java.awt.event.InputEvent;
+import java.awt.im.InputMethodHighlight;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.peer.FontPeer;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Properties;
+import java.util.ResourceBundle;
+
+import org.apache.harmony.awt.ChoiceStyle;
+import org.apache.harmony.awt.ComponentInternals;
+import org.apache.harmony.awt.ContextStorage;
+import org.apache.harmony.awt.ReadOnlyIterator;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.wtk.CreationParams;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+import org.apache.harmony.awt.wtk.NativeCursor;
+
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+import org.apache.harmony.awt.wtk.NativeEventThread;
+import org.apache.harmony.awt.wtk.ShutdownWatchdog;
+import org.apache.harmony.awt.wtk.Synchronizer;
+import org.apache.harmony.awt.wtk.WTK;
+import org.apache.harmony.luni.util.NotImplementedException;
+
+/**
+ * The Toolkit class is the representation of the platform-specific Abstract
+ * Window Toolkit implementation. Toolkit's subclasses are used to bind the
+ * various components to particular native toolkit implementations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class Toolkit {
+
+    /**
+     * The Constant RECOURCE_PATH.
+     */
+    private static final String RECOURCE_PATH = "org.apache.harmony.awt.resources.AWTProperties"; //$NON-NLS-1$
+
+    /**
+     * The Constant properties.
+     */
+    private static final ResourceBundle properties = loadResources(RECOURCE_PATH);
+
+    /**
+     * The dispatcher.
+     */
+    Dispatcher dispatcher;
+
+    /**
+     * The system event queue core.
+     */
+    private EventQueueCore systemEventQueueCore;
+
+    /**
+     * The dispatch thread.
+     */
+    EventDispatchThread dispatchThread;
+
+    /**
+     * The native thread.
+     */
+    NativeEventThread nativeThread;
+
+    /**
+     * The AWT events manager.
+     */
+    protected AWTEventsManager awtEventsManager;
+
+    /**
+     * The Class AWTTreeLock.
+     */
+    private class AWTTreeLock {
+    }
+
+    /**
+     * The AWT tree lock.
+     */
+    final Object awtTreeLock = new AWTTreeLock();
+
+    /**
+     * The synchronizer.
+     */
+    private final Synchronizer synchronizer = ContextStorage.getSynchronizer();
+
+    /**
+     * The shutdown watchdog.
+     */
+    final ShutdownWatchdog shutdownWatchdog = new ShutdownWatchdog();
+
+    /**
+     * The auto number.
+     */
+    final AutoNumber autoNumber = new AutoNumber();
+
+    /**
+     * The event type lookup.
+     */
+    final AWTEvent.EventTypeLookup eventTypeLookup = new AWTEvent.EventTypeLookup();
+
+    /**
+     * The b dynamic layout set.
+     */
+    private boolean bDynamicLayoutSet = true;
+
+    /**
+     * The set of desktop properties that user set directly.
+     */
+    private final HashSet<String> userPropSet = new HashSet<String>();
+
+    /**
+     * The desktop properties.
+     */
+    protected Map<String, Object> desktopProperties;
+
+    /**
+     * The desktop props support.
+     */
+    protected PropertyChangeSupport desktopPropsSupport;
+
+    /**
+     * For this component the native window is being created It is used in the
+     * callback-driven window creation (e.g. on Windows in the handler of
+     * WM_CREATE event) to establish the connection between this component and
+     * its native window.
+     */
+    private Object recentNativeWindowComponent;
+
+    /**
+     * The wtk.
+     */
+    private WTK wtk;
+
+    /**
+     * The Class ComponentInternalsImpl.
+     * 
+     * @since Android 1.0
+     */
+    protected final class ComponentInternalsImpl extends ComponentInternals {
+
+        /**
+         * Shutdown.
+         */
+        @Override
+        public void shutdown() {
+            dispatchThread.shutdown();
+        }
+
+        /**
+         * Sets the desktop property to the specified value and fires a property
+         * change event.
+         * 
+         * @param name
+         *            the name of property.
+         * @param value
+         *            the new value of property.
+         */
+        @Override
+        public void setDesktopProperty(String name, Object value) {
+            Toolkit.this.setDesktopProperty(name, value);
+        }
+    }
+
+    /**
+     * A lot of methods must throw HeadlessException if
+     * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>.
+     * 
+     * @throws HeadlessException
+     *             the headless exception.
+     */
+    static void checkHeadless() throws HeadlessException {
+        if (GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance())
+            throw new HeadlessException();
+    }
+
+    /**
+     * Lock AWT.
+     */
+    final void lockAWT() {
+        synchronizer.lock();
+    }
+
+    /**
+     * Static lock AWT.
+     */
+    static final void staticLockAWT() {
+        ContextStorage.getSynchronizer().lock();
+    }
+
+    /**
+     * Unlock AWT.
+     */
+    final void unlockAWT() {
+        synchronizer.unlock();
+    }
+
+    /**
+     * Static unlock AWT.
+     */
+    static final void staticUnlockAWT() {
+        ContextStorage.getSynchronizer().unlock();
+    }
+
+    /**
+     * InvokeAndWait under AWT lock. W/o this method system can hang up. Added
+     * to support modality (Dialog.show() & PopupMenu.show()) from not event
+     * dispatch thread. Use in other cases is not recommended. Still can be
+     * called only for whole API methods that cannot be called from other
+     * classes API methods. Examples: show() for modal dialogs - correct, only
+     * user can call it, directly or through setVisible(true) setBounds() for
+     * components - incorrect, setBounds() can be called from layoutContainer()
+     * for layout managers
+     * 
+     * @param runnable
+     *            the runnable.
+     * @throws InterruptedException
+     *             the interrupted exception.
+     * @throws InvocationTargetException
+     *             the invocation target exception.
+     */
+    final void unsafeInvokeAndWait(Runnable runnable) throws InterruptedException,
+            InvocationTargetException {
+        synchronizer.storeStateAndFree();
+        try {
+            EventQueue.invokeAndWait(runnable);
+        } finally {
+            synchronizer.lockAndRestoreState();
+        }
+    }
+
+    /**
+     * Gets the synchronizer.
+     * 
+     * @return the synchronizer.
+     */
+    final Synchronizer getSynchronizer() {
+        return synchronizer;
+    }
+
+    /**
+     * Gets the wTK.
+     * 
+     * @return the wTK.
+     */
+    final WTK getWTK() {
+        return wtk;
+    }
+
+    /**
+     * Gets the property with the specified key and default value. This method
+     * returns the defValue if the property is not found.
+     * 
+     * @param propName
+     *            the name of property.
+     * @param defVal
+     *            the default value.
+     * @return the property value.
+     */
+    public static String getProperty(String propName, String defVal) {
+        if (propName == null) {
+            // awt.7D=Property name is null
+            throw new NullPointerException(Messages.getString("awt.7D")); //$NON-NLS-1$
+        }
+        staticLockAWT();
+        try {
+            String retVal = null;
+            if (properties != null) {
+                try {
+                    retVal = properties.getString(propName);
+                } catch (MissingResourceException e) {
+                } catch (ClassCastException e) {
+                }
+            }
+            return (retVal == null) ? defVal : retVal;
+        } finally {
+            staticUnlockAWT();
+        }
+    }
+
+    /**
+     * Gets the default Toolkit.
+     * 
+     * @return the default Toolkit.
+     */
+    public static Toolkit getDefaultToolkit() {
+        synchronized (ContextStorage.getContextLock()) {
+            if (ContextStorage.shutdownPending()) {
+                return null;
+            }
+            Toolkit defToolkit = ContextStorage.getDefaultToolkit();
+            if (defToolkit != null) {
+                return defToolkit;
+            }
+            staticLockAWT();
+            try {
+                defToolkit = GraphicsEnvironment.isHeadless() ? new HeadlessToolkit()
+                        : new ToolkitImpl();
+                ContextStorage.setDefaultToolkit(defToolkit);
+                return defToolkit;
+            } finally {
+                staticUnlockAWT();
+            }
+            // TODO: read system property named awt.toolkit
+            // and create an instance of the specified class,
+            // by default use ToolkitImpl
+        }
+    }
+
+    /**
+     * Gets the default Font.
+     * 
+     * @return the default Font for Toolkit.
+     */
+    Font getDefaultFont() {
+        return wtk.getSystemProperties().getDefaultFont();
+    }
+
+    /**
+     * Load resources.
+     * 
+     * @param path
+     *            the path.
+     * @return the resource bundle.
+     */
+    private static ResourceBundle loadResources(String path) {
+        try {
+            return ResourceBundle.getBundle(path);
+        } catch (MissingResourceException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the wTK class name.
+     * 
+     * @return the wTK class name.
+     */
+    private static String getWTKClassName() {
+        return "com.android.internal.awt.AndroidWTK";
+    }
+
+    /**
+     * Gets the component by id.
+     * 
+     * @param id
+     *            the id.
+     * @return the component by id.
+     */
+    Component getComponentById(long id) {
+        if (id == 0) {
+            return null;
+        }
+        return null;
+    }
+
+    /**
+     * Gets the GraphicsFactory.
+     * 
+     * @return the GraphicsFactory object.
+     */
+    public GraphicsFactory getGraphicsFactory() {
+        return wtk.getGraphicsFactory();
+    }
+
+    /**
+     * Instantiates a new toolkit.
+     */
+    public Toolkit() {
+        init();
+    }
+
+    /**
+     * Initiates AWT.
+     */
+    protected void init() {
+        lockAWT();
+        try {
+            ComponentInternals.setComponentInternals(new ComponentInternalsImpl());
+            new EventQueue(this); // create the system EventQueue
+            dispatcher = new Dispatcher(this);
+            final String className = getWTKClassName();
+            desktopProperties = new HashMap<String, Object>();
+            desktopPropsSupport = new PropertyChangeSupport(this);
+            awtEventsManager = new AWTEventsManager();
+            dispatchThread = new EventDispatchThread(this, dispatcher);
+            nativeThread = new NativeEventThread();
+            NativeEventThread.Init init = new NativeEventThread.Init() {
+                public WTK init() {
+                    wtk = createWTK(className);
+                    wtk.getNativeEventQueue().setShutdownWatchdog(shutdownWatchdog);
+                    synchronizer.setEnvironment(wtk, dispatchThread);
+                    ContextStorage.setWTK(wtk);
+                    return wtk;
+                }
+            };
+            nativeThread.start(init);
+            dispatchThread.start();
+            wtk.getNativeEventQueue().awake();
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Synchronizes this toolkit's graphics.
+     */
+    public abstract void sync();
+
+    /**
+     * Returns the construction status of a specified image that is being
+     * created.
+     * 
+     * @param a0
+     *            the image to be checked.
+     * @param a1
+     *            the width of scaled image for which the status is being
+     *            checked or -1.
+     * @param a2
+     *            the height of scaled image for which the status is being
+     *            checked or -1.
+     * @param a3
+     *            the ImageObserver object to be notified while the image is
+     *            being prepared.
+     * @return the ImageObserver flags which give the current state of the image
+     *         data.
+     */
+    public abstract int checkImage(Image a0, int a1, int a2, ImageObserver a3);
+
+    /**
+     * Creates the image with the specified ImageProducer.
+     * 
+     * @param a0
+     *            the ImageProducer to be used for image creation.
+     * @return the image with the specified ImageProducer.
+     */
+    public abstract Image createImage(ImageProducer a0);
+
+    /**
+     * Creates the image from the specified byte array, offset and length. The
+     * byte array should contain data with image format supported by Toolkit
+     * such as JPEG, GIF, or PNG.
+     * 
+     * @param a0
+     *            the byte array with the image data.
+     * @param a1
+     *            the offset of the beginning the image data in the byte array.
+     * @param a2
+     *            the length of the image data in the byte array.
+     * @return the created Image.
+     */
+    public abstract Image createImage(byte[] a0, int a1, int a2);
+
+    /**
+     * Creates the image using image data from the specified URL.
+     * 
+     * @param a0
+     *            the URL for extracting image data.
+     * @return the Image.
+     */
+    public abstract Image createImage(URL a0);
+
+    /**
+     * Creates the image using image data from the specified file.
+     * 
+     * @param a0
+     *            the file name which contains image data of supported format.
+     * @return the Image.
+     */
+    public abstract Image createImage(String a0);
+
+    /**
+     * Gets the color model.
+     * 
+     * @return the ColorModel of Toolkit's screen.
+     * @throws HeadlessException
+     *             if the GraphicsEnvironment.isHeadless() method returns true.
+     */
+    public abstract ColorModel getColorModel() throws HeadlessException;
+
+    /**
+     * Gets the screen device metrics for the specified font.
+     * 
+     * @param font
+     *            the Font.
+     * @return the FontMetrics for the specified Font.
+     * @deprecated Use getLineMetrics method from Font class.
+     */
+
+    @Deprecated
+    public abstract FontMetrics getFontMetrics(Font font);
+
+    /**
+     * Prepares the specified image for rendering on the screen with the
+     * specified size.
+     * 
+     * @param a0
+     *            the Image to be prepared.
+     * @param a1
+     *            the width of the screen representation or -1 for the current
+     *            screen.
+     * @param a2
+     *            the height of the screen representation or -1 for the current
+     *            screen.
+     * @param a3
+     *            the ImageObserver object to be notified as soon as the image
+     *            is prepared.
+     * @return true, if image is fully prepared, false otherwise.
+     */
+    public abstract boolean prepareImage(Image a0, int a1, int a2, ImageObserver a3);
+
+    /**
+     * Creates an audio beep.
+     */
+    public abstract void beep();
+
+    /**
+     * Returns the array of font names which are available in this Toolkit.
+     * 
+     * @return the array of font names which are available in this Toolkit.
+     * @deprecated use GraphicsEnvironment.getAvailableFontFamilyNames() method.
+     */
+    @Deprecated
+    public abstract String[] getFontList();
+
+    /**
+     * Gets the the Font implementation using the specified peer interface.
+     * 
+     * @param a0
+     *            the Font name to be implemented.
+     * @param a1
+     *            the the font style: PLAIN, BOLD, ITALIC.
+     * @return the FontPeer implementation of the specified Font.
+     * @deprecated use java.awt.GraphicsEnvironment.getAllFonts method.
+     */
+
+    @Deprecated
+    protected abstract FontPeer getFontPeer(String a0, int a1);
+
+    /**
+     * Gets the image from the specified file which contains image data in a
+     * supported image format (such as JPEG, GIF, or PNG); this method should
+     * return the same Image for multiple calls of this method with the same
+     * image file name.
+     * 
+     * @param a0
+     *            the file name which contains image data in a supported image
+     *            format (such as JPEG, GIF, or PNG).
+     * @return the Image.
+     */
+    public abstract Image getImage(String a0);
+
+    /**
+     * Gets the image from the specified URL which contains image data in a
+     * supported image format (such as JPEG, GIF, or PNG); this method should
+     * return the same Image for multiple calls of this method with the same
+     * image URL.
+     * 
+     * @param a0
+     *            the URL which contains image data in a supported image format
+     *            (such as JPEG, GIF, or PNG).
+     * @return the Image.
+     */
+    public abstract Image getImage(URL a0);
+
+    /**
+     * Gets the screen resolution.
+     * 
+     * @return the screen resolution.
+     * @throws HeadlessException
+     *             if the GraphicsEnvironment.isHeadless() method returns true.
+     */
+    public abstract int getScreenResolution() throws HeadlessException;
+
+    /**
+     * Gets the screen size.
+     * 
+     * @return a Dimension object containing the width and height of the screen.
+     * @throws HeadlessException
+     *             if the GraphicsEnvironment.isHeadless() method returns true.
+     */
+    public abstract Dimension getScreenSize() throws HeadlessException;
+
+    /**
+     * Gets the EventQueue instance without checking access.
+     * 
+     * @return the system EventQueue.
+     */
+    protected abstract EventQueue getSystemEventQueueImpl();
+
+    /**
+     * Returns a map of text attributes for the abstract level description of
+     * the specified input method highlight, or null if no mapping is found.
+     * 
+     * @param highlight
+     *            the InputMethodHighlight.
+     * @return the Map<java.awt.font. text attribute,?>.
+     * @throws HeadlessException
+     *             if the GraphicsEnvironment.isHeadless() method returns true.
+     */
+    public abstract Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlight(
+            InputMethodHighlight highlight) throws HeadlessException;
+
+    /**
+     * Map input method highlight impl.
+     * 
+     * @param highlight
+     *            the highlight.
+     * @return the map<java.awt.font. text attribute,?>.
+     * @throws HeadlessException
+     *             the headless exception.
+     */
+    Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlightImpl(InputMethodHighlight highlight)
+            throws HeadlessException {
+        HashMap<java.awt.font.TextAttribute, ?> map = new HashMap<java.awt.font.TextAttribute, Object>();
+        wtk.getSystemProperties().mapInputMethodHighlight(highlight, map);
+        return Collections.<java.awt.font.TextAttribute, Object> unmodifiableMap(map);
+    }
+
+    /**
+     * Adds the specified PropertyChangeListener listener for the specified
+     * property.
+     * 
+     * @param propName
+     *            the property name for which the specified
+     *            PropertyChangeListener will be added.
+     * @param l
+     *            the PropertyChangeListener object.
+     */
+    public void addPropertyChangeListener(String propName, PropertyChangeListener l) {
+        lockAWT();
+        try {
+            if (desktopProperties.isEmpty()) {
+                initializeDesktopProperties();
+            }
+        } finally {
+            unlockAWT();
+        }
+        if (l != null) { // there is no guarantee that null listener will not be
+            // added
+            desktopPropsSupport.addPropertyChangeListener(propName, l);
+        }
+    }
+
+    /**
+     * Returns an array of the property change listeners registered with this
+     * Toolkit.
+     * 
+     * @return an array of the property change listeners registered with this
+     *         Toolkit.
+     */
+    public PropertyChangeListener[] getPropertyChangeListeners() {
+        return desktopPropsSupport.getPropertyChangeListeners();
+    }
+
+    /**
+     * Returns an array of the property change listeners registered with this
+     * Toolkit for notification regarding the specified property.
+     * 
+     * @param propName
+     *            the property name for which the PropertyChangeListener was
+     *            registered.
+     * @return the array of PropertyChangeListeners registered for the specified
+     *         property name.
+     */
+    public PropertyChangeListener[] getPropertyChangeListeners(String propName) {
+        return desktopPropsSupport.getPropertyChangeListeners(propName);
+    }
+
+    /**
+     * Removes the specified property change listener registered for the
+     * specified property name.
+     * 
+     * @param propName
+     *            the property name.
+     * @param l
+     *            the PropertyChangeListener registered for the specified
+     *            property name.
+     */
+    public void removePropertyChangeListener(String propName, PropertyChangeListener l) {
+        desktopPropsSupport.removePropertyChangeListener(propName, l);
+    }
+
+    /**
+     * Creates a custom cursor with the specified Image, hot spot, and cursor
+     * description.
+     * 
+     * @param img
+     *            the image of activated cursor.
+     * @param hotSpot
+     *            the Point giving the coordinates of the cursor's hot spot.
+     * @param name
+     *            the cursor description.
+     * @return the cursor with the specified Image, hot spot, and cursor
+     *         description.
+     * @throws IndexOutOfBoundsException
+     *             if the hot spot values are outside the bounds of the cursor.
+     * @throws HeadlessException
+     *             if isHeadless() method of GraphicsEnvironment class returns
+     *             true.
+     */
+    public Cursor createCustomCursor(Image img, Point hotSpot, String name)
+            throws IndexOutOfBoundsException, HeadlessException {
+        lockAWT();
+        try {
+            int w = img.getWidth(null), x = hotSpot.x;
+            int h = img.getHeight(null), y = hotSpot.y;
+            if (x < 0 || x >= w || y < 0 || y >= h) {
+                // awt.7E=invalid hotSpot
+                throw new IndexOutOfBoundsException(Messages.getString("awt.7E")); //$NON-NLS-1$
+            }
+            return new Cursor(name, img, hotSpot);
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Returns the supported cursor dimension which is closest to the specified
+     * width and height. If the Toolkit only supports a single cursor size, this
+     * method should return the supported cursor size. If custom cursor is not
+     * supported, a dimension of 0, 0 should be returned.
+     * 
+     * @param prefWidth
+     *            the preferred cursor width.
+     * @param prefHeight
+     *            the preferred cursor height.
+     * @return the supported cursor dimension which is closest to the specified
+     *         width and height.
+     * @throws HeadlessException
+     *             if GraphicsEnvironment.isHeadless() returns true.
+     */
+    public Dimension getBestCursorSize(int prefWidth, int prefHeight) throws HeadlessException {
+        lockAWT();
+        try {
+            return wtk.getCursorFactory().getBestCursorSize(prefWidth, prefHeight);
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the value for the specified desktop property.
+     * 
+     * @param propName
+     *            the property name.
+     * @return the Object that is the property's value.
+     */
+    public final Object getDesktopProperty(String propName) {
+        lockAWT();
+        try {
+            if (desktopProperties.isEmpty()) {
+                initializeDesktopProperties();
+            }
+            if (propName.equals("awt.dynamicLayoutSupported")) { //$NON-NLS-1$
+                // dynamicLayoutSupported is special case
+                return Boolean.valueOf(isDynamicLayoutActive());
+            }
+            Object val = desktopProperties.get(propName);
+            if (val == null) {
+                // try to lazily load prop value
+                // just for compatibility, our lazilyLoad is empty
+                val = lazilyLoadDesktopProperty(propName);
+            }
+            return val;
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Returns the locking key state for the specified key.
+     * 
+     * @param a0
+     *            the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK, or
+     *            VK_KANA_LOCK.
+     * @return true if the specified key code is in the locked state, false
+     *         otherwise.
+     * @throws UnsupportedOperationException
+     *             if the state of this key can't be retrieved, or if the
+     *             keyboard doesn't have this key.
+     * @throws NotImplementedException
+     *             if this method is not implemented.
+     */
+    public boolean getLockingKeyState(int a0) throws UnsupportedOperationException,
+            org.apache.harmony.luni.util.NotImplementedException {
+        lockAWT();
+        try {
+        } finally {
+            unlockAWT();
+        }
+        if (true) {
+            throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$
+        }
+        return true;
+    }
+
+    /**
+     * Returns the maximum number of colors which the Toolkit supports for
+     * custom cursor.
+     * 
+     * @return the maximum cursor colors.
+     * @throws HeadlessException
+     *             if the GraphicsEnvironment.isHeadless() method returns true.
+     */
+    public int getMaximumCursorColors() throws HeadlessException {
+        lockAWT();
+        try {
+            return wtk.getCursorFactory().getMaximumCursorColors();
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the menu shortcut key mask.
+     * 
+     * @return the menu shortcut key mask.
+     * @throws HeadlessException
+     *             if the GraphicsEnvironment.isHeadless() method returns true.
+     */
+    public int getMenuShortcutKeyMask() throws HeadlessException {
+        lockAWT();
+        try {
+            return InputEvent.CTRL_MASK;
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the screen insets.
+     * 
+     * @param gc
+     *            the GraphicsConfiguration.
+     * @return the insets of this toolkit.
+     * @throws HeadlessException
+     *             if the GraphicsEnvironment.isHeadless() method returns true.
+     */
+    public Insets getScreenInsets(GraphicsConfiguration gc) throws HeadlessException {
+        if (gc == null) {
+            throw new NullPointerException();
+        }
+        lockAWT();
+        try {
+            return new Insets(0, 0, 0, 0); // TODO: get real screen insets
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the system EventQueue instance. If the default implementation of
+     * checkAwtEventQueueAccess is used, then this results of a call to the
+     * security manager's checkPermission method with an
+     * AWTPermission("accessEventQueue") permission.
+     * 
+     * @return the system EventQueue instance.
+     */
+    public final EventQueue getSystemEventQueue() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkAwtEventQueueAccess();
+        }
+        return getSystemEventQueueImpl();
+    }
+
+    /**
+     * Gets the system event queue core.
+     * 
+     * @return the system event queue core.
+     */
+    EventQueueCore getSystemEventQueueCore() {
+        return systemEventQueueCore;
+    }
+
+    /**
+     * Sets the system event queue core.
+     * 
+     * @param core
+     *            the new system event queue core.
+     */
+    void setSystemEventQueueCore(EventQueueCore core) {
+        systemEventQueueCore = core;
+    }
+
+    /**
+     * Initialize the desktop properties.
+     */
+    protected void initializeDesktopProperties() {
+        lockAWT();
+        try {
+            wtk.getSystemProperties().init(desktopProperties);
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Checks if dynamic layout of Containers is active or not.
+     * 
+     * @return true, if is dynamic layout of Containers is active, false
+     *         otherwise.
+     * @throws HeadlessException
+     *             if the GraphicsEnvironment.isHeadless() method returns true.
+     */
+    public boolean isDynamicLayoutActive() throws HeadlessException {
+        lockAWT();
+        try {
+            // always return true
+            return true;
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Returns if the layout of Containers is checked dynamically during
+     * resizing, or statically after resizing is completed.
+     * 
+     * @return true, if if the layout of Containers is checked dynamically
+     *         during resizing; false, if the layout of Containers is checked
+     *         statically after resizing is completed.
+     * @throws HeadlessException
+     *             if the GraphicsEnvironment.isHeadless() method returns true.
+     */
+    protected boolean isDynamicLayoutSet() throws HeadlessException {
+        lockAWT();
+        try {
+            return bDynamicLayoutSet;
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Checks if the specified frame state is supported by Toolkit or not.
+     * 
+     * @param state
+     *            the frame state.
+     * @return true, if frame state is supported, false otherwise.
+     * @throws HeadlessException
+     *             if the GraphicsEnvironment.isHeadless() method returns true.
+     */
+    public boolean isFrameStateSupported(int state) throws HeadlessException {
+        lockAWT();
+        try {
+            return wtk.getWindowFactory().isWindowStateSupported(state);
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Loads the value of the desktop property with the specified property name.
+     * 
+     * @param propName
+     *            the property name.
+     * @return the desktop property values.
+     */
+    protected Object lazilyLoadDesktopProperty(String propName) {
+        return null;
+    }
+
+    /**
+     * Loads the current system color values to the specified array.
+     * 
+     * @param colors
+     *            the array where the current system color values are written by
+     *            this method.
+     * @throws HeadlessException
+     *             if the GraphicsEnvironment.isHeadless() method returns true.
+     */
+    protected void loadSystemColors(int[] colors) throws HeadlessException {
+        lockAWT();
+        try {
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the value of the desktop property with the specified name.
+     * 
+     * @param propName
+     *            the property's name.
+     * @param value
+     *            the property's value.
+     */
+    protected final void setDesktopProperty(String propName, Object value) {
+        Object oldVal;
+        lockAWT();
+        try {
+            oldVal = getDesktopProperty(propName);
+            userPropSet.add(propName);
+            desktopProperties.put(propName, value);
+        } finally {
+            unlockAWT();
+        }
+        desktopPropsSupport.firePropertyChange(propName, oldVal, value);
+    }
+
+    /**
+     * Sets the layout state, whether the Container layout is checked
+     * dynamically during resizing, or statically after resizing is completed.
+     * 
+     * @param dynamic
+     *            the new dynamic layout state - if true the layout of
+     *            Containers is checked dynamically during resizing, if false -
+     *            statically after resizing is completed.
+     * @throws HeadlessException
+     *             if the GraphicsEnvironment.isHeadless() method returns true.
+     */
+    public void setDynamicLayout(boolean dynamic) throws HeadlessException {
+        lockAWT();
+        try {
+            bDynamicLayoutSet = dynamic;
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Sets the locking key state for the specified key code.
+     * 
+     * @param a0
+     *            the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK, or
+     *            VK_KANA_LOCK.
+     * @param a1
+     *            the state - true to set the specified key code to the locked
+     *            state, false - to unlock it.
+     * @throws UnsupportedOperationException
+     *             if the state of this key can't be set, or if the keyboard
+     *             doesn't have this key.
+     * @throws NotImplementedException
+     *             if this method is not implemented.
+     */
+    public void setLockingKeyState(int a0, boolean a1) throws UnsupportedOperationException,
+            org.apache.harmony.luni.util.NotImplementedException {
+        lockAWT();
+        try {
+        } finally {
+            unlockAWT();
+        }
+        if (true) {
+            throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$
+        }
+        return;
+    }
+
+    /**
+     * On queue empty.
+     */
+    void onQueueEmpty() {
+        throw new RuntimeException("Not implemented!");
+    }
+
+    /**
+     * Creates the wtk.
+     * 
+     * @param clsName
+     *            the cls name.
+     * @return the wTK.
+     */
+    private WTK createWTK(String clsName) {
+        WTK newWTK = null;
+        try {
+            newWTK = (WTK)Class.forName(clsName).newInstance();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return newWTK;
+    }
+
+    /**
+     * Connect the component to its native window
+     * 
+     * @param winId
+     *            the id of native window just created.
+     */
+    boolean onWindowCreated(long winId) {
+        return false;
+    }
+
+    /**
+     * Gets the native event queue.
+     * 
+     * @return the native event queue.
+     */
+    NativeEventQueue getNativeEventQueue() {
+        return wtk.getNativeEventQueue();
+    }
+
+    /**
+     * Returns a shared instance of implementation of
+     * org.apache.harmony.awt.wtk.NativeCursor for current platform for.
+     * 
+     * @param type
+     *            the Java Cursor type.
+     * @return new instance of implementation of NativeCursor.
+     */
+    NativeCursor createNativeCursor(int type) {
+        return wtk.getCursorFactory().getCursor(type);
+    }
+
+    /**
+     * Returns a shared instance of implementation of
+     * org.apache.harmony.awt.wtk.NativeCursor for current platform for custom
+     * cursor
+     * 
+     * @param img
+     *            the img.
+     * @param hotSpot
+     *            the hot spot.
+     * @param name
+     *            the name.
+     * @return new instance of implementation of NativeCursor.
+     */
+    NativeCursor createCustomNativeCursor(Image img, Point hotSpot, String name) {
+        return wtk.getCursorFactory().createCustomCursor(img, hotSpot.x, hotSpot.y);
+    }
+
+    /**
+     * Adds an AWTEventListener to the Toolkit to listen for events of types
+     * corresponding to bits in the specified event mask. Event masks are
+     * defined in AWTEvent class.
+     * 
+     * @param listener
+     *            the AWTEventListener.
+     * @param eventMask
+     *            the bitmask of event types.
+     */
+    public void addAWTEventListener(AWTEventListener listener, long eventMask) {
+        lockAWT();
+        try {
+            SecurityManager security = System.getSecurityManager();
+            if (security != null) {
+                security.checkPermission(awtEventsManager.permission);
+            }
+            awtEventsManager.addAWTEventListener(listener, eventMask);
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Removes the specified AWT event listener.
+     * 
+     * @param listener
+     *            the AWTEventListener to be removed.
+     */
+    public void removeAWTEventListener(AWTEventListener listener) {
+        lockAWT();
+        try {
+            SecurityManager security = System.getSecurityManager();
+            if (security != null) {
+                security.checkPermission(awtEventsManager.permission);
+            }
+            awtEventsManager.removeAWTEventListener(listener);
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Gets the array of all AWT event listeners registered with this Toolkit.
+     * 
+     * @return the array of all AWT event listeners registered with this
+     *         Toolkit.
+     */
+    public AWTEventListener[] getAWTEventListeners() {
+        lockAWT();
+        try {
+            SecurityManager security = System.getSecurityManager();
+            if (security != null) {
+                security.checkPermission(awtEventsManager.permission);
+            }
+            return awtEventsManager.getAWTEventListeners();
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Returns the array of the AWT event listeners registered with this Toolkit
+     * for the event types corresponding to the specified event mask.
+     * 
+     * @param eventMask
+     *            the bit mask of event type.
+     * @return the array of the AWT event listeners registered in this Toolkit
+     *         for the event types corresponding to the specified event mask.
+     */
+    public AWTEventListener[] getAWTEventListeners(long eventMask) {
+        lockAWT();
+        try {
+            SecurityManager security = System.getSecurityManager();
+            if (security != null) {
+                security.checkPermission(awtEventsManager.permission);
+            }
+            return awtEventsManager.getAWTEventListeners(eventMask);
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    /**
+     * Dispatch AWT event.
+     * 
+     * @param event
+     *            the event.
+     */
+    void dispatchAWTEvent(AWTEvent event) {
+        awtEventsManager.dispatchAWTEvent(event);
+    }
+
+    /**
+     * The Class AWTEventsManager.
+     */
+    final class AWTEventsManager {
+
+        /**
+         * The permission.
+         */
+        AWTPermission permission = new AWTPermission("listenToAllAWTEvents"); //$NON-NLS-1$
+
+        /**
+         * The listeners.
+         */
+        private final AWTListenerList<AWTEventListenerProxy> listeners = new AWTListenerList<AWTEventListenerProxy>();
+
+        /**
+         * Adds the AWT event listener.
+         * 
+         * @param listener
+         *            the listener.
+         * @param eventMask
+         *            the event mask.
+         */
+        void addAWTEventListener(AWTEventListener listener, long eventMask) {
+            if (listener != null) {
+                listeners.addUserListener(new AWTEventListenerProxy(eventMask, listener));
+            }
+        }
+
+        /**
+         * Removes the AWT event listener.
+         * 
+         * @param listener
+         *            the listener.
+         */
+        void removeAWTEventListener(AWTEventListener listener) {
+            if (listener != null) {
+                for (AWTEventListenerProxy proxy : listeners.getUserListeners()) {
+                    if (listener == proxy.getListener()) {
+                        listeners.removeUserListener(proxy);
+                        return;
+                    }
+                }
+            }
+        }
+
+        /**
+         * Gets the AWT event listeners.
+         * 
+         * @return the AWT event listeners.
+         */
+        AWTEventListener[] getAWTEventListeners() {
+            HashSet<EventListener> listenersSet = new HashSet<EventListener>();
+            for (AWTEventListenerProxy proxy : listeners.getUserListeners()) {
+                listenersSet.add(proxy.getListener());
+            }
+            return listenersSet.toArray(new AWTEventListener[listenersSet.size()]);
+        }
+
+        /**
+         * Gets the AWT event listeners.
+         * 
+         * @param eventMask
+         *            the event mask.
+         * @return the AWT event listeners.
+         */
+        AWTEventListener[] getAWTEventListeners(long eventMask) {
+            HashSet<EventListener> listenersSet = new HashSet<EventListener>();
+            for (AWTEventListenerProxy proxy : listeners.getUserListeners()) {
+                if ((proxy.getEventMask() & eventMask) == eventMask) {
+                    listenersSet.add(proxy.getListener());
+                }
+            }
+            return listenersSet.toArray(new AWTEventListener[listenersSet.size()]);
+        }
+
+        /**
+         * Dispatch AWT event.
+         * 
+         * @param event
+         *            the event.
+         */
+        void dispatchAWTEvent(AWTEvent event) {
+            AWTEvent.EventDescriptor descriptor = eventTypeLookup.getEventDescriptor(event);
+            if (descriptor == null) {
+                return;
+            }
+            for (AWTEventListenerProxy proxy : listeners.getUserListeners()) {
+                if ((proxy.getEventMask() & descriptor.eventMask) != 0) {
+                    proxy.eventDispatched(event);
+                }
+            }
+        }
+    }
+
+    /**
+     * The Class AutoNumber.
+     */
+    static final class AutoNumber {
+
+        /**
+         * The next component.
+         */
+        int nextComponent = 0;
+
+        /**
+         * The next canvas.
+         */
+        int nextCanvas = 0;
+
+        /**
+         * The next panel.
+         */
+        int nextPanel = 0;
+
+        /**
+         * The next window.
+         */
+        int nextWindow = 0;
+
+        /**
+         * The next frame.
+         */
+        int nextFrame = 0;
+
+        /**
+         * The next dialog.
+         */
+        int nextDialog = 0;
+
+        /**
+         * The next button.
+         */
+        int nextButton = 0;
+
+        /**
+         * The next menu component.
+         */
+        int nextMenuComponent = 0;
+
+        /**
+         * The next label.
+         */
+        int nextLabel = 0;
+
+        /**
+         * The next check box.
+         */
+        int nextCheckBox = 0;
+
+        /**
+         * The next scrollbar.
+         */
+        int nextScrollbar = 0;
+
+        /**
+         * The next scroll pane.
+         */
+        int nextScrollPane = 0;
+
+        /**
+         * The next list.
+         */
+        int nextList = 0;
+
+        /**
+         * The next choice.
+         */
+        int nextChoice = 0;
+
+        /**
+         * The next file dialog.
+         */
+        int nextFileDialog = 0;
+
+        /**
+         * The next text area.
+         */
+        int nextTextArea = 0;
+
+        /**
+         * The next text field.
+         */
+        int nextTextField = 0;
+    }
+
+    private class Lock {
+    }
+
+    /**
+     * The lock.
+     */
+    private final Object lock = new Lock();
+
+}
diff --git a/awt/java/awt/ToolkitImpl.java b/awt/java/awt/ToolkitImpl.java
new file mode 100644
index 0000000..5015aef
--- /dev/null
+++ b/awt/java/awt/ToolkitImpl.java
@@ -0,0 +1,255 @@
+/*
+ *  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.
+ */
+
+package java.awt;
+
+import java.awt.im.InputMethodHighlight;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.peer.*;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.Hashtable;
+import java.util.Map;
+import org.apache.harmony.awt.gl.image.*;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+
+class ToolkitImpl extends Toolkit {
+	
+    static final Hashtable<Serializable, Image> imageCache = new Hashtable<Serializable, Image>();
+
+    @Override
+    public void sync() {
+        lockAWT();
+        try {
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @Override
+    public int checkImage(Image image, int width, int height, ImageObserver observer) {
+        lockAWT();
+        try {
+            if (width == 0 || height == 0) {
+                return ImageObserver.ALLBITS;
+            }
+            if (!(image instanceof OffscreenImage)) {
+                return ImageObserver.ALLBITS;
+            }
+            OffscreenImage oi = (OffscreenImage) image;
+            return oi.checkImage(observer);
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @Override
+    public Image createImage(ImageProducer producer) {
+        lockAWT();
+        try {
+            return new OffscreenImage(producer);
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @Override
+    public Image createImage(byte[] imagedata, int imageoffset, int imagelength) {
+        lockAWT();
+        try {
+            return new OffscreenImage(new ByteArrayDecodingImageSource(imagedata, imageoffset,
+                    imagelength));
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @Override
+    public Image createImage(URL url) {
+        lockAWT();
+        try {
+            return new OffscreenImage(new URLDecodingImageSource(url));
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @Override
+    public Image createImage(String filename) {
+        lockAWT();
+        try {
+            return new OffscreenImage(new FileDecodingImageSource(filename));
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @Override
+    public ColorModel getColorModel() {
+        lockAWT();
+        try {
+            return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
+                    .getDefaultConfiguration().getColorModel();
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    @Deprecated
+    public FontMetrics getFontMetrics(Font font) {
+        lockAWT();
+        try {
+        	GraphicsFactory gf = getGraphicsFactory();
+            return gf.getFontMetrics(font);
+        } finally {
+            unlockAWT();
+        }
+    }
+    
+    @Override
+    public boolean prepareImage(Image image, int width, int height, ImageObserver observer) {
+        lockAWT();
+        try {
+            if (width == 0 || height == 0) {
+                return true;
+            }
+            if (!(image instanceof OffscreenImage)) {
+                return true;
+            }
+            OffscreenImage oi = (OffscreenImage) image;
+            return oi.prepareImage(observer);
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @Override
+    public void beep() {
+        lockAWT();
+        try {
+        	// ???AWT: is there nothing to be implemented here?
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    @Deprecated
+    public String[] getFontList() {
+        lockAWT();
+        try {
+        } finally {
+            unlockAWT();
+        }
+        return null;
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    @Deprecated
+    protected FontPeer getFontPeer(String a0, int a1) {
+        lockAWT();
+        try {
+            return null;
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @Override
+    public Image getImage(String filename) {
+        return getImage(filename, this);
+    }
+
+    static Image getImage(String filename, Toolkit toolkit) {
+        synchronized (imageCache) {
+            Image im = (filename == null ? null : imageCache.get(filename));
+
+            if (im == null) {
+                try {
+                    im = toolkit.createImage(filename);
+                    imageCache.put(filename, im);
+                } catch (Exception e) {
+                }
+            }
+
+            return im;
+        }
+    }
+
+    @Override
+    public Image getImage(URL url) {
+        return getImage(url, this);
+    }
+
+    static Image getImage(URL url, Toolkit toolkit) {
+        synchronized (imageCache) {
+            Image im = imageCache.get(url);
+            if (im == null) {
+                try {
+                    im = toolkit.createImage(url);
+                    imageCache.put(url, im);
+                } catch (Exception e) {
+                }
+            }
+            return im;
+        }
+    }
+
+    @Override
+    public int getScreenResolution() throws HeadlessException {
+        lockAWT();
+        try {
+        	return 62;
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @Override
+    public Dimension getScreenSize() {
+        lockAWT();
+        try {
+            DisplayMode dm = GraphicsEnvironment.getLocalGraphicsEnvironment()
+                    .getDefaultScreenDevice().getDisplayMode();
+            return new Dimension(dm.getWidth(), dm.getHeight());
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @Override
+    public Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlight(
+            InputMethodHighlight highlight) throws HeadlessException {
+        lockAWT();
+        try {
+            return mapInputMethodHighlightImpl(highlight);
+        } finally {
+            unlockAWT();
+        }
+    }
+
+    @Override
+    protected EventQueue getSystemEventQueueImpl() {
+        return getSystemEventQueueCore().getActiveEventQueue();
+    }
+}
diff --git a/awt/java/awt/Transparency.java b/awt/java/awt/Transparency.java
new file mode 100644
index 0000000..44a1e7f
--- /dev/null
+++ b/awt/java/awt/Transparency.java
@@ -0,0 +1,57 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+
+package java.awt;
+
+/**
+ * The Transparency interface defines transparency's general modes.
+ * 
+ * @since Android 1.0
+ */
+public interface Transparency {
+
+    /**
+     * The Constant OPAQUE represents completely opaque data, all pixels have an
+     * alpha value of 1.0.
+     */
+    public static final int OPAQUE = 1;
+
+    /**
+     * The Constant BITMASK represents data which can be either completely
+     * opaque, with an alpha value of 1.0, or completely transparent, with an
+     * alpha value of 0.0.
+     */
+    public static final int BITMASK = 2;
+
+    /**
+     * The Constant TRANSLUCENT represents data which alpha value can vary
+     * between and including 0.0 and 1.0.
+     */
+    public static final int TRANSLUCENT = 3;
+
+    /**
+     * Gets the transparency mode.
+     * 
+     * @return the transparency mode: OPAQUE, BITMASK or TRANSLUCENT.
+     */
+    public int getTransparency();
+
+}
diff --git a/awt/java/awt/color/CMMException.java b/awt/java/awt/color/CMMException.java
new file mode 100644
index 0000000..18b9a7e
--- /dev/null
+++ b/awt/java/awt/color/CMMException.java
@@ -0,0 +1,44 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+/**
+ * The CMMException is thrown as soon as a native CMM error occurs.
+ * 
+ * @since Android 1.0
+ */
+public class CMMException extends java.lang.RuntimeException {
+    
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 5775558044142994965L;
+
+    /**
+     * Instantiates a new CMM exception with detail message.
+     * 
+     * @param s
+     *            the detail message of the exception.
+     */
+    public CMMException (String s) {
+        super (s);
+    }
+}
diff --git a/awt/java/awt/color/ColorSpace.java b/awt/java/awt/color/ColorSpace.java
new file mode 100644
index 0000000..44c491b
--- /dev/null
+++ b/awt/java/awt/color/ColorSpace.java
@@ -0,0 +1,414 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+import java.io.Serializable;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ColorSpace class defines a color space type for a Color and provides
+ * methods for arrays of color component operations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ColorSpace implements Serializable {
+
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = -409452704308689724L;
+
+    /**
+     * The Constant TYPE_XYZ indicates XYZ color space type.
+     */
+    public static final int TYPE_XYZ = 0;
+
+    /**
+     * The Constant TYPE_Lab indicates Lab color space type.
+     */
+    public static final int TYPE_Lab = 1;
+
+    /**
+     * The Constant TYPE_Luv indicates Luv color space type.
+     */
+    public static final int TYPE_Luv = 2;
+
+    /**
+     * The Constant TYPE_YCbCr indicates YCbCr color space type.
+     */
+    public static final int TYPE_YCbCr = 3;
+
+    /**
+     * The Constant TYPE_Yxy indicates Yxy color space type.
+     */
+    public static final int TYPE_Yxy = 4;
+
+    /**
+     * The Constant TYPE_RGB indicates RGB color space type.
+     */
+    public static final int TYPE_RGB = 5;
+
+    /**
+     * The Constant TYPE_GRAY indicates Gray color space type.
+     */
+    public static final int TYPE_GRAY = 6;
+
+    /**
+     * The Constant TYPE_HSV indicates HSV color space type.
+     */
+    public static final int TYPE_HSV = 7;
+
+    /**
+     * The Constant TYPE_HLS indicates HLS color space type.
+     */
+    public static final int TYPE_HLS = 8;
+
+    /**
+     * The Constant TYPE_CMYK indicates CMYK color space type.
+     */
+    public static final int TYPE_CMYK = 9;
+
+    /**
+     * The Constant TYPE_CMY indicates CMY color space type.
+     */
+    public static final int TYPE_CMY = 11;
+
+    /**
+     * The Constant TYPE_2CLR indicates color spaces with 2 components.
+     */
+    public static final int TYPE_2CLR = 12;
+
+    /**
+     * The Constant TYPE_3CLR indicates color spaces with 3 components.
+     */
+    public static final int TYPE_3CLR = 13;
+
+    /**
+     * The Constant TYPE_4CLR indicates color spaces with 4 components.
+     */
+    public static final int TYPE_4CLR = 14;
+
+    /**
+     * The Constant TYPE_5CLR indicates color spaces with 5 components.
+     */
+    public static final int TYPE_5CLR = 15;
+
+    /**
+     * The Constant TYPE_6CLR indicates color spaces with 6 components.
+     */
+    public static final int TYPE_6CLR = 16;
+
+    /**
+     * The Constant TYPE_7CLR indicates color spaces with 7 components.
+     */
+    public static final int TYPE_7CLR = 17;
+
+    /**
+     * The Constant TYPE_8CLR indicates color spaces with 8 components.
+     */
+    public static final int TYPE_8CLR = 18;
+
+    /**
+     * The Constant TYPE_9CLR indicates color spaces with 9 components.
+     */
+    public static final int TYPE_9CLR = 19;
+
+    /**
+     * The Constant TYPE_ACLR indicates color spaces with 10 components.
+     */
+    public static final int TYPE_ACLR = 20;
+
+    /**
+     * The Constant TYPE_BCLR indicates color spaces with 11 components.
+     */
+    public static final int TYPE_BCLR = 21;
+
+    /**
+     * The Constant TYPE_CCLR indicates color spaces with 12 components.
+     */
+    public static final int TYPE_CCLR = 22;
+
+    /**
+     * The Constant TYPE_DCLR indicates color spaces with 13 components.
+     */
+    public static final int TYPE_DCLR = 23;
+
+    /**
+     * The Constant TYPE_ECLR indicates color spaces with 14 components.
+     */
+    public static final int TYPE_ECLR = 24;
+
+    /**
+     * The Constant TYPE_FCLR indicates color spaces with 15 components.
+     */
+    public static final int TYPE_FCLR = 25;
+
+    /**
+     * The Constant CS_sRGB indicates standard RGB color space.
+     */
+    public static final int CS_sRGB = 1000;
+
+    /**
+     * The Constant CS_LINEAR_RGB indicates linear RGB color space.
+     */
+    public static final int CS_LINEAR_RGB = 1004;
+
+    /**
+     * The Constant CS_CIEXYZ indicates CIEXYZ conversion color space.
+     */
+    public static final int CS_CIEXYZ = 1001;
+
+    /**
+     * The Constant CS_PYCC indicates Photo YCC conversion color space.
+     */
+    public static final int CS_PYCC = 1002;
+
+    /**
+     * The Constant CS_GRAY indicates linear gray scale color space.
+     */
+    public static final int CS_GRAY = 1003;
+
+    /**
+     * The cs_ gray.
+     */
+    private static ColorSpace cs_Gray = null;
+    
+    /**
+     * The cs_ pycc.
+     */
+    private static ColorSpace cs_PYCC = null;
+    
+    /**
+     * The cs_ ciexyz.
+     */
+    private static ColorSpace cs_CIEXYZ = null;
+    
+    /**
+     * The cs_ lrgb.
+     */
+    private static ColorSpace cs_LRGB = null;
+    
+    /**
+     * The cs_s rgb.
+     */
+    private static ColorSpace cs_sRGB = null;
+
+    /**
+     * The type.
+     */
+    private int type;
+    
+    /**
+     * The num components.
+     */
+    private int numComponents;
+
+    /**
+     * Instantiates a ColorSpace with the specified ColorSpace type and number
+     * of components.
+     * 
+     * @param type
+     *            the type of color space.
+     * @param numcomponents
+     *            the number of components.
+     */
+    protected ColorSpace(int type, int numcomponents) {
+        this.numComponents = numcomponents;
+        this.type = type;
+    }
+
+    /**
+     * Gets the name of the component for the specified component index.
+     * 
+     * @param idx
+     *            the index of the component.
+     * @return the name of the component.
+     */
+    public String getName(int idx) {
+        if (idx < 0 || idx > numComponents - 1) {
+            // awt.16A=Invalid component index: {0}
+            throw new IllegalArgumentException(Messages.getString("awt.16A", idx)); //$NON-NLS-1$
+        }
+
+      return "Unnamed color component #" + idx; //$NON-NLS-1$
+    }
+
+    /**
+     * Performs the transformation of a color from this ColorSpace into the RGB
+     * color space.
+     * 
+     * @param colorvalue
+     *            the color value in this ColorSpace.
+     * @return the float array with color components in the RGB color space.
+     */
+    public abstract float[] toRGB(float[] colorvalue);
+
+    /**
+     * Performs the transformation of a color from this ColorSpace into the
+     * CS_CIEXYZ color space.
+     * 
+     * @param colorvalue
+     *            the color value in this ColorSpace.
+     * @return the float array with color components in the CS_CIEXYZ color
+     *         space.
+     */
+    public abstract float[] toCIEXYZ(float[] colorvalue);
+
+    /**
+     * Performs the transformation of a color from the RGB color space into this
+     * ColorSpace.
+     * 
+     * @param rgbvalue
+     *            the float array representing a color in the RGB color space.
+     * @return the float array with the transformed color components.
+     */
+    public abstract float[] fromRGB(float[] rgbvalue);
+
+    /**
+     * Performs the transformation of a color from the CS_CIEXYZ color space
+     * into this ColorSpace.
+     * 
+     * @param colorvalue
+     *            the float array representing a color in the CS_CIEXYZ color
+     *            space.
+     * @return the float array with the transformed color components.
+     */
+    public abstract float[] fromCIEXYZ(float[] colorvalue);
+
+    /**
+     * Gets the minimum normalized color component value for the specified
+     * component.
+     * 
+     * @param component
+     *            the component to determine the minimum value.
+     * @return the minimum normalized value of the component.
+     */
+    public float getMinValue(int component) {
+        if (component < 0 || component > numComponents - 1) {
+            // awt.16A=Invalid component index: {0}
+            throw new IllegalArgumentException(Messages.getString("awt.16A", component)); //$NON-NLS-1$
+        }
+        return 0;
+    }
+
+    /**
+     * Gets the maximum normalized color component value for the specified
+     * component.
+     * 
+     * @param component
+     *            the component to determine the maximum value.
+     * @return the maximum normalized value of the component.
+     */
+    public float getMaxValue(int component) {
+        if (component < 0 || component > numComponents - 1) {
+            // awt.16A=Invalid component index: {0}
+            throw new IllegalArgumentException(Messages.getString("awt.16A", component)); //$NON-NLS-1$
+        }
+        return 1;
+    }
+
+    /**
+     * Checks if this ColorSpace has CS_sRGB type or not.
+     * 
+     * @return true, if this ColorSpace has CS_sRGB type, false otherwise.
+     */
+    public boolean isCS_sRGB() {
+        // If our color space is sRGB, then cs_sRGB
+        // is already initialized
+        return (this == cs_sRGB);
+    }
+
+    /**
+     * Gets the type of the ColorSpace.
+     * 
+     * @return the type of the ColorSpace.
+     */
+    public int getType() {
+        return type;
+    }
+
+    /**
+     * Gets the number of components for this ColorSpace.
+     * 
+     * @return the number of components.
+     */
+    public int getNumComponents() {
+        return numComponents;
+    }
+
+
+    /**
+     * Gets the single instance of ColorSpace with the specified ColorSpace:
+     * CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ, CS_GRAY, or CS_PYCC.
+     * 
+     * @param colorspace
+     *            the identifier of the specified Colorspace.
+     * @return the single instance of the desired ColorSpace.
+     */
+    public static ColorSpace getInstance(int colorspace) {
+        switch (colorspace) {
+            case CS_sRGB:
+                if (cs_sRGB == null) {
+                    cs_sRGB = new ICC_ColorSpace(
+                            new ICC_ProfileStub(CS_sRGB));
+                    LUTColorConverter.sRGB_CS = cs_sRGB;
+                            //ICC_Profile.getInstance (CS_sRGB));
+                }
+                return cs_sRGB;
+            case CS_CIEXYZ:
+                if (cs_CIEXYZ == null) {
+                    cs_CIEXYZ = new ICC_ColorSpace(
+                            new ICC_ProfileStub(CS_CIEXYZ));
+                            //ICC_Profile.getInstance (CS_CIEXYZ));
+                }
+                return cs_CIEXYZ;
+            case CS_GRAY:
+                if (cs_Gray == null) {
+                    cs_Gray = new ICC_ColorSpace(
+                            new ICC_ProfileStub(CS_GRAY));
+                    LUTColorConverter.LINEAR_GRAY_CS = cs_Gray;
+                            //ICC_Profile.getInstance (CS_GRAY));
+                }
+                return cs_Gray;
+            case CS_PYCC:
+                if (cs_PYCC == null) {
+                    cs_PYCC = new ICC_ColorSpace(
+                            new ICC_ProfileStub(CS_PYCC));
+                            //ICC_Profile.getInstance (CS_PYCC));
+                }
+                return cs_PYCC;
+            case CS_LINEAR_RGB:
+                if (cs_LRGB == null) {
+                    cs_LRGB = new ICC_ColorSpace(
+                            new ICC_ProfileStub(CS_LINEAR_RGB));
+                    LUTColorConverter.LINEAR_GRAY_CS = cs_Gray;
+                            //ICC_Profile.getInstance (CS_LINEAR_RGB));
+                }
+                return cs_LRGB;
+            default:
+        }
+
+        // Unknown argument passed
+        // awt.16B=Not a predefined colorspace
+        throw new IllegalArgumentException(Messages.getString("Not a predefined colorspace")); //$NON-NLS-1$
+    }
+
+}
\ No newline at end of file
diff --git a/awt/java/awt/color/ICC_ColorSpace.java b/awt/java/awt/color/ICC_ColorSpace.java
new file mode 100644
index 0000000..5b4d7e9
--- /dev/null
+++ b/awt/java/awt/color/ICC_ColorSpace.java
@@ -0,0 +1,468 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+import org.apache.harmony.awt.gl.color.ColorConverter;
+import org.apache.harmony.awt.gl.color.ColorScaler;
+import org.apache.harmony.awt.gl.color.ICC_Transform;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+import java.io.*;
+
+/**
+ * This class implements the abstract class ColorSpace and represents device
+ * independent and device dependent color spaces. This color space is based on
+ * the International Color Consortium Specification (ICC) File Format for Color
+ * Profiles: <a href="http://www.color.org">http://www.color.org</a>
+ * 
+ * @since Android 1.0
+ */
+public class ICC_ColorSpace extends ColorSpace {
+    
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 3455889114070431483L;
+
+    // Need to keep compatibility with serialized form
+    /**
+     * The Constant serialPersistentFields.
+     */
+    private static final ObjectStreamField[]
+      serialPersistentFields = {
+        new ObjectStreamField("thisProfile", ICC_Profile.class), //$NON-NLS-1$
+        new ObjectStreamField("minVal", float[].class), //$NON-NLS-1$
+        new ObjectStreamField("maxVal", float[].class), //$NON-NLS-1$
+        new ObjectStreamField("diffMinMax", float[].class), //$NON-NLS-1$
+        new ObjectStreamField("invDiffMinMax", float[].class), //$NON-NLS-1$
+        new ObjectStreamField("needScaleInit", Boolean.TYPE) //$NON-NLS-1$
+    };
+
+
+   /**
+     * According to ICC specification (from http://www.color.org) "For the
+     * CIEXYZ encoding, each component (X, Y, and Z) is encoded as a
+     * u1Fixed15Number". This means that max value for this encoding is 1 +
+     * (32767/32768)
+     */
+    private static final float MAX_XYZ = 1f + (32767f/32768f);
+    
+    /**
+     * The Constant MAX_SHORT.
+     */
+    private static final float MAX_SHORT = 65535f;
+    
+    /**
+     * The Constant INV_MAX_SHORT.
+     */
+    private static final float INV_MAX_SHORT = 1f/MAX_SHORT;
+    
+    /**
+     * The Constant SHORT2XYZ_FACTOR.
+     */
+    private static final float SHORT2XYZ_FACTOR = MAX_XYZ/MAX_SHORT;
+    
+    /**
+     * The Constant XYZ2SHORT_FACTOR.
+     */
+    private static final float XYZ2SHORT_FACTOR = MAX_SHORT/MAX_XYZ;
+
+    /**
+     * The profile.
+     */
+    private ICC_Profile profile = null;
+    
+    /**
+     * The min values.
+     */
+    private float minValues[] = null;
+    
+    /**
+     * The max values.
+     */
+    private float maxValues[] = null;
+
+    // cache transforms here - performance gain
+    /**
+     * The to rgb transform.
+     */
+    private ICC_Transform toRGBTransform = null;
+    
+    /**
+     * The from rgb transform.
+     */
+    private ICC_Transform fromRGBTransform = null;
+    
+    /**
+     * The to xyz transform.
+     */
+    private ICC_Transform toXYZTransform = null;
+    
+    /**
+     * The from xyz transform.
+     */
+    private ICC_Transform fromXYZTransform = null;
+
+    /**
+     * The converter.
+     */
+    private final ColorConverter converter = new ColorConverter();
+    
+    /**
+     * The scaler.
+     */
+    private final ColorScaler scaler = new ColorScaler();
+    
+    /**
+     * The scaling data loaded.
+     */
+    private boolean scalingDataLoaded = false;
+
+    /**
+     * The resolved deserialized inst.
+     */
+    private ICC_ColorSpace resolvedDeserializedInst;
+
+    /**
+     * Instantiates a new ICC color space from an ICC_Profile object.
+     * 
+     * @param pf
+     *            the ICC_Profile object.
+     */
+    public ICC_ColorSpace(ICC_Profile pf) {
+        super(pf.getColorSpaceType(), pf.getNumComponents());
+
+        int pfClass = pf.getProfileClass();
+
+        switch (pfClass) {
+            case ICC_Profile.CLASS_COLORSPACECONVERSION:
+            case ICC_Profile.CLASS_DISPLAY:
+            case ICC_Profile.CLASS_OUTPUT:
+            case ICC_Profile.CLASS_INPUT:
+                break; // OK, it is color conversion profile
+            default:
+                // awt.168=Invalid profile class.
+                throw new IllegalArgumentException(Messages.getString("awt.168")); //$NON-NLS-1$
+        }
+
+        profile = pf;
+        fillMinMaxValues();
+    }
+
+    /**
+     * Gets the ICC_Profile for this ICC_ColorSpace.
+     * 
+     * @return the ICC_Profile for this ICC_ColorSpace.
+     */
+    public ICC_Profile getProfile() {
+        if (profile instanceof ICC_ProfileStub) {
+            profile = ((ICC_ProfileStub) profile).loadProfile();
+        }
+
+        return profile;
+    }
+
+    /**
+     * Performs the transformation of a color from this ColorSpace into the RGB
+     * color space.
+     * 
+     * @param colorvalue
+     *            the color value in this ColorSpace.
+     * @return the float array with color components in the RGB color space.
+     */
+    @Override
+    public float[] toRGB(float[] colorvalue) {
+        if (toRGBTransform == null) {
+            ICC_Profile sRGBProfile =
+                ((ICC_ColorSpace) ColorSpace.getInstance(CS_sRGB)).getProfile();
+            ICC_Profile[] profiles = {getProfile(), sRGBProfile};
+            toRGBTransform = new ICC_Transform(profiles);
+            if (!scalingDataLoaded) {
+                scaler.loadScalingData(this);
+                scalingDataLoaded = true;
+            }
+        }
+
+        short[] data = new short[getNumComponents()];
+
+        scaler.scale(colorvalue, data, 0);
+
+        short[] converted =
+            converter.translateColor(toRGBTransform, data, null);
+
+        // unscale to sRGB
+        float[] res = new float[3];
+
+        res[0] = ((converted[0] & 0xFFFF)) * INV_MAX_SHORT;
+        res[1] = ((converted[1] & 0xFFFF)) * INV_MAX_SHORT;
+        res[2] = ((converted[2] & 0xFFFF)) * INV_MAX_SHORT;
+
+        return res;
+    }
+
+    /**
+     * Performs the transformation of a color from this ColorSpace into the
+     * CS_CIEXYZ color space.
+     * 
+     * @param colorvalue
+     *            the color value in this ColorSpace.
+     * @return the float array with color components in the CS_CIEXYZ color
+     *         space.
+     */
+    @Override
+    public float[] toCIEXYZ(float[] colorvalue) {
+        if (toXYZTransform == null) {
+            ICC_Profile xyzProfile =
+                ((ICC_ColorSpace) ColorSpace.getInstance(CS_CIEXYZ)).getProfile();
+            ICC_Profile[] profiles = {getProfile(), xyzProfile};
+            try {
+                int[] intents = {
+                        ICC_Profile.icRelativeColorimetric,
+                        ICC_Profile.icPerceptual};
+                toXYZTransform = new ICC_Transform(profiles, intents);
+            } catch (CMMException e) { // No such tag, use what we can
+                toXYZTransform = new ICC_Transform(profiles);
+            }
+
+            if (!scalingDataLoaded) {
+                scaler.loadScalingData(this);
+                scalingDataLoaded = true;
+            }
+        }
+
+        short[] data = new short[getNumComponents()];
+
+        scaler.scale(colorvalue, data, 0);
+
+        short[] converted =
+            converter.translateColor(toXYZTransform, data, null);
+
+        // unscale to XYZ
+        float[] res = new float[3];
+
+        res[0] = ((converted[0] & 0xFFFF)) * SHORT2XYZ_FACTOR;
+        res[1] = ((converted[1] & 0xFFFF)) * SHORT2XYZ_FACTOR;
+        res[2] = ((converted[2] & 0xFFFF)) * SHORT2XYZ_FACTOR;
+
+        return res;
+    }
+
+    /**
+     * Performs the transformation of a color from the RGB color space into this
+     * ColorSpace.
+     * 
+     * @param rgbvalue
+     *            the float array representing a color in the RGB color space.
+     * @return the float array with the transformed color components.
+     */
+    @Override
+    public float[] fromRGB(float[] rgbvalue) {
+        if (fromRGBTransform == null) {
+            ICC_Profile sRGBProfile =
+                ((ICC_ColorSpace) ColorSpace.getInstance(CS_sRGB)).getProfile();
+            ICC_Profile[] profiles = {sRGBProfile, getProfile()};
+            fromRGBTransform = new ICC_Transform(profiles);
+            if (!scalingDataLoaded) {
+                scaler.loadScalingData(this);
+                scalingDataLoaded = true;
+            }
+        }
+
+        // scale rgb value to short
+        short[] scaledRGBValue = new short[3];
+        scaledRGBValue[0] = (short)(rgbvalue[0] * MAX_SHORT + 0.5f);
+        scaledRGBValue[1] = (short)(rgbvalue[1] * MAX_SHORT + 0.5f);
+        scaledRGBValue[2] = (short)(rgbvalue[2] * MAX_SHORT + 0.5f);
+
+        short[] converted =
+            converter.translateColor(fromRGBTransform, scaledRGBValue, null);
+
+        float[] res = new float[getNumComponents()];
+
+        scaler.unscale(res, converted, 0);
+
+        return res;
+    }
+
+    /**
+     * Performs the transformation of a color from the CS_CIEXYZ color space
+     * into this ColorSpace.
+     * 
+     * @param xyzvalue
+     *            the float array representing a color in the CS_CIEXYZ color
+     *            space.
+     * @return the float array with the transformed color components.
+     */
+    @Override
+    public float[] fromCIEXYZ(float[] xyzvalue) {
+        if (fromXYZTransform == null) {
+            ICC_Profile xyzProfile =
+                ((ICC_ColorSpace) ColorSpace.getInstance(CS_CIEXYZ)).getProfile();
+            ICC_Profile[] profiles = {xyzProfile, getProfile()};
+            try {
+                int[] intents = {
+                        ICC_Profile.icPerceptual,
+                        ICC_Profile.icRelativeColorimetric};
+                fromXYZTransform = new ICC_Transform(profiles, intents);
+            } catch (CMMException e) { // No such tag, use what we can
+                fromXYZTransform = new ICC_Transform(profiles);
+            }
+
+            if (!scalingDataLoaded) {
+                scaler.loadScalingData(this);
+                scalingDataLoaded = true;
+            }
+
+        }
+
+        // scale xyz value to short
+        short[] scaledXYZValue = new short[3];
+        scaledXYZValue[0] = (short)(xyzvalue[0] * XYZ2SHORT_FACTOR + 0.5f);
+        scaledXYZValue[1] = (short)(xyzvalue[1] * XYZ2SHORT_FACTOR + 0.5f);
+        scaledXYZValue[2] = (short)(xyzvalue[2] * XYZ2SHORT_FACTOR + 0.5f);
+
+        short[] converted =
+            converter.translateColor(fromXYZTransform, scaledXYZValue, null);
+
+        float[] res = new float[getNumComponents()];
+
+        scaler.unscale(res, converted, 0);
+
+        return res;
+    }
+
+    /**
+     * Gets the minimum normalized color component value for the specified
+     * component.
+     * 
+     * @param component
+     *            the component to determine the minimum value.
+     * @return the minimum normalized value of the component.
+     */
+    @Override
+    public float getMinValue(int component) {
+        if ((component < 0) || (component > this.getNumComponents() - 1)) {
+            // awt.169=Component index out of range
+            throw new IllegalArgumentException(Messages.getString("awt.169")); //$NON-NLS-1$
+        }
+
+        return minValues[component];
+    }
+
+    /**
+     * Gets the maximum normalized color component value for the specified
+     * component.
+     * 
+     * @param component
+     *            the component to determine the maximum value.
+     * @return the maximum normalized value of the component.
+     */
+    @Override
+    public float getMaxValue(int component) {
+        if ((component < 0) || (component > this.getNumComponents() - 1)) {
+            // awt.169=Component index out of range
+            throw new IllegalArgumentException(Messages.getString("awt.169")); //$NON-NLS-1$
+        }
+
+        return maxValues[component];
+    }
+
+    /**
+     * Fill min max values.
+     */
+    private void fillMinMaxValues() {
+        int n = getNumComponents();
+        maxValues = new float[n];
+        minValues = new float[n];
+        switch (getType()) {
+            case ColorSpace.TYPE_XYZ:
+                minValues[0] = 0;
+                minValues[1] = 0;
+                minValues[2] = 0;
+                maxValues[0] = MAX_XYZ;
+                maxValues[1] = MAX_XYZ;
+                maxValues[2] = MAX_XYZ;
+                break;
+            case ColorSpace.TYPE_Lab:
+                minValues[0] = 0;
+                minValues[1] = -128;
+                minValues[2] = -128;
+                maxValues[0] = 100;
+                maxValues[1] = 127;
+                maxValues[2] = 127;
+                break;
+            default:
+                for(int i=0; i<n; i++) {
+                    minValues[i] = 0;
+                    maxValues[i] = 1;
+                }
+        }
+    }
+
+    /**
+     * Write object.
+     * 
+     * @param out
+     *            the out
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        ObjectOutputStream.PutField fields = out.putFields();
+
+        fields.put("thisProfile", profile); //$NON-NLS-1$
+        fields.put("minVal", null); //$NON-NLS-1$
+        fields.put("maxVal", null); //$NON-NLS-1$
+        fields.put("diffMinMax", null); //$NON-NLS-1$
+        fields.put("invDiffMinMax", null); //$NON-NLS-1$
+        fields.put("needScaleInit", true); //$NON-NLS-1$
+
+        out.writeFields();
+    }
+
+    /**
+     * Read object.
+     * 
+     * @param in
+     *            the in
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     * @throws ClassNotFoundException
+     *             the class not found exception
+     */
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        ObjectInputStream.GetField fields = in.readFields();
+        resolvedDeserializedInst =
+                new ICC_ColorSpace((ICC_Profile) fields.get("thisProfile", null)); //$NON-NLS-1$
+    }
+
+    /**
+     * Read resolve.
+     * 
+     * @return the object
+     * @throws ObjectStreamException
+     *             the object stream exception
+     */
+    Object readResolve() throws ObjectStreamException {
+        return resolvedDeserializedInst;
+    }
+}
+
diff --git a/awt/java/awt/color/ICC_Profile.java b/awt/java/awt/color/ICC_Profile.java
new file mode 100644
index 0000000..8ffee6c
--- /dev/null
+++ b/awt/java/awt/color/ICC_Profile.java
@@ -0,0 +1,1477 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.color;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.StringTokenizer;
+
+import org.apache.harmony.awt.gl.color.ICC_ProfileHelper;
+import org.apache.harmony.awt.gl.color.NativeCMM;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ICC_Profile class represents a color profile data for color spaces based
+ * on the International Color Consortium Specification ICC.1:2001-12, File
+ * Format for Color Profiles.
+ * 
+ * @since Android 1.0
+ */
+public class ICC_Profile implements Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -3938515861990936766L;
+
+    // NOTE: Constant field values are noted in 1.5 specification.
+
+    /**
+     * The Constant CLASS_INPUT indicates that profile class is input.
+     */
+    public static final int CLASS_INPUT = 0;
+
+    /**
+     * The Constant CLASS_DISPLAY indicates that profile class is display.
+     */
+    public static final int CLASS_DISPLAY = 1;
+
+    /**
+     * The Constant CLASS_OUTPUT indicates that profile class is output.
+     */
+    public static final int CLASS_OUTPUT = 2;
+
+    /**
+     * The Constant CLASS_DEVICELINK indicates that profile class is device
+     * link.
+     */
+    public static final int CLASS_DEVICELINK = 3;
+
+    /**
+     * The Constant CLASS_COLORSPACECONVERSION indicates that profile class is
+     * color space conversion.
+     */
+    public static final int CLASS_COLORSPACECONVERSION = 4;
+
+    /**
+     * The Constant CLASS_ABSTRACT indicates that profile class is abstract.
+     */
+    public static final int CLASS_ABSTRACT = 5;
+
+    /**
+     * The Constant CLASS_NAMEDCOLOR indicates that profile class is named
+     * color.
+     */
+    public static final int CLASS_NAMEDCOLOR = 6;
+
+    /**
+     * The Constant icSigXYZData - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigXYZData = 1482250784;
+
+    /**
+     * The Constant icSigLabData - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigLabData = 1281450528;
+
+    /**
+     * The Constant icSigLuvData - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigLuvData = 1282766368;
+
+    /**
+     * The Constant icSigYCbCrData - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigYCbCrData = 1497588338;
+
+    /**
+     * The Constant icSigYxyData - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigYxyData = 1501067552;
+
+    /**
+     * The Constant icSigRgbData - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigRgbData = 1380401696;
+
+    /**
+     * The Constant icSigGrayData - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigGrayData = 1196573017;
+
+    /**
+     * The Constant icSigHsvData - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigHsvData = 1213421088;
+
+    /**
+     * The Constant icSigHlsData - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigHlsData = 1212961568;
+
+    /**
+     * The Constant icSigCmykData - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigCmykData = 1129142603;
+
+    /**
+     * The Constant icSigCmyData - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigCmyData = 1129142560;
+
+    /**
+     * The Constant icSigSpace2CLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpace2CLR = 843271250;
+
+    /**
+     * The Constant icSigSpace3CLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpace3CLR = 860048466;
+
+    /**
+     * The Constant icSigSpace4CLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpace4CLR = 876825682;
+
+    /**
+     * The Constant icSigSpace5CLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpace5CLR = 893602898;
+
+    /**
+     * The Constant icSigSpace6CLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpace6CLR = 910380114;
+
+    /**
+     * The Constant icSigSpace7CLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpace7CLR = 927157330;
+
+    /**
+     * The Constant icSigSpace8CLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpace8CLR = 943934546;
+
+    /**
+     * The Constant icSigSpace9CLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpace9CLR = 960711762;
+
+    /**
+     * The Constant icSigSpaceACLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpaceACLR = 1094929490;
+
+    /**
+     * The Constant icSigSpaceBCLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpaceBCLR = 1111706706;
+
+    /**
+     * The Constant icSigSpaceCCLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpaceCCLR = 1128483922;
+
+    /**
+     * The Constant icSigSpaceDCLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpaceDCLR = 1145261138;
+
+    /**
+     * The Constant icSigSpaceECLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpaceECLR = 1162038354;
+
+    /**
+     * The Constant icSigSpaceFCLR - ICC Profile Color Space Type Signature.
+     */
+    public static final int icSigSpaceFCLR = 1178815570;
+
+    /**
+     * The Constant icSigInputClass - ICC Profile Class Signature.
+     */
+    public static final int icSigInputClass = 1935896178;
+
+    /**
+     * The Constant icSigDisplayClass - ICC Profile Class Signature.
+     */
+    public static final int icSigDisplayClass = 1835955314;
+
+    /**
+     * The Constant icSigOutputClass - ICC Profile Class Signature.
+     */
+    public static final int icSigOutputClass = 1886549106;
+
+    /**
+     * The Constant icSigLinkClass - ICC Profile Class Signature.
+     */
+    public static final int icSigLinkClass = 1818848875;
+
+    /**
+     * The Constant icSigAbstractClass - ICC Profile Class Signature.
+     */
+    public static final int icSigAbstractClass = 1633842036;
+
+    /**
+     * The Constant icSigColorantOrderTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigColorantOrderTag = 1668051567;
+
+    /**
+     * The Constant icSigColorantTableTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigColorantTableTag = 1668051572;
+
+    /**
+     * The Constant icSigColorSpaceClass - ICC Profile Tag Signature.
+     */
+    public static final int icSigColorSpaceClass = 1936744803;
+
+    /**
+     * The Constant icSigNamedColorClass - ICC Profile Tag Signature.
+     */
+    public static final int icSigNamedColorClass = 1852662636;
+
+    /**
+     * The Constant icPerceptual - ICC Profile Rendering Intent.
+     */
+    public static final int icPerceptual = 0;
+
+    /**
+     * The Constant icRelativeColorimetric - ICC Profile Rendering Intent.
+     */
+    public static final int icRelativeColorimetric = 1;
+
+    /**
+     * The Constant icSaturation - ICC Profile Rendering Intent.
+     */
+    public static final int icSaturation = 2;
+
+    /**
+     * The Constant icAbsoluteColorimetric - ICC Profile Rendering Intent.
+     */
+    public static final int icAbsoluteColorimetric = 3;
+
+    /**
+     * The Constant icSigHead - ICC Profile Tag Signature.
+     */
+    public static final int icSigHead = 1751474532;
+
+    /**
+     * The Constant icSigAToB0Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigAToB0Tag = 1093812784;
+
+    /**
+     * The Constant icSigAToB1Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigAToB1Tag = 1093812785;
+
+    /**
+     * The Constant icSigAToB2Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigAToB2Tag = 1093812786;
+
+    /**
+     * The Constant icSigBlueColorantTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigBlueColorantTag = 1649957210;
+
+    /**
+     * The Constant icSigBlueMatrixColumnTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigBlueMatrixColumnTag = 1649957210;
+
+    /**
+     * The Constant icSigBlueTRCTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigBlueTRCTag = 1649693251;
+
+    /**
+     * The Constant icSigBToA0Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigBToA0Tag = 1110589744;
+
+    /**
+     * The Constant icSigBToA1Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigBToA1Tag = 1110589745;
+
+    /**
+     * The Constant icSigBToA2Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigBToA2Tag = 1110589746;
+
+    /**
+     * The Constant icSigCalibrationDateTimeTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigCalibrationDateTimeTag = 1667329140;
+
+    /**
+     * The Constant icSigCharTargetTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigCharTargetTag = 1952543335;
+
+    /**
+     * The Constant icSigCopyrightTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigCopyrightTag = 1668313716;
+
+    /**
+     * The Constant icSigCrdInfoTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigCrdInfoTag = 1668441193;
+
+    /**
+     * The Constant icSigDeviceMfgDescTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigDeviceMfgDescTag = 1684893284;
+
+    /**
+     * The Constant icSigDeviceModelDescTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigDeviceModelDescTag = 1684890724;
+
+    /**
+     * The Constant icSigDeviceSettingsTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigDeviceSettingsTag = 1684371059;
+
+    /**
+     * The Constant icSigGamutTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigGamutTag = 1734438260;
+
+    /**
+     * The Constant icSigGrayTRCTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigGrayTRCTag = 1800688195;
+
+    /**
+     * The Constant icSigGreenColorantTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigGreenColorantTag = 1733843290;
+
+    /**
+     * The Constant icSigGreenMatrixColumnTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigGreenMatrixColumnTag = 1733843290;
+
+    /**
+     * The Constant icSigGreenTRCTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigGreenTRCTag = 1733579331;
+
+    /**
+     * The Constant icSigLuminanceTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigLuminanceTag = 1819635049;
+
+    /**
+     * The Constant icSigMeasurementTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigMeasurementTag = 1835360627;
+
+    /**
+     * The Constant icSigMediaBlackPointTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigMediaBlackPointTag = 1651208308;
+
+    /**
+     * The Constant icSigMediaWhitePointTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigMediaWhitePointTag = 2004119668;
+
+    /**
+     * The Constant icSigNamedColor2Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigNamedColor2Tag = 1852009522;
+
+    /**
+     * The Constant icSigOutputResponseTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigOutputResponseTag = 1919251312;
+
+    /**
+     * The Constant icSigPreview0Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigPreview0Tag = 1886545200;
+
+    /**
+     * The Constant icSigPreview1Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigPreview1Tag = 1886545201;
+
+    /**
+     * The Constant icSigPreview2Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigPreview2Tag = 1886545202;
+
+    /**
+     * The Constant icSigProfileDescriptionTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigProfileDescriptionTag = 1684370275;
+
+    /**
+     * The Constant icSigProfileSequenceDescTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigProfileSequenceDescTag = 1886610801;
+
+    /**
+     * The Constant icSigPs2CRD0Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigPs2CRD0Tag = 1886610480;
+
+    /**
+     * The Constant icSigPs2CRD1Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigPs2CRD1Tag = 1886610481;
+
+    /**
+     * The Constant icSigPs2CRD2Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigPs2CRD2Tag = 1886610482;
+
+    /**
+     * The Constant icSigPs2CRD3Tag - ICC Profile Tag Signature.
+     */
+    public static final int icSigPs2CRD3Tag = 1886610483;
+
+    /**
+     * The Constant icSigPs2CSATag - ICC Profile Tag Signature.
+     */
+    public static final int icSigPs2CSATag = 1886597747;
+
+    /**
+     * The Constant icSigPs2RenderingIntentTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigPs2RenderingIntentTag = 1886597737;
+
+    /**
+     * The Constant icSigRedColorantTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigRedColorantTag = 1918392666;
+
+    /**
+     * The Constant icSigRedMatrixColumnTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigRedMatrixColumnTag = 1918392666;
+
+    /**
+     * The Constant icSigRedTRCTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigRedTRCTag = 1918128707;
+
+    /**
+     * The Constant icSigScreeningDescTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigScreeningDescTag = 1935897188;
+
+    /**
+     * The Constant icSigScreeningTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigScreeningTag = 1935897198;
+
+    /**
+     * The Constant icSigTechnologyTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigTechnologyTag = 1952801640;
+
+    /**
+     * The Constant icSigUcrBgTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigUcrBgTag = 1650877472;
+
+    /**
+     * The Constant icSigViewingCondDescTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigViewingCondDescTag = 1987405156;
+
+    /**
+     * The Constant icSigViewingConditionsTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigViewingConditionsTag = 1986618743;
+
+    /**
+     * The Constant icSigChromaticAdaptationTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigChromaticAdaptationTag = 1667785060;
+
+    /**
+     * The Constant icSigChromaticityTag - ICC Profile Tag Signature.
+     */
+    public static final int icSigChromaticityTag = 1667789421;
+
+    /**
+     * The Constant icHdrSize - ICC Profile Header Location.
+     */
+    public static final int icHdrSize = 0;
+
+    /**
+     * The Constant icHdrCmmId - ICC Profile Header Location.
+     */
+    public static final int icHdrCmmId = 4;
+
+    /**
+     * The Constant icHdrVersion - ICC Profile Header Location.
+     */
+    public static final int icHdrVersion = 8;
+
+    /**
+     * The Constant icHdrDeviceClass - ICC Profile Header Location.
+     */
+    public static final int icHdrDeviceClass = 12;
+
+    /**
+     * The Constant icHdrColorSpace - ICC Profile Header Location.
+     */
+    public static final int icHdrColorSpace = 16;
+
+    /**
+     * The Constant icHdrPcs - ICC Profile Header Location.
+     */
+    public static final int icHdrPcs = 20;
+
+    /**
+     * The Constant icHdrDate - ICC Profile Header Location.
+     */
+    public static final int icHdrDate = 24;
+
+    /**
+     * The Constant icHdrMagic - ICC Profile Header Location.
+     */
+    public static final int icHdrMagic = 36;
+
+    /**
+     * The Constant icHdrPlatform - ICC Profile Header Location.
+     */
+    public static final int icHdrPlatform = 40;
+
+    /**
+     * The Constant icHdrProfileID - ICC Profile Header Location.
+     */
+    public static final int icHdrProfileID = 84;
+
+    /**
+     * The Constant icHdrFlags - ICC Profile Header Location.
+     */
+    public static final int icHdrFlags = 44;
+
+    /**
+     * The Constant icHdrManufacturer - ICC Profile Header Location.
+     */
+    public static final int icHdrManufacturer = 48;
+
+    /**
+     * The Constant icHdrModel - ICC Profile Header Location.
+     */
+    public static final int icHdrModel = 52;
+
+    /**
+     * The Constant icHdrAttributes - ICC Profile Header Location.
+     */
+    public static final int icHdrAttributes = 56;
+
+    /**
+     * The Constant icHdrRenderingIntent - ICC Profile Header Location.
+     */
+    public static final int icHdrRenderingIntent = 64;
+
+    /**
+     * The Constant icHdrIlluminant - ICC Profile Header Location.
+     */
+    public static final int icHdrIlluminant = 68;
+
+    /**
+     * The Constant icHdrCreator - ICC Profile Header Location.
+     */
+    public static final int icHdrCreator = 80;
+
+    /**
+     * The Constant icICCAbsoluteColorimetric - ICC Profile Rendering Intent.
+     */
+    public static final int icICCAbsoluteColorimetric = 3;
+
+    /**
+     * The Constant icMediaRelativeColorimetric - ICC Profile Rendering Intent.
+     */
+    public static final int icMediaRelativeColorimetric = 1;
+
+    /**
+     * The Constant icTagType - ICC Profile Constant.
+     */
+    public static final int icTagType = 0;
+
+    /**
+     * The Constant icTagReserved - ICC Profile Constant.
+     */
+    public static final int icTagReserved = 4;
+
+    /**
+     * The Constant icCurveCount - ICC Profile Constant.
+     */
+    public static final int icCurveCount = 8;
+
+    /**
+     * The Constant icCurveData - ICC Profile Constant.
+     */
+    public static final int icCurveData = 12;
+
+    /**
+     * The Constant icXYZNumberX - ICC Profile Constant.
+     */
+    public static final int icXYZNumberX = 8;
+
+    /**
+     * Size of a profile header.
+     */
+    private static final int headerSize = 128;
+
+    /**
+     * header magic number.
+     */
+    private static final int headerMagicNumber = 0x61637370;
+
+    // Cache of predefined profiles
+    /**
+     * The s rgb profile.
+     */
+    private static ICC_Profile sRGBProfile;
+
+    /**
+     * The xyz profile.
+     */
+    private static ICC_Profile xyzProfile;
+
+    /**
+     * The gray profile.
+     */
+    private static ICC_Profile grayProfile;
+
+    /**
+     * The pycc profile.
+     */
+    private static ICC_Profile pyccProfile;
+
+    /**
+     * The linear rgb profile.
+     */
+    private static ICC_Profile linearRGBProfile;
+
+    /**
+     * Handle to the current profile.
+     */
+    private transient long profileHandle = 0;
+
+    /**
+     * If handle is used by another class this object is not responsible for
+     * closing profile.
+     */
+    private transient boolean handleStolen = false;
+
+    /**
+     * Cached header data.
+     */
+    private transient byte[] headerData = null;
+
+    /**
+     * Serialization support.
+     */
+    private transient ICC_Profile openedProfileObject;
+
+    /**
+     * Instantiates a new ICC profile with the given data.
+     * 
+     * @param data
+     *            the data.
+     */
+    private ICC_Profile(byte[] data) {
+        profileHandle = NativeCMM.cmmOpenProfile(data);
+        NativeCMM.addHandle(this, profileHandle);
+    }
+
+    /**
+     * Used to instantiate dummy ICC_ProfileStub objects.
+     */
+    ICC_Profile() {
+    }
+
+    /**
+     * Used to instantiate subclasses (ICC_ProfileGrey and ICC_ProfileRGB).
+     * 
+     * @param profileHandle
+     *            - should be valid handle to opened color profile
+     */
+    ICC_Profile(long profileHandle) {
+        this.profileHandle = profileHandle;
+        // A new object reference, need to add it.
+        NativeCMM.addHandle(this, profileHandle);
+    }
+
+    /**
+     * Writes the ICC_Profile to a file with the specified name.
+     * 
+     * @param fileName
+     *            the file name.
+     * @throws IOException
+     *             if an I/O exception has occurred during writing or opening
+     *             the file.
+     */
+    public void write(String fileName) throws IOException {
+        FileOutputStream oStream = new FileOutputStream(fileName);
+        oStream.write(getData());
+        oStream.close();
+    }
+
+    /**
+     * Serializable implementation.
+     * 
+     * @param s
+     *            the s
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     */
+    private void writeObject(ObjectOutputStream s) throws IOException {
+        s.defaultWriteObject();
+        s.writeObject(null);
+        s.writeObject(getData());
+    }
+
+    /**
+     * Serializable implementation.
+     * 
+     * @param s
+     *            the s
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     * @throws ClassNotFoundException
+     *             the class not found exception
+     */
+    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        String colorSpaceStr = (String)s.readObject();
+        byte[] data = (byte[])s.readObject();
+
+        if (colorSpaceStr != null) {
+            if (colorSpaceStr.equals("CS_sRGB")) { //$NON-NLS-1$
+                openedProfileObject = getInstance(ColorSpace.CS_sRGB);
+            } else if (colorSpaceStr.equals("CS_GRAY")) { //$NON-NLS-1$
+                openedProfileObject = getInstance(ColorSpace.CS_GRAY);
+            } else if (colorSpaceStr.equals("CS_LINEAR_RGB")) { //$NON-NLS-1$
+                openedProfileObject = getInstance(ColorSpace.CS_LINEAR_RGB);
+            } else if (colorSpaceStr.equals("CS_CIEXYZ")) { //$NON-NLS-1$
+                openedProfileObject = getInstance(ColorSpace.CS_CIEXYZ);
+            } else if (colorSpaceStr.equals("CS_PYCC")) { //$NON-NLS-1$
+                openedProfileObject = getInstance(ColorSpace.CS_PYCC);
+            } else {
+                openedProfileObject = ICC_Profile.getInstance(data);
+            }
+        } else {
+            openedProfileObject = ICC_Profile.getInstance(data);
+        }
+    }
+
+    /**
+     * Resolves instances being deserialized into instances registered with CMM.
+     * 
+     * @return ICC_Profile object for profile registered with CMM.
+     * @throws ObjectStreamException
+     *             if there is an error in the serialized files or during the
+     *             process of reading them.
+     */
+    protected Object readResolve() throws ObjectStreamException {
+        return openedProfileObject;
+    }
+
+    /**
+     * Writes the ICC_Profile to an OutputStream.
+     * 
+     * @param s
+     *            the OutputStream.
+     * @throws IOException
+     *             signals that an I/O exception has occurred during writing or
+     *             opening OutputStream.
+     */
+    public void write(OutputStream s) throws IOException {
+        s.write(getData());
+    }
+
+    /**
+     * Sets a tagged data element in the profile from a byte array.
+     * 
+     * @param tagSignature
+     *            the ICC tag signature for the data element to be set.
+     * @param tagData
+     *            the data to be set for the specified tag signature.
+     */
+    public void setData(int tagSignature, byte[] tagData) {
+        NativeCMM.cmmSetProfileElement(profileHandle, tagSignature, tagData);
+        // Remove cached header data if header is modified
+        if (tagSignature == icSigHead) {
+            headerData = null;
+        }
+    }
+
+    /**
+     * Gets a tagged data element from the profile as a byte array. Elements are
+     * identified by tag signatures as defined in the ICC specification.
+     * 
+     * @param tagSignature
+     *            the ICC tag signature for the data element to get.
+     * @return a byte array that contains the tagged data element.
+     */
+    public byte[] getData(int tagSignature) {
+        int tagSize = 0;
+        try {
+            tagSize = NativeCMM.cmmGetProfileElementSize(profileHandle, tagSignature);
+        } catch (CMMException e) {
+            // We'll get this exception if there's no element with
+            // the specified tag signature
+            return null;
+        }
+
+        byte[] data = new byte[tagSize];
+        NativeCMM.cmmGetProfileElement(profileHandle, tagSignature, data);
+        return data;
+    }
+
+    /**
+     * Gets a data byte array of this ICC_Profile.
+     * 
+     * @return a byte array that contains the ICC Profile data.
+     */
+    public byte[] getData() {
+        int profileSize = NativeCMM.cmmGetProfileSize(profileHandle);
+        byte[] data = new byte[profileSize];
+        NativeCMM.cmmGetProfile(profileHandle, data);
+        return data;
+    }
+
+    /**
+     * Frees the resources associated with an ICC_Profile object.
+     */
+    @Override
+    protected void finalize() {
+        if (profileHandle != 0 && !handleStolen) {
+            NativeCMM.cmmCloseProfile(profileHandle);
+        }
+
+        // Always remove because key no more exist
+        // when object is destroyed
+        NativeCMM.removeHandle(this);
+    }
+
+    /**
+     * Gets the profile class.
+     * 
+     * @return the profile class constant.
+     */
+    public int getProfileClass() {
+        int deviceClassSignature = getIntFromHeader(icHdrDeviceClass);
+
+        switch (deviceClassSignature) {
+            case icSigColorSpaceClass:
+                return CLASS_COLORSPACECONVERSION;
+            case icSigDisplayClass:
+                return CLASS_DISPLAY;
+            case icSigOutputClass:
+                return CLASS_OUTPUT;
+            case icSigInputClass:
+                return CLASS_INPUT;
+            case icSigLinkClass:
+                return CLASS_DEVICELINK;
+            case icSigAbstractClass:
+                return CLASS_ABSTRACT;
+            case icSigNamedColorClass:
+                return CLASS_NAMEDCOLOR;
+            default:
+        }
+
+        // Not an ICC profile class
+        // awt.15F=Profile class does not comply with ICC specification
+        throw new IllegalArgumentException(Messages.getString("awt.15F")); //$NON-NLS-1$
+
+    }
+
+    /**
+     * Gets the color space type of the Profile Connection Space (PCS).
+     * 
+     * @return the PCS type.
+     */
+    public int getPCSType() {
+        return csFromSignature(getIntFromHeader(icHdrPcs));
+    }
+
+    /**
+     * Gets the number of components of this ICC Profile.
+     * 
+     * @return the number of components of this ICC Profile.
+     */
+    public int getNumComponents() {
+        switch (getIntFromHeader(icHdrColorSpace)) {
+            // The most common cases go first to increase speed
+            case icSigRgbData:
+            case icSigXYZData:
+            case icSigLabData:
+                return 3;
+            case icSigCmykData:
+                return 4;
+                // Then all other
+            case icSigGrayData:
+                return 1;
+            case icSigSpace2CLR:
+                return 2;
+            case icSigYCbCrData:
+            case icSigLuvData:
+            case icSigYxyData:
+            case icSigHlsData:
+            case icSigHsvData:
+            case icSigCmyData:
+            case icSigSpace3CLR:
+                return 3;
+            case icSigSpace4CLR:
+                return 4;
+            case icSigSpace5CLR:
+                return 5;
+            case icSigSpace6CLR:
+                return 6;
+            case icSigSpace7CLR:
+                return 7;
+            case icSigSpace8CLR:
+                return 8;
+            case icSigSpace9CLR:
+                return 9;
+            case icSigSpaceACLR:
+                return 10;
+            case icSigSpaceBCLR:
+                return 11;
+            case icSigSpaceCCLR:
+                return 12;
+            case icSigSpaceDCLR:
+                return 13;
+            case icSigSpaceECLR:
+                return 14;
+            case icSigSpaceFCLR:
+                return 15;
+            default:
+        }
+
+        // awt.160=Color space doesn't comply with ICC specification
+        throw new ProfileDataException(Messages.getString("awt.160") //$NON-NLS-1$
+        );
+    }
+
+    /**
+     * Gets the minor version of this ICC profile.
+     * 
+     * @return the minor version of this ICC profile.
+     */
+    public int getMinorVersion() {
+        return getByteFromHeader(icHdrVersion + 1);
+    }
+
+    /**
+     * Gets the major version of this ICC profile.
+     * 
+     * @return the major version of this ICC profile.
+     */
+    public int getMajorVersion() {
+        return getByteFromHeader(icHdrVersion);
+    }
+
+    /**
+     * Gets the color space type of this ICC_Profile.
+     * 
+     * @return the color space type.
+     */
+    public int getColorSpaceType() {
+        return csFromSignature(getIntFromHeader(icHdrColorSpace));
+    }
+
+    /**
+     * Tries to open the file at the specified path. Path entries can be divided
+     * by a separator character.
+     * 
+     * @param path
+     *            the path to the file.
+     * @param fileName
+     *            the file name.
+     * @return the input stream to read the file.
+     */
+    private static FileInputStream tryPath(String path, String fileName) {
+        FileInputStream fiStream = null;
+
+        if (path == null) {
+            return null;
+        }
+
+        StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
+
+        while (st.hasMoreTokens()) {
+            String pathEntry = st.nextToken();
+            try {
+                fiStream = new FileInputStream(pathEntry + File.separatorChar + fileName);
+                if (fiStream != null) {
+                    return fiStream;
+                }
+            } catch (FileNotFoundException e) {
+            }
+        }
+
+        return fiStream;
+    }
+
+    /**
+     * Gets the single instance of ICC_Profile from data in the specified file.
+     * 
+     * @param fileName
+     *            the specified name of file with ICC profile data.
+     * @return single instance of ICC_Profile.
+     * @throws IOException
+     *             signals that an I/O error occurred while reading the file or
+     *             the file does not exist.
+     */
+    public static ICC_Profile getInstance(String fileName) throws IOException {
+        final String fName = fileName; // to use in the privileged block
+
+        FileInputStream fiStream = (FileInputStream)AccessController
+                .doPrivileged(new PrivilegedAction<FileInputStream>() {
+                    public FileInputStream run() {
+                        FileInputStream fiStream = null;
+
+                        // Open absolute path
+                        try {
+                            fiStream = new FileInputStream(fName);
+                            if (fiStream != null) {
+                                return fiStream;
+                            }
+                        } catch (FileNotFoundException e) {
+                        }
+
+                        // Check java.iccprofile.path entries
+                        fiStream = tryPath(System.getProperty("java.iccprofile.path"), fName); //$NON-NLS-1$
+                        if (fiStream != null) {
+                            return fiStream;
+                        }
+
+                        // Check java.class.path entries
+                        fiStream = tryPath(System.getProperty("java.class.path"), fName); //$NON-NLS-1$
+                        if (fiStream != null) {
+                            return fiStream;
+                        }
+
+                        // Check directory with java sample profiles
+                        String home = System.getProperty("java.home"); //$NON-NLS-1$
+                        if (home != null) {
+                            fiStream = tryPath(home + File.separatorChar
+                                    + "lib" + File.separatorChar + "cmm", fName //$NON-NLS-1$ //$NON-NLS-2$
+                            );
+                        }
+
+                        return fiStream;
+                    }
+                });
+
+        if (fiStream == null) {
+            // awt.161=Unable to open file {0}
+            throw new IOException(Messages.getString("awt.161", fileName)); //$NON-NLS-1$
+        }
+
+        ICC_Profile pf = getInstance(fiStream);
+        fiStream.close();
+        return pf;
+    }
+
+    /**
+     * Gets the single instance of ICC_Profile with data in the specified
+     * InputStream.
+     * 
+     * @param s
+     *            the InputStream with ICC profile data.
+     * @return single instance of ICC_Profile.
+     * @throws IOException
+     *             if an I/O exception has occurred during reading from
+     *             InputStream.
+     * @throws IllegalArgumentException
+     *             if the file does not contain valid ICC Profile data.
+     */
+    public static ICC_Profile getInstance(InputStream s) throws IOException {
+        byte[] header = new byte[headerSize];
+        // awt.162=Invalid ICC Profile Data
+        String invalidDataMessage = Messages.getString("awt.162"); //$NON-NLS-1$
+
+        // Get header from the input stream
+        if (s.read(header) != headerSize) {
+            throw new IllegalArgumentException(invalidDataMessage);
+        }
+
+        // Check the profile data for consistency
+        if (ICC_ProfileHelper.getBigEndianFromByteArray(header, icHdrMagic) != headerMagicNumber) {
+            throw new IllegalArgumentException(invalidDataMessage);
+        }
+
+        // Get profile size from header, create an array for profile data
+        int profileSize = ICC_ProfileHelper.getBigEndianFromByteArray(header, icHdrSize);
+        byte[] profileData = new byte[profileSize];
+
+        // Copy header into it
+        System.arraycopy(header, 0, profileData, 0, headerSize);
+
+        // Read the profile itself
+        if (s.read(profileData, headerSize, profileSize - headerSize) != profileSize - headerSize) {
+            throw new IllegalArgumentException(invalidDataMessage);
+        }
+
+        return getInstance(profileData);
+    }
+
+    /**
+     * Gets the single instance of ICC_Profile from the specified data in a byte
+     * array.
+     * 
+     * @param data
+     *            the byte array of ICC profile.
+     * @return single instance of ICC_Profile from the specified data in a byte
+     *         array.
+     * @throws IllegalArgumentException
+     *             if the file does not contain valid ICC Profile data.
+     */
+    public static ICC_Profile getInstance(byte[] data) {
+        ICC_Profile res = null;
+
+        try {
+            res = new ICC_Profile(data);
+        } catch (CMMException e) {
+            // awt.162=Invalid ICC Profile Data
+            throw new IllegalArgumentException(Messages.getString("awt.162")); //$NON-NLS-1$
+        }
+
+        if (System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) { //$NON-NLS-1$ //$NON-NLS-2$
+            try {
+                if (res.getColorSpaceType() == ColorSpace.TYPE_RGB
+                        && res.getDataSize(icSigMediaWhitePointTag) > 0
+                        && res.getDataSize(icSigRedColorantTag) > 0
+                        && res.getDataSize(icSigGreenColorantTag) > 0
+                        && res.getDataSize(icSigBlueColorantTag) > 0
+                        && res.getDataSize(icSigRedTRCTag) > 0
+                        && res.getDataSize(icSigGreenTRCTag) > 0
+                        && res.getDataSize(icSigBlueTRCTag) > 0) {
+                    res = new ICC_ProfileRGB(res.getProfileHandle());
+                } else if (res.getColorSpaceType() == ColorSpace.TYPE_GRAY
+                        && res.getDataSize(icSigMediaWhitePointTag) > 0
+                        && res.getDataSize(icSigGrayTRCTag) > 0) {
+                    res = new ICC_ProfileGray(res.getProfileHandle());
+                }
+
+            } catch (CMMException e) { /* return res in this case */
+            }
+        }
+
+        return res;
+    }
+
+    /**
+     * Gets the single instance of ICC_Profile with the specific color space
+     * defined by the ColorSpace class: CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ,
+     * CS_PYCC, CS_GRAY.
+     * 
+     * @param cspace
+     *            the type of color space defined in the ColorSpace class.
+     * @return single instance of ICC_Profile.
+     * @throws IllegalArgumentException
+     *             is not one of the defined color space types.
+     */
+    public static ICC_Profile getInstance(int cspace) {
+        try {
+            switch (cspace) {
+
+                case ColorSpace.CS_sRGB:
+                    if (sRGBProfile == null) {
+                        sRGBProfile = getInstance("sRGB.pf"); //$NON-NLS-1$
+                    }
+                    return sRGBProfile;
+
+                case ColorSpace.CS_CIEXYZ:
+                    if (xyzProfile == null) {
+                        xyzProfile = getInstance("CIEXYZ.pf"); //$NON-NLS-1$
+                    }
+                    return xyzProfile;
+
+                case ColorSpace.CS_GRAY:
+                    if (grayProfile == null) {
+                        grayProfile = getInstance("GRAY.pf"); //$NON-NLS-1$
+                    }
+                    return grayProfile;
+
+                case ColorSpace.CS_PYCC:
+                    if (pyccProfile == null) {
+                        pyccProfile = getInstance("PYCC.pf"); //$NON-NLS-1$
+                    }
+                    return pyccProfile;
+
+                case ColorSpace.CS_LINEAR_RGB:
+                    if (linearRGBProfile == null) {
+                        linearRGBProfile = getInstance("LINEAR_RGB.pf"); //$NON-NLS-1$
+                    }
+                    return linearRGBProfile;
+            }
+
+        } catch (IOException e) {
+            // awt.163=Can't open color profile
+            throw new IllegalArgumentException(Messages.getString("Can't open color profile")); //$NON-NLS-1$
+        }
+
+        // awt.164=Not a predefined color space
+        throw new IllegalArgumentException(Messages.getString("Not a predefined color space")); //$NON-NLS-1$
+    }
+
+    /**
+     * Reads an integer from the profile header at the specified position.
+     * 
+     * @param idx
+     *            - offset in bytes from the beginning of the header
+     * @return the integer value from header
+     */
+    private int getIntFromHeader(int idx) {
+        if (headerData == null) {
+            headerData = getData(icSigHead);
+        }
+
+        return ((headerData[idx] & 0xFF) << 24) | ((headerData[idx + 1] & 0xFF) << 16)
+                | ((headerData[idx + 2] & 0xFF) << 8) | ((headerData[idx + 3] & 0xFF));
+    }
+
+    /**
+     * Reads byte from the profile header at the specified position.
+     * 
+     * @param idx
+     *            - offset in bytes from the beginning of the header
+     * @return the byte from header
+     */
+    private byte getByteFromHeader(int idx) {
+        if (headerData == null) {
+            headerData = getData(icSigHead);
+        }
+
+        return headerData[idx];
+    }
+
+    /**
+     * Converts ICC color space signature to the java predefined color space
+     * type.
+     * 
+     * @param signature
+     *            the signature
+     * @return the int
+     */
+    private int csFromSignature(int signature) {
+        switch (signature) {
+            case icSigRgbData:
+                return ColorSpace.TYPE_RGB;
+            case icSigXYZData:
+                return ColorSpace.TYPE_XYZ;
+            case icSigCmykData:
+                return ColorSpace.TYPE_CMYK;
+            case icSigLabData:
+                return ColorSpace.TYPE_Lab;
+            case icSigGrayData:
+                return ColorSpace.TYPE_GRAY;
+            case icSigHlsData:
+                return ColorSpace.TYPE_HLS;
+            case icSigLuvData:
+                return ColorSpace.TYPE_Luv;
+            case icSigYCbCrData:
+                return ColorSpace.TYPE_YCbCr;
+            case icSigYxyData:
+                return ColorSpace.TYPE_Yxy;
+            case icSigHsvData:
+                return ColorSpace.TYPE_HSV;
+            case icSigCmyData:
+                return ColorSpace.TYPE_CMY;
+            case icSigSpace2CLR:
+                return ColorSpace.TYPE_2CLR;
+            case icSigSpace3CLR:
+                return ColorSpace.TYPE_3CLR;
+            case icSigSpace4CLR:
+                return ColorSpace.TYPE_4CLR;
+            case icSigSpace5CLR:
+                return ColorSpace.TYPE_5CLR;
+            case icSigSpace6CLR:
+                return ColorSpace.TYPE_6CLR;
+            case icSigSpace7CLR:
+                return ColorSpace.TYPE_7CLR;
+            case icSigSpace8CLR:
+                return ColorSpace.TYPE_8CLR;
+            case icSigSpace9CLR:
+                return ColorSpace.TYPE_9CLR;
+            case icSigSpaceACLR:
+                return ColorSpace.TYPE_ACLR;
+            case icSigSpaceBCLR:
+                return ColorSpace.TYPE_BCLR;
+            case icSigSpaceCCLR:
+                return ColorSpace.TYPE_CCLR;
+            case icSigSpaceDCLR:
+                return ColorSpace.TYPE_DCLR;
+            case icSigSpaceECLR:
+                return ColorSpace.TYPE_ECLR;
+            case icSigSpaceFCLR:
+                return ColorSpace.TYPE_FCLR;
+            default:
+        }
+
+        // awt.165=Color space doesn't comply with ICC specification
+        throw new IllegalArgumentException(Messages.getString("awt.165")); //$NON-NLS-1$
+    }
+
+    /**
+     * Gets the profile handle.
+     * 
+     * @return the profile handle
+     */
+    private long getProfileHandle() {
+        handleStolen = true;
+        return profileHandle;
+    }
+
+    /**
+     * Gets the data size.
+     * 
+     * @param tagSignature
+     *            the tag signature
+     * @return the data size
+     */
+    private int getDataSize(int tagSignature) {
+        return NativeCMM.cmmGetProfileElementSize(profileHandle, tagSignature);
+    }
+
+    /**
+     * Reads XYZ value from the tag data.
+     * 
+     * @param tagSignature
+     *            the tag signature
+     * @return the XYZ value
+     */
+    float[] getXYZValue(int tagSignature) {
+        float[] res = new float[3];
+        byte[] data = getData(tagSignature);
+
+        // Convert from ICC s15Fixed16Number type
+        // 1 (float) = 0x10000 (s15Fixed16Number),
+        // hence dividing by 0x10000
+        res[0] = ICC_ProfileHelper.getIntFromByteArray(data, 0) / 65536.f;
+        res[1] = ICC_ProfileHelper.getIntFromByteArray(data, 4) / 65536.f;
+        res[2] = ICC_ProfileHelper.getIntFromByteArray(data, 8) / 65536.f;
+
+        return res;
+    }
+
+    /**
+     * Gets the media white point.
+     * 
+     * @return the media white point.
+     */
+    float[] getMediaWhitePoint() {
+        return getXYZValue(icSigMediaWhitePointTag);
+    }
+
+    /**
+     * If TRC is not a table returns gamma via return value and sets dataTRC to
+     * null. If TRC is a table returns 0 and fills dataTRC with values.
+     * 
+     * @param tagSignature
+     *            the tag signature
+     * @param dataTRC
+     *            the data trc
+     * @return - gamma or zero if TRC is a table
+     */
+    private float getGammaOrTRC(int tagSignature, short[] dataTRC) {
+        byte[] data = getData(tagSignature);
+        int trcSize = ICC_ProfileHelper.getIntFromByteArray(data, icCurveCount);
+
+        dataTRC = null;
+
+        if (trcSize == 0) {
+            return 1.0f;
+        }
+
+        if (trcSize == 1) {
+            // Cast from ICC u8Fixed8Number to float
+            return ICC_ProfileHelper.getShortFromByteArray(data, icCurveData) / 256.f;
+        }
+
+        // TRC is a table
+        dataTRC = new short[trcSize];
+        for (int i = 0, pos = icCurveData; i < trcSize; i++, pos += 2) {
+            dataTRC[i] = ICC_ProfileHelper.getShortFromByteArray(data, pos);
+        }
+        return 0;
+    }
+
+    /**
+     * Gets the gamma.
+     * 
+     * @param tagSignature
+     *            the tag signature
+     * @return the gamma
+     */
+    float getGamma(int tagSignature) {
+        short[] dataTRC = null;
+        float gamma = getGammaOrTRC(tagSignature, dataTRC);
+
+        if (dataTRC == null) {
+            return gamma;
+        }
+        // awt.166=TRC is not a simple gamma value.
+        throw new ProfileDataException(Messages.getString("awt.166")); //$NON-NLS-1$
+    }
+
+    /**
+     * Gets the TRC.
+     * 
+     * @param tagSignature
+     *            the tag signature
+     * @return the tRC
+     */
+    short[] getTRC(int tagSignature) {
+        short[] dataTRC = null;
+        getGammaOrTRC(tagSignature, dataTRC);
+
+        if (dataTRC == null) {
+            // awt.167=TRC is a gamma value, not a table.
+            throw new ProfileDataException(Messages.getString("awt.167")); //$NON-NLS-1$
+        }
+        return dataTRC;
+    }
+}
diff --git a/awt/java/awt/color/ICC_ProfileGray.java b/awt/java/awt/color/ICC_ProfileGray.java
new file mode 100644
index 0000000..f748101
--- /dev/null
+++ b/awt/java/awt/color/ICC_ProfileGray.java
@@ -0,0 +1,78 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+/**
+ * The ICC_ProfileGray class represent profiles with TYPE_GRAY color space type,
+ * and includes the grayTRCTag and mediaWhitePointTag tags. The gray component
+ * can be transformed from a GRAY device profile color space to the CIEXYZ
+ * Profile through the tone reproduction curve (TRC):
+ * <p>
+ * PCSY = grayTRC[deviceGray]
+ * 
+ * @since Android 1.0
+ */
+public class ICC_ProfileGray extends ICC_Profile {
+    
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -1124721290732002649L;
+
+    /**
+     * Instantiates a new iC c_ profile gray.
+     * 
+     * @param profileHandle
+     *            the profile handle
+     */
+    ICC_ProfileGray(long profileHandle) {
+        super(profileHandle);
+    }
+
+    /**
+     * Gets the TRC as an array of shorts.
+     * 
+     * @return the short array of the TRC.
+     */
+    public short[] getTRC() {
+        return super.getTRC(icSigGrayTRCTag);
+    }
+
+    /**
+     * Gets the media white point.
+     * 
+     * @return the media white point
+     */
+    @Override
+    public float[] getMediaWhitePoint() {
+        return super.getMediaWhitePoint();
+    }
+
+    /**
+     * Gets a gamma value representing the tone reproduction curve (TRC).
+     * 
+     * @return the gamma value representing the tone reproduction curve (TRC).
+     */
+    public float getGamma() {
+        return super.getGamma(icSigGrayTRCTag);
+    }
+}
+
diff --git a/awt/java/awt/color/ICC_ProfileRGB.java b/awt/java/awt/color/ICC_ProfileRGB.java
new file mode 100644
index 0000000..9c6010f
--- /dev/null
+++ b/awt/java/awt/color/ICC_ProfileRGB.java
@@ -0,0 +1,154 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ICC_ProfileRGB class represents profiles with RGB color space type and
+ * contains the redColorantTag, greenColorantTag, blueColorantTag, redTRCTag,
+ * greenTRCTag, blueTRCTag, and mediaWhitePointTag tags.
+ * 
+ * @since Android 1.0
+ */
+public class ICC_ProfileRGB extends ICC_Profile {
+    
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 8505067385152579334L;
+
+    /**
+     * Instantiates a new RGB ICC_Profile.
+     * 
+     * @param profileHandle
+     *            the profile handle
+     */
+    ICC_ProfileRGB(long profileHandle) {
+        super(profileHandle);
+    }
+
+    /**
+     * The Constant REDCOMPONENT indicates the red component.
+     */
+    public static final int REDCOMPONENT = 0;
+
+    /**
+     * The Constant GREENCOMPONENT indicates the green component.
+     */
+    public static final int GREENCOMPONENT = 1;
+
+    /**
+     * The Constant BLUECOMPONENT indicates the blue component.
+     */
+    public static final int BLUECOMPONENT = 2;
+
+    // awt.15E=Unknown component. Must be REDCOMPONENT, GREENCOMPONENT or BLUECOMPONENT.
+    /**
+     * The Constant UNKNOWN_COMPONENT_MSG.
+     */
+    private static final String UNKNOWN_COMPONENT_MSG = Messages
+            .getString("awt.15E"); //$NON-NLS-1$
+
+    /**
+     * Gets the TRC.
+     * 
+     * @param component
+     *            the tag signature.
+     * @return the TRC value.
+     */
+    @Override
+    public short[] getTRC(int component) {
+        switch (component) {
+            case REDCOMPONENT:
+                return super.getTRC(icSigRedTRCTag);
+            case GREENCOMPONENT:
+                return super.getTRC(icSigGreenTRCTag);
+            case BLUECOMPONENT:
+                return super.getTRC(icSigBlueTRCTag);
+            default:
+        }
+
+        throw new IllegalArgumentException(UNKNOWN_COMPONENT_MSG);
+    }
+
+    /**
+     * Gets the gamma.
+     * 
+     * @param component
+     *            the tag signature.
+     * @return the gamma value.
+     */
+    @Override
+    public float getGamma(int component) {
+        switch (component) {
+            case REDCOMPONENT:
+                return super.getGamma(icSigRedTRCTag);
+            case GREENCOMPONENT:
+                return super.getGamma(icSigGreenTRCTag);
+            case BLUECOMPONENT:
+                return super.getGamma(icSigBlueTRCTag);
+            default:
+        }
+
+        throw new IllegalArgumentException(UNKNOWN_COMPONENT_MSG);
+    }
+
+    /**
+     * Gets a float matrix which contains the X, Y, and Z components of the
+     * profile's redColorantTag, greenColorantTag, and blueColorantTag.
+     * 
+     * @return the float matrix which contains the X, Y, and Z components of the
+     *         profile's redColorantTag, greenColorantTag, and blueColorantTag.
+     */
+    public float[][] getMatrix() {
+        float [][] m = new float[3][3]; // The matrix
+
+        float[] redXYZ = getXYZValue(icSigRedColorantTag);
+        float[] greenXYZ = getXYZValue(icSigGreenColorantTag);
+        float[] blueXYZ = getXYZValue(icSigBlueColorantTag);
+
+        m[0][0] = redXYZ[0];
+        m[1][0] = redXYZ[1];
+        m[2][0] = redXYZ[2];
+
+        m[0][1] = greenXYZ[0];
+        m[1][1] = greenXYZ[1];
+        m[2][1] = greenXYZ[2];
+
+        m[0][2] = blueXYZ[0];
+        m[1][2] = blueXYZ[1];
+        m[2][2] = blueXYZ[2];
+
+        return m;
+    }
+
+    /**
+     * Gets the media white point.
+     * 
+     * @return the media white point.
+     */
+    @Override
+    public float[] getMediaWhitePoint() {
+        return super.getMediaWhitePoint();
+    }
+}
+
diff --git a/awt/java/awt/color/ICC_ProfileStub.java b/awt/java/awt/color/ICC_ProfileStub.java
new file mode 100644
index 0000000..bc04c8a
--- /dev/null
+++ b/awt/java/awt/color/ICC_ProfileStub.java
@@ -0,0 +1,173 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.color;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectStreamException;
+import java.io.OutputStream;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+final class ICC_ProfileStub extends ICC_Profile {
+    private static final long serialVersionUID = 501389760875253507L;
+
+    transient int colorspace;
+
+    public ICC_ProfileStub(int csSpecifier) {
+        switch (csSpecifier) {
+            case ColorSpace.CS_sRGB:
+            case ColorSpace.CS_CIEXYZ:
+            case ColorSpace.CS_LINEAR_RGB:
+            case ColorSpace.CS_PYCC:
+            case ColorSpace.CS_GRAY:
+                break;
+            default:
+                // awt.15D=Invalid colorspace
+                throw new IllegalArgumentException(Messages.getString("awt.15D")); //$NON-NLS-1$
+        }
+        colorspace = csSpecifier;
+    }
+
+    @Override
+    public void write(String fileName) throws IOException {
+        throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+    }
+
+    /**
+     * Serializable implementation
+     *
+     * @throws ObjectStreamException
+     */
+    private Object writeReplace() throws ObjectStreamException {
+        return loadProfile();
+    }
+
+    @Override
+    public void write(OutputStream s) throws IOException {
+        throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+    }
+
+    @Override
+    public void setData(int tagSignature, byte[] tagData) {
+        throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+    }
+
+    @Override
+    public byte[] getData(int tagSignature) {
+        throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+    }
+
+    @Override
+    public byte[] getData() {
+        throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+    }
+
+    @Override
+    protected void finalize() {
+    }
+
+    @Override
+    public int getProfileClass() {
+        return CLASS_COLORSPACECONVERSION;
+    }
+
+    @Override
+    public int getPCSType() {
+        throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+    }
+
+    @Override
+    public int getNumComponents() {
+        switch (colorspace) {
+            case ColorSpace.CS_sRGB:
+            case ColorSpace.CS_CIEXYZ:
+            case ColorSpace.CS_LINEAR_RGB:
+            case ColorSpace.CS_PYCC:
+                return 3;
+            case ColorSpace.CS_GRAY:
+                return 1;
+            default:
+                throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+        }
+    }
+
+    @Override
+    public int getMinorVersion() {
+        throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+    }
+
+    @Override
+    public int getMajorVersion() {
+        throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+    }
+
+    @Override
+    public int getColorSpaceType() {
+        switch (colorspace) {
+            case ColorSpace.CS_sRGB:
+            case ColorSpace.CS_LINEAR_RGB:
+                return ColorSpace.TYPE_RGB;
+            case ColorSpace.CS_CIEXYZ:
+                return ColorSpace.TYPE_XYZ;
+            case ColorSpace.CS_PYCC:
+                return ColorSpace.TYPE_3CLR;
+            case ColorSpace.CS_GRAY:
+                return ColorSpace.TYPE_GRAY;
+            default:
+                throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+        }
+    }
+
+    public static ICC_Profile getInstance(String fileName) throws IOException {
+        throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+    }
+
+    public static ICC_Profile getInstance(InputStream s) throws IOException {
+        throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+    }
+
+    public static ICC_Profile getInstance(byte[] data) {
+        throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+    }
+
+    public static ICC_Profile getInstance(int cspace) {
+        throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+    }
+
+    public ICC_Profile loadProfile() {
+        switch (colorspace) {
+            case ColorSpace.CS_sRGB:
+                return ICC_Profile.getInstance(ColorSpace.CS_sRGB);
+            case ColorSpace.CS_GRAY:
+                return ICC_Profile.getInstance(ColorSpace.CS_GRAY);
+            case ColorSpace.CS_CIEXYZ:
+                return ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ);
+            case ColorSpace.CS_LINEAR_RGB:
+                return ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB);
+            case ColorSpace.CS_PYCC:
+                return ICC_Profile.getInstance(ColorSpace.CS_PYCC);
+            default:
+                throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+        }
+    }
+}
\ No newline at end of file
diff --git a/awt/java/awt/color/ProfileDataException.java b/awt/java/awt/color/ProfileDataException.java
new file mode 100644
index 0000000..335f314
--- /dev/null
+++ b/awt/java/awt/color/ProfileDataException.java
@@ -0,0 +1,47 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+/**
+ * The ProfileDataException class represents an error which occurs while
+ * accessing or processing an ICC_Profile object.
+ * 
+ * @since Android 1.0
+ */
+public class ProfileDataException extends RuntimeException {
+    
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 7286140888240322498L;
+
+    /**
+     * Instantiates a new profile data exception with detailed message.
+     * 
+     * @param s
+     *            the detailed message of the exception.
+     */
+    public ProfileDataException(String s) {
+        super(s);
+    }
+
+}
+
diff --git a/awt/java/awt/color/package.html b/awt/java/awt/color/package.html
new file mode 100644
index 0000000..609d963
--- /dev/null
+++ b/awt/java/awt/color/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      This package contains classes representing color spaces and profiles based on the International Color Consortium (ICC) Profile Format Specification. 
+    </p>
+    @since Android 1.0
+  </body>
+</html>
diff --git a/awt/java/awt/event/AWTEventListener.java b/awt/java/awt/event/AWTEventListener.java
new file mode 100644
index 0000000..76293b3
--- /dev/null
+++ b/awt/java/awt/event/AWTEventListener.java
@@ -0,0 +1,36 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface AWTEventListener extends EventListener {
+
+    public void eventDispatched(AWTEvent event);
+
+}
diff --git a/awt/java/awt/event/AWTEventListenerProxy.java b/awt/java/awt/event/AWTEventListenerProxy.java
new file mode 100644
index 0000000..3edc41f3
--- /dev/null
+++ b/awt/java/awt/event/AWTEventListenerProxy.java
@@ -0,0 +1,58 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+
+import java.util.EventListenerProxy;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class AWTEventListenerProxy extends EventListenerProxy implements AWTEventListener {
+
+    private AWTEventListener listener;
+    private long eventMask;
+
+    public AWTEventListenerProxy(long eventMask, AWTEventListener listener) {
+        super(listener);
+
+        // awt.193=Listener can't be zero
+        assert listener != null : Messages.getString("awt.193"); //$NON-NLS-1$
+
+        this.listener = listener;
+        this.eventMask = eventMask;
+    }
+
+    public void eventDispatched(AWTEvent evt) {
+        listener.eventDispatched(evt);
+    }
+
+    public long getEventMask() {
+        return eventMask;
+    }
+
+}
diff --git a/awt/java/awt/event/ActionEvent.java b/awt/java/awt/event/ActionEvent.java
new file mode 100644
index 0000000..e882e0d
--- /dev/null
+++ b/awt/java/awt/event/ActionEvent.java
@@ -0,0 +1,114 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class ActionEvent extends AWTEvent {
+
+    private static final long serialVersionUID = -7671078796273832149L;
+
+    public static final int SHIFT_MASK = 1;
+
+    public static final int CTRL_MASK = 2;
+
+    public static final int META_MASK = 4;
+
+    public static final int ALT_MASK = 8;
+
+    public static final int ACTION_FIRST = 1001;
+
+    public static final int ACTION_LAST = 1001;
+
+    public static final int ACTION_PERFORMED = 1001;
+
+    private long when;
+    private int modifiers;
+    private String command;
+
+    public ActionEvent(Object source, int id, String command) {
+        this(source, id, command, 0);
+    }
+
+    public ActionEvent(Object source, int id, String command, int modifiers) {
+        this(source, id, command, 0l, modifiers);
+    }
+
+    public ActionEvent(Object source, int id, String command, long when, int modifiers) {
+        super(source, id);
+
+        this.command = command;
+        this.when = when;
+        this.modifiers = modifiers;
+    }
+
+    public int getModifiers() {
+        return modifiers;
+    }
+
+    public String getActionCommand() {
+        return command;
+    }
+
+    public long getWhen() {
+        return when;
+    }
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * ActionEvent e = new ActionEvent(new Component(){},
+         *       ActionEvent.ACTION_PERFORMED, "Command",
+         *       ActionEvent.SHIFT_MASK|ActionEvent.CTRL_MASK|
+         *       ActionEvent.META_MASK|ActionEvent.ALT_MASK);
+         * System.out.println(e);
+         */
+
+        String idString = (id == ACTION_PERFORMED) ? 
+                          "ACTION_PERFORMED" : "unknown type"; //$NON-NLS-1$ //$NON-NLS-2$
+        String modifiersString = ""; //$NON-NLS-1$
+
+        if ((modifiers & SHIFT_MASK) > 0) {
+            modifiersString += "Shift"; //$NON-NLS-1$
+        }
+        if ((modifiers & CTRL_MASK) > 0) {
+            modifiersString += modifiersString.length() == 0 ? "Ctrl" : "+Ctrl"; //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if ((modifiers & META_MASK) > 0) {
+            modifiersString += modifiersString.length() == 0 ? "Meta" : "+Meta"; //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if ((modifiers & ALT_MASK) > 0) {
+            modifiersString += modifiersString.length() == 0 ? "Alt" : "+Alt"; //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        return (idString + ",cmd=" + command + ",when=" + when +  //$NON-NLS-1$ //$NON-NLS-2$
+                ",modifiers=" + modifiersString); //$NON-NLS-1$
+    }
+
+}
diff --git a/awt/java/awt/event/ActionListener.java b/awt/java/awt/event/ActionListener.java
new file mode 100644
index 0000000..a6eee7a
--- /dev/null
+++ b/awt/java/awt/event/ActionListener.java
@@ -0,0 +1,35 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface ActionListener extends EventListener {
+
+    public void actionPerformed(ActionEvent e);
+
+}
diff --git a/awt/java/awt/event/AdjustmentEvent.java b/awt/java/awt/event/AdjustmentEvent.java
new file mode 100644
index 0000000..be2d6c4
--- /dev/null
+++ b/awt/java/awt/event/AdjustmentEvent.java
@@ -0,0 +1,123 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.Adjustable;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class AdjustmentEvent extends AWTEvent {
+
+    private static final long serialVersionUID = 5700290645205279921L;
+
+    public static final int ADJUSTMENT_FIRST = 601;
+
+    public static final int ADJUSTMENT_LAST = 601;
+
+    public static final int ADJUSTMENT_VALUE_CHANGED = 601;
+
+    public static final int UNIT_INCREMENT = 1;
+
+    public static final int UNIT_DECREMENT = 2;
+
+    public static final int BLOCK_DECREMENT = 3;
+
+    public static final int BLOCK_INCREMENT = 4;
+
+    public static final int TRACK = 5;
+
+    private int type;
+    private int value;
+    private boolean isAdjusting;
+
+    public AdjustmentEvent(Adjustable source, int id, int type, int value) {
+        this(source, id, type, value, false);
+    }
+
+    public AdjustmentEvent(Adjustable source, int id, int type, int value, 
+                           boolean isAdjusting) {
+        super(source, id);
+        this.type = type;
+        this.value = value;
+        this.isAdjusting = isAdjusting;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public int getAdjustmentType() {
+        return type;
+    }
+
+    public boolean getValueIsAdjusting() {
+        return isAdjusting;
+    }
+
+    public Adjustable getAdjustable() {
+        return (Adjustable) source;
+    }
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * AdjustmentEvent e = new AdjustmentEvent(new Scrollbar(), 
+         *       AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, 
+         *       AdjustmentEvent.UNIT_INCREMENT, 1);
+         * System.out.println(e);
+         */
+
+        String idString = (id == ADJUSTMENT_VALUE_CHANGED ?
+                "ADJUSTMENT_VALUE_CHANGED" : "unknown type"); //$NON-NLS-1$ //$NON-NLS-2$
+        String adjType = null;
+
+        switch (type) {
+        case UNIT_INCREMENT:
+            adjType = "UNIT_INCREMENT"; //$NON-NLS-1$
+            break;
+        case UNIT_DECREMENT:
+            adjType = "UNIT_DECREMENT"; //$NON-NLS-1$
+            break;
+        case BLOCK_INCREMENT:
+            adjType = "BLOCK_INCREMENT"; //$NON-NLS-1$
+            break;
+        case BLOCK_DECREMENT:
+            adjType = "BLOCK_DECREMENT"; //$NON-NLS-1$
+            break;
+        case TRACK:
+            adjType = "TRACK"; //$NON-NLS-1$
+            break;
+        default:
+            adjType = "unknown type"; //$NON-NLS-1$
+        }
+
+        return (idString + ",adjType=" + adjType + ",value=" + value + //$NON-NLS-1$ //$NON-NLS-2$
+                ",isAdjusting=" + isAdjusting); //$NON-NLS-1$
+    }
+
+}
diff --git a/awt/java/awt/event/AdjustmentListener.java b/awt/java/awt/event/AdjustmentListener.java
new file mode 100644
index 0000000..5f6a724
--- /dev/null
+++ b/awt/java/awt/event/AdjustmentListener.java
@@ -0,0 +1,35 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface AdjustmentListener extends EventListener {
+
+    public void adjustmentValueChanged(AdjustmentEvent e);
+
+}
diff --git a/awt/java/awt/event/ComponentAdapter.java b/awt/java/awt/event/ComponentAdapter.java
new file mode 100644
index 0000000..c42235f
--- /dev/null
+++ b/awt/java/awt/event/ComponentAdapter.java
@@ -0,0 +1,46 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ComponentAdapter implements ComponentListener {
+
+    public ComponentAdapter() {
+    }
+
+    public void componentHidden(ComponentEvent e) {
+    }
+
+    public void componentMoved(ComponentEvent e) {
+    }
+
+    public void componentResized(ComponentEvent e) {
+    }
+
+    public void componentShown(ComponentEvent e) {
+    }
+
+}
diff --git a/awt/java/awt/event/ComponentEvent.java b/awt/java/awt/event/ComponentEvent.java
new file mode 100644
index 0000000..760d3ab
--- /dev/null
+++ b/awt/java/awt/event/ComponentEvent.java
@@ -0,0 +1,88 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class ComponentEvent extends AWTEvent {
+
+    private static final long serialVersionUID = 8101406823902992965L;
+
+    public static final int COMPONENT_FIRST = 100;
+
+    public static final int COMPONENT_LAST = 103;
+
+    public static final int COMPONENT_MOVED = 100;
+
+    public static final int COMPONENT_RESIZED = 101;
+
+    public static final int COMPONENT_SHOWN = 102;
+
+    public static final int COMPONENT_HIDDEN = 103;
+
+    public ComponentEvent(Component source, int id) {
+        super(source, id);
+    }
+
+    public Component getComponent() {
+        return (Component) source;
+    }
+    
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * ComponentEvent e = new ComponentEvent(new Button("Button"), 
+         *          ComponentEvent.COMPONENT_SHOWN);
+         * System.out.println(e);
+         */
+
+        String idString = null;
+        Component c = getComponent();
+
+        switch (id) {
+        case COMPONENT_MOVED:
+            idString = "COMPONENT_MOVED"; //$NON-NLS-1$
+            break;
+        case COMPONENT_RESIZED:
+            idString = "COMPONENT_RESIZED"; //$NON-NLS-1$
+            break;
+        case COMPONENT_SHOWN:
+            return "COMPONENT_SHOWN"; //$NON-NLS-1$
+        case COMPONENT_HIDDEN:
+            return "COMPONENT_HIDDEN"; //$NON-NLS-1$
+        default:
+            return "unknown type"; //$NON-NLS-1$
+        }
+
+        return (idString + " (" + c.getX() + "," + c.getY() +  //$NON-NLS-1$ //$NON-NLS-2$
+                " " + c.getWidth()+ "x" + c.getHeight() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+
+}
diff --git a/awt/java/awt/event/ComponentListener.java b/awt/java/awt/event/ComponentListener.java
new file mode 100644
index 0000000..a5adba2
--- /dev/null
+++ b/awt/java/awt/event/ComponentListener.java
@@ -0,0 +1,41 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface ComponentListener extends EventListener {
+
+    public void componentHidden(ComponentEvent e);
+
+    public void componentMoved(ComponentEvent e);
+
+    public void componentResized(ComponentEvent e);
+
+    public void componentShown(ComponentEvent e);
+
+}
diff --git a/awt/java/awt/event/ContainerAdapter.java b/awt/java/awt/event/ContainerAdapter.java
new file mode 100644
index 0000000..44983c7
--- /dev/null
+++ b/awt/java/awt/event/ContainerAdapter.java
@@ -0,0 +1,40 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ContainerAdapter implements ContainerListener {
+
+    public ContainerAdapter() {
+    }
+
+    public void componentAdded(ContainerEvent e) {
+    }
+
+    public void componentRemoved(ContainerEvent e) {
+    }
+
+}
diff --git a/awt/java/awt/event/ContainerEvent.java b/awt/java/awt/event/ContainerEvent.java
new file mode 100644
index 0000000..372c9e4
--- /dev/null
+++ b/awt/java/awt/event/ContainerEvent.java
@@ -0,0 +1,89 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+//???AWT: import java.awt.Container;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class ContainerEvent extends ComponentEvent {
+
+    private static final long serialVersionUID = -4114942250539772041L;
+
+    public static final int CONTAINER_FIRST = 300;
+
+    public static final int CONTAINER_LAST = 301;
+
+    public static final int COMPONENT_ADDED = 300;
+
+    public static final int COMPONENT_REMOVED = 301;
+
+    private Component child;
+
+    public ContainerEvent(Component src, int id, Component child) {
+        super(src, id);
+        this.child = child;
+    }
+
+    public Component getChild() {
+        return child;
+    }
+
+    //???AWT
+    /*
+    public Container getContainer() {
+        return (Container) source;
+    }
+    */
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * ContainerEvent e = new ContainerEvent(new Panel(),
+         *          ContainerEvent.COMPONENT_ADDED,
+         *          new Button("Button"));
+         * System.out.println(e);
+         */
+
+        String idString = null;
+
+        switch (id) {
+        case COMPONENT_ADDED:
+            idString = "COMPONENT_ADDED"; //$NON-NLS-1$
+            break;
+        case COMPONENT_REMOVED:
+            idString = "COMPONENT_REMOVED"; //$NON-NLS-1$
+            break;
+        default:
+            idString = "unknown type"; //$NON-NLS-1$
+        }
+
+        return (idString + ",child=" + child.getName()); //$NON-NLS-1$
+    }
+
+}
diff --git a/awt/java/awt/event/ContainerListener.java b/awt/java/awt/event/ContainerListener.java
new file mode 100644
index 0000000..517859e
--- /dev/null
+++ b/awt/java/awt/event/ContainerListener.java
@@ -0,0 +1,37 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface ContainerListener extends EventListener {
+
+    public void componentAdded(ContainerEvent e);
+
+    public void componentRemoved(ContainerEvent e);
+
+}
diff --git a/awt/java/awt/event/FocusAdapter.java b/awt/java/awt/event/FocusAdapter.java
new file mode 100644
index 0000000..3a3e37f
--- /dev/null
+++ b/awt/java/awt/event/FocusAdapter.java
@@ -0,0 +1,40 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class FocusAdapter implements FocusListener {
+
+    public FocusAdapter() {
+    }
+
+    public void focusGained(FocusEvent e) {
+    }
+
+    public void focusLost(FocusEvent e) {
+    }
+
+}
diff --git a/awt/java/awt/event/FocusEvent.java b/awt/java/awt/event/FocusEvent.java
new file mode 100644
index 0000000..4a18689
--- /dev/null
+++ b/awt/java/awt/event/FocusEvent.java
@@ -0,0 +1,96 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class FocusEvent extends ComponentEvent {
+
+    private static final long serialVersionUID = 523753786457416396L;
+
+    public static final int FOCUS_FIRST = 1004;
+
+    public static final int FOCUS_LAST = 1005;
+
+    public static final int FOCUS_GAINED = 1004;
+
+    public static final int FOCUS_LOST = 1005;
+
+    private boolean temporary;
+    private Component opposite;
+
+    public FocusEvent(Component source, int id) {
+        this(source, id, false);
+    }
+
+    public FocusEvent(Component source, int id, boolean temporary) {
+        this(source, id, temporary, null);
+    }
+
+    public FocusEvent(Component source, int id, boolean temporary, Component opposite) {
+        super(source, id);
+        this.temporary = temporary;
+        this.opposite = opposite;
+    }
+
+    public Component getOppositeComponent() {
+        return opposite;
+    }
+
+    public boolean isTemporary() {
+        return temporary;
+    }
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * FocusEvent e = new FocusEvent(new Button("Button0"),
+         *       FocusEvent.FOCUS_GAINED, false, new Button("Button1"));
+         * System.out.println(e);
+         */
+
+        String idString = null;
+
+        switch (id) {
+        case FOCUS_GAINED:
+            idString = "FOCUS_GAINED"; //$NON-NLS-1$
+            break;
+        case FOCUS_LOST:
+            idString = "FOCUS_LOST"; //$NON-NLS-1$
+            break;
+        default:
+            idString = "unknown type"; //$NON-NLS-1$
+        }
+
+        return (idString +
+                (temporary ? ",temporary" : ",permanent") + //$NON-NLS-1$ //$NON-NLS-2$
+                ",opposite=" + opposite); //$NON-NLS-1$
+    }
+
+}
diff --git a/awt/java/awt/event/FocusListener.java b/awt/java/awt/event/FocusListener.java
new file mode 100644
index 0000000..6bbbd00
--- /dev/null
+++ b/awt/java/awt/event/FocusListener.java
@@ -0,0 +1,37 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface FocusListener extends EventListener {
+
+    public void focusGained(FocusEvent e);
+
+    public void focusLost(FocusEvent e);
+
+}
diff --git a/awt/java/awt/event/HierarchyBoundsAdapter.java b/awt/java/awt/event/HierarchyBoundsAdapter.java
new file mode 100644
index 0000000..bbfe8ff
--- /dev/null
+++ b/awt/java/awt/event/HierarchyBoundsAdapter.java
@@ -0,0 +1,40 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class HierarchyBoundsAdapter implements HierarchyBoundsListener {
+
+    public HierarchyBoundsAdapter() {
+    }
+
+    public void ancestorMoved(HierarchyEvent e) {
+    }
+
+    public void ancestorResized(HierarchyEvent e) {
+    }
+
+}
diff --git a/awt/java/awt/event/HierarchyBoundsListener.java b/awt/java/awt/event/HierarchyBoundsListener.java
new file mode 100644
index 0000000..3e8f2e7
--- /dev/null
+++ b/awt/java/awt/event/HierarchyBoundsListener.java
@@ -0,0 +1,37 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface HierarchyBoundsListener extends EventListener {
+
+    public void ancestorMoved(HierarchyEvent e);
+
+    public void ancestorResized(HierarchyEvent e);
+
+}
diff --git a/awt/java/awt/event/HierarchyEvent.java b/awt/java/awt/event/HierarchyEvent.java
new file mode 100644
index 0000000..c1d22f4
--- /dev/null
+++ b/awt/java/awt/event/HierarchyEvent.java
@@ -0,0 +1,154 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+//???AWT: import java.awt.Container;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class HierarchyEvent extends AWTEvent {
+
+    private static final long serialVersionUID = -5337576970038043990L;
+
+    public static final int HIERARCHY_FIRST = 1400;
+
+    public static final int HIERARCHY_CHANGED = 1400;
+
+    public static final int ANCESTOR_MOVED = 1401;
+
+    public static final int ANCESTOR_RESIZED = 1402;
+
+    public static final int HIERARCHY_LAST = 1402;
+
+    public static final int PARENT_CHANGED = 1;
+
+    public static final int DISPLAYABILITY_CHANGED = 2;
+
+    public static final int SHOWING_CHANGED = 4;
+
+    //???AWT: private Container changedParent;
+    private Component changed;
+    private long changeFlag;
+
+    //???AWT
+    /*
+    public HierarchyEvent(Component source, int id, Component changed, 
+                          Container changedParent) {
+        this(source, id, changed, changedParent, 0l);
+    }
+    */
+
+    //???AWT
+    /*
+    public HierarchyEvent(Component source, int id, Component changed,
+            Container changedParent, long changeFlags) {
+        super(source, id);
+
+        this.changed = changed;
+        this.changedParent = changedParent;
+        this.changeFlag = changeFlags;
+    }
+    */
+    //???AWT: Fake constructor, should be as above.
+    public HierarchyEvent(Component source, int id, Component changed,
+            Object changedParent, long changeFlags) {
+        super(source, id);
+
+//        this.changed = changed;
+//        this.changedParent = changedParent;
+//        this.changeFlag = changeFlags;
+    }
+    
+    public Component getComponent() {
+        return (Component) source;
+    }
+
+    public long getChangeFlags() {
+        return changeFlag;
+    }
+
+    public Component getChanged() {
+        return changed;
+    }
+
+    //???AWT
+    /*
+    public Container getChangedParent() {
+        return changedParent;
+
+    }
+    */
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * HierarchyEvent e = new HierarchyEvent(new Button("Button"),
+         *          HierarchyEvent.HIERARCHY_CHANGED,
+         *          new Panel(), new Container());
+         * System.out.println(e);
+         */
+        String paramString = null;
+
+        switch (id) {
+        case HIERARCHY_CHANGED:
+            paramString = "HIERARCHY_CHANGED"; //$NON-NLS-1$
+            break;
+        case ANCESTOR_MOVED:
+            paramString = "ANCESTOR_MOVED"; //$NON-NLS-1$
+            break;
+        case ANCESTOR_RESIZED:
+            paramString = "ANCESTOR_RESIZED"; //$NON-NLS-1$
+            break;
+        default:
+            paramString = "unknown type"; //$NON-NLS-1$
+        }
+
+        paramString += " ("; //$NON-NLS-1$
+
+        if (id == HIERARCHY_CHANGED) {
+            if ((changeFlag & PARENT_CHANGED) > 0) {
+                paramString += "PARENT_CHANGED,"; //$NON-NLS-1$
+            }
+            if ((changeFlag & DISPLAYABILITY_CHANGED) > 0) {
+                paramString += "DISPLAYABILITY_CHANGED,"; //$NON-NLS-1$
+            }
+            if ((changeFlag & SHOWING_CHANGED) > 0) {
+                paramString += "SHOWING_CHANGED,"; //$NON-NLS-1$
+            }
+        }
+
+        //???AWT
+        /*
+        return paramString + "changed=" + changed +  //$NON-NLS-1$
+                ",changedParent=" + changedParent + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+        */
+        return paramString;
+    }
+
+}
diff --git a/awt/java/awt/event/HierarchyListener.java b/awt/java/awt/event/HierarchyListener.java
new file mode 100644
index 0000000..ff3d9bc
--- /dev/null
+++ b/awt/java/awt/event/HierarchyListener.java
@@ -0,0 +1,35 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface HierarchyListener extends EventListener {
+
+    public void hierarchyChanged(HierarchyEvent e);
+
+}
diff --git a/awt/java/awt/event/InputEvent.java b/awt/java/awt/event/InputEvent.java
new file mode 100644
index 0000000..343b7a3
--- /dev/null
+++ b/awt/java/awt/event/InputEvent.java
@@ -0,0 +1,190 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class InputEvent extends ComponentEvent {
+
+    private static final long serialVersionUID = -2482525981698309786L;
+
+    public static final int SHIFT_MASK = 1;
+
+    public static final int CTRL_MASK = 2;
+
+    public static final int META_MASK = 4;
+
+    public static final int ALT_MASK = 8;
+
+    public static final int ALT_GRAPH_MASK = 32;
+
+    public static final int BUTTON1_MASK = 16;
+
+    public static final int BUTTON2_MASK = 8;
+
+    public static final int BUTTON3_MASK = 4;
+
+    public static final int SHIFT_DOWN_MASK = 64;
+
+    public static final int CTRL_DOWN_MASK = 128;
+
+    public static final int META_DOWN_MASK = 256;
+
+    public static final int ALT_DOWN_MASK = 512;
+
+    public static final int BUTTON1_DOWN_MASK = 1024;
+
+    public static final int BUTTON2_DOWN_MASK = 2048;
+
+    public static final int BUTTON3_DOWN_MASK = 4096;
+
+    public static final int ALT_GRAPH_DOWN_MASK = 8192;
+
+    private static final int DOWN_MASKS = SHIFT_DOWN_MASK | CTRL_DOWN_MASK |
+            META_DOWN_MASK | ALT_DOWN_MASK | BUTTON1_DOWN_MASK |
+            BUTTON2_DOWN_MASK | BUTTON3_DOWN_MASK | ALT_GRAPH_DOWN_MASK;
+
+    private long when;
+    private int modifiersEx;
+
+    public static String getModifiersExText(int modifiers/*Ex*/) {
+        return MouseEvent.addMouseModifiersExText(
+                KeyEvent.getKeyModifiersExText(modifiers), modifiers);
+    }
+
+    static int extractExFlags(int modifiers) {
+        int exFlags = modifiers & DOWN_MASKS;
+
+        if ((modifiers & SHIFT_MASK) != 0) {
+            exFlags |= SHIFT_DOWN_MASK;
+        }
+        if ((modifiers & CTRL_MASK) != 0) {
+            exFlags |= CTRL_DOWN_MASK;
+        }
+        if ((modifiers & META_MASK) != 0) {
+            exFlags |= META_DOWN_MASK;
+        }
+        if ((modifiers & ALT_MASK) != 0) {
+            exFlags |= ALT_DOWN_MASK;
+        }
+        if ((modifiers & ALT_GRAPH_MASK) != 0) {
+            exFlags |= ALT_GRAPH_DOWN_MASK;
+        }
+        if ((modifiers & BUTTON1_MASK) != 0) {
+            exFlags |= BUTTON1_DOWN_MASK;
+        }
+        if ((modifiers & BUTTON2_MASK) != 0) {
+            exFlags |= BUTTON2_DOWN_MASK;
+        }
+        if ((modifiers & BUTTON3_MASK) != 0) {
+            exFlags |= BUTTON3_DOWN_MASK;
+        }
+
+        return exFlags;
+    }
+
+    InputEvent(Component source, int id, long when, int modifiers) {
+        super(source, id);
+
+        this.when = when;
+        modifiersEx = extractExFlags(modifiers);
+    }
+
+    public int getModifiers() {
+        int modifiers = 0;
+
+        if ((modifiersEx & SHIFT_DOWN_MASK) != 0) {
+            modifiers |= SHIFT_MASK;
+        }
+        if ((modifiersEx & CTRL_DOWN_MASK) != 0) {
+            modifiers |= CTRL_MASK;
+        }
+        if ((modifiersEx & META_DOWN_MASK) != 0) {
+            modifiers |= META_MASK;
+        }
+        if ((modifiersEx & ALT_DOWN_MASK) != 0) {
+            modifiers |= ALT_MASK;
+        }
+        if ((modifiersEx & ALT_GRAPH_DOWN_MASK) != 0) {
+            modifiers |= ALT_GRAPH_MASK;
+        }
+        if ((modifiersEx & BUTTON1_DOWN_MASK) != 0) {
+            modifiers |= BUTTON1_MASK;
+        }
+        if ((modifiersEx & BUTTON2_DOWN_MASK) != 0) {
+            modifiers |= BUTTON2_MASK;
+        }
+        if ((modifiersEx & BUTTON3_DOWN_MASK) != 0) {
+            modifiers |= BUTTON3_MASK;
+        }
+
+        return modifiers;
+    }
+
+    public int getModifiersEx() {
+        return modifiersEx;
+    }
+
+    void setModifiers(int modifiers) {
+        modifiersEx = extractExFlags(modifiers);
+    }
+
+    public boolean isAltDown() {
+        return ((modifiersEx & ALT_DOWN_MASK) != 0);
+    }
+
+    public boolean isAltGraphDown() {
+        return ((modifiersEx & ALT_GRAPH_DOWN_MASK) != 0);
+    }
+
+    public boolean isControlDown() {
+        return ((modifiersEx & CTRL_DOWN_MASK) != 0);
+    }
+
+    public boolean isMetaDown() {
+        return ((modifiersEx & META_DOWN_MASK) != 0);
+    }
+
+    public boolean isShiftDown() {
+        return ((modifiersEx & SHIFT_DOWN_MASK) != 0);
+    }
+
+    public long getWhen() {
+        return when;
+    }
+
+    @Override
+    public void consume() {
+        super.consume();
+    }
+
+    @Override
+    public boolean isConsumed() {
+        return super.isConsumed();
+    }
+
+}
diff --git a/awt/java/awt/event/InputMethodEvent.java b/awt/java/awt/event/InputMethodEvent.java
new file mode 100644
index 0000000..be001a5
--- /dev/null
+++ b/awt/java/awt/event/InputMethodEvent.java
@@ -0,0 +1,156 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+import java.awt.font.TextHitInfo;
+import java.text.AttributedCharacterIterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class InputMethodEvent extends AWTEvent {
+
+    private static final long serialVersionUID = 4727190874778922661L;
+
+    public static final int INPUT_METHOD_FIRST = 1100;
+
+    public static final int INPUT_METHOD_TEXT_CHANGED = 1100;
+
+    public static final int CARET_POSITION_CHANGED = 1101;
+
+    public static final int INPUT_METHOD_LAST = 1101;
+
+    private AttributedCharacterIterator text;
+    private TextHitInfo visiblePosition;
+    private TextHitInfo caret;
+    private int committedCharacterCount;
+    private long when;
+
+    public InputMethodEvent(Component src, int id,
+                            TextHitInfo caret, 
+                            TextHitInfo visiblePos) {
+        this(src, id, null, 0, caret, visiblePos);
+    }
+
+    public InputMethodEvent(Component src, int id, 
+                            AttributedCharacterIterator text,
+                            int commitedCharCount,
+                            TextHitInfo caret, 
+                            TextHitInfo visiblePos) {
+        this(src, id, 0l, text, commitedCharCount, caret, visiblePos);
+    }
+
+    public InputMethodEvent(Component src, int id, long when,
+                            AttributedCharacterIterator text, 
+                            int committedCharacterCount,
+                            TextHitInfo caret,
+                            TextHitInfo visiblePos) {
+        super(src, id);
+
+        if ((id < INPUT_METHOD_FIRST) || (id > INPUT_METHOD_LAST)) {
+            // awt.18E=Wrong event id
+            throw new IllegalArgumentException(Messages.getString("awt.18E")); //$NON-NLS-1$
+        }
+        if ((id == CARET_POSITION_CHANGED) && (text != null)) {
+            // awt.18F=Text must be null for CARET_POSITION_CHANGED
+            throw new IllegalArgumentException(Messages.getString("awt.18F")); //$NON-NLS-1$
+        }
+        if ((text != null) &&
+                ((committedCharacterCount < 0) ||
+                 (committedCharacterCount > 
+                        (text.getEndIndex() - text.getBeginIndex())))) {
+            // awt.190=Wrong committedCharacterCount
+            throw new IllegalArgumentException(Messages.getString("awt.190")); //$NON-NLS-1$
+        }
+
+        this.when = when;
+        this.text = text;
+        this.caret = caret;
+        this.visiblePosition = visiblePos;
+        this.committedCharacterCount = committedCharacterCount;
+    }
+
+    public TextHitInfo getCaret() {
+        return caret;
+    }
+
+    public int getCommittedCharacterCount() {
+        return committedCharacterCount;
+    }
+
+    public AttributedCharacterIterator getText() {
+        return text;
+    }
+
+    public TextHitInfo getVisiblePosition() {
+        return visiblePosition;
+    }
+
+    public long getWhen() {
+        return when;
+    }
+
+    @Override
+    public void consume() {
+        super.consume();
+    }
+
+    @Override
+    public boolean isConsumed() {
+        return super.isConsumed();
+    }
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * InputMethodEvent e = new InputMethodEvent(new Component(){},
+         *          InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
+         *          TextHitInfo.leading(1), TextHitInfo.trailing(2));
+         * System.out.println(e);
+         */
+        String typeString = null;
+
+        switch (id) {
+        case INPUT_METHOD_TEXT_CHANGED:
+            typeString = "INPUT_METHOD_TEXT_CHANGED"; //$NON-NLS-1$
+            break;
+        case CARET_POSITION_CHANGED:
+            typeString = "CARET_POSITION_CHANGED"; //$NON-NLS-1$
+            break;
+        default:
+            typeString = "unknown type"; //$NON-NLS-1$
+        }
+
+        return typeString + ",text=" + text +  //$NON-NLS-1$
+                ",commitedCharCount=" + committedCharacterCount + //$NON-NLS-1$
+                ",caret=" + caret + ",visiblePosition=" + visiblePosition; //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+}
diff --git a/awt/java/awt/event/InputMethodListener.java b/awt/java/awt/event/InputMethodListener.java
new file mode 100644
index 0000000..85eaa7e
--- /dev/null
+++ b/awt/java/awt/event/InputMethodListener.java
@@ -0,0 +1,37 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface InputMethodListener extends EventListener {
+
+    public void caretPositionChanged(InputMethodEvent e);
+
+    public void inputMethodTextChanged(InputMethodEvent e);
+
+}
diff --git a/awt/java/awt/event/InvocationEvent.java b/awt/java/awt/event/InvocationEvent.java
new file mode 100644
index 0000000..58e3b72
--- /dev/null
+++ b/awt/java/awt/event/InvocationEvent.java
@@ -0,0 +1,138 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.ActiveEvent;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class InvocationEvent extends AWTEvent implements ActiveEvent {
+
+    private static final long serialVersionUID = 436056344909459450L;
+
+    public static final int INVOCATION_FIRST = 1200;
+
+    public static final int INVOCATION_DEFAULT = 1200;
+
+    public static final int INVOCATION_LAST = 1200;
+
+    protected Runnable runnable;
+
+    protected Object notifier;
+
+    protected boolean catchExceptions;
+
+    private long when;
+    private Throwable throwable;
+
+    public InvocationEvent(Object source, Runnable runnable) {
+        this(source, runnable, null, false);
+    }
+
+    public InvocationEvent(Object source, Runnable runnable, 
+                           Object notifier, boolean catchExceptions) {
+        this(source, INVOCATION_DEFAULT, runnable, notifier, catchExceptions);
+    }
+
+    protected InvocationEvent(Object source, int id, Runnable runnable,
+            Object notifier, boolean catchExceptions)
+    {
+        super(source, id);
+
+        // awt.18C=Cannot invoke null runnable
+        assert runnable != null : Messages.getString("awt.18C"); //$NON-NLS-1$
+
+        if (source == null) {
+            // awt.18D=Source is null
+            throw new IllegalArgumentException(Messages.getString("awt.18D")); //$NON-NLS-1$
+        }
+        this.runnable = runnable;
+        this.notifier = notifier;
+        this.catchExceptions = catchExceptions;
+
+        throwable = null;
+        when = System.currentTimeMillis();
+    }
+
+    public void dispatch() {
+        if (!catchExceptions) {
+            runAndNotify();
+        } else {
+            try {
+                runAndNotify();
+            } catch (Throwable t) {
+                throwable = t;
+            }
+        }
+    }
+
+    private void runAndNotify() {
+        if (notifier != null) {
+            synchronized(notifier) {
+                try {
+                    runnable.run();
+                } finally {
+                    notifier.notifyAll();
+                }
+            }
+        } else {
+            runnable.run();
+        }
+    }
+
+    public Exception getException() {
+        return (throwable != null && throwable instanceof Exception) ?
+                (Exception)throwable : null;
+    }
+
+    public Throwable getThrowable() {
+        return throwable;
+    }
+
+    public long getWhen() {
+        return when;
+    }
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * InvocationEvent e = new InvocationEvent(new Component(){},
+         *       new Runnable() { public void run(){} });
+         * System.out.println(e);
+         */
+
+        return ((id == INVOCATION_DEFAULT ? "INVOCATION_DEFAULT" : "unknown type") + //$NON-NLS-1$ //$NON-NLS-2$
+                ",runnable=" + runnable + //$NON-NLS-1$
+                ",notifier=" + notifier + //$NON-NLS-1$
+                ",catchExceptions=" + catchExceptions + //$NON-NLS-1$
+                ",when=" + when); //$NON-NLS-1$
+    }
+
+}
diff --git a/awt/java/awt/event/ItemEvent.java b/awt/java/awt/event/ItemEvent.java
new file mode 100644
index 0000000..09908f2
--- /dev/null
+++ b/awt/java/awt/event/ItemEvent.java
@@ -0,0 +1,96 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.ItemSelectable;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class ItemEvent extends AWTEvent {
+
+    private static final long serialVersionUID = -608708132447206933L;
+
+    public static final int ITEM_FIRST = 701;
+
+    public static final int ITEM_LAST = 701;
+
+    public static final int ITEM_STATE_CHANGED = 701;
+
+    public static final int SELECTED = 1;
+
+    public static final int DESELECTED = 2;
+
+    private Object item;
+    private int stateChange;
+
+    public ItemEvent(ItemSelectable source, int id, Object item, int stateChange) {
+        super(source, id);
+
+        this.item = item;
+        this.stateChange = stateChange;
+    }
+
+    public Object getItem() {
+        return item;
+    }
+
+    public int getStateChange() {
+        return stateChange;
+    }
+
+    public ItemSelectable getItemSelectable() {
+        return (ItemSelectable) source;
+    }
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * Checkbox c = new Checkbox("Checkbox", true);
+         * ItemEvent e = new ItemEvent(c, ItemEvent.ITEM_STATE_CHANGED, 
+         *                             c, ItemEvent.SELECTED);
+         * System.out.println(e);
+         */
+
+        String stateString = null;
+
+        switch (stateChange) {
+        case SELECTED:
+            stateString = "SELECTED"; //$NON-NLS-1$
+            break;
+        case DESELECTED:
+            stateString = "DESELECTED"; //$NON-NLS-1$
+            break;
+        default:
+            stateString = "unknown type"; //$NON-NLS-1$
+        }
+
+        return ((id == ITEM_STATE_CHANGED ? "ITEM_STATE_CHANGED" : "unknown type") + //$NON-NLS-1$ //$NON-NLS-2$
+                ",item=" + item + ",stateChange=" + stateString); //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+}
diff --git a/awt/java/awt/event/ItemListener.java b/awt/java/awt/event/ItemListener.java
new file mode 100644
index 0000000..8dec673
--- /dev/null
+++ b/awt/java/awt/event/ItemListener.java
@@ -0,0 +1,35 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface ItemListener extends EventListener {
+
+    public void itemStateChanged(ItemEvent e);
+
+}
diff --git a/awt/java/awt/event/KeyAdapter.java b/awt/java/awt/event/KeyAdapter.java
new file mode 100644
index 0000000..a96cca8
--- /dev/null
+++ b/awt/java/awt/event/KeyAdapter.java
@@ -0,0 +1,43 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class KeyAdapter implements KeyListener {
+
+    public KeyAdapter() {
+    }
+
+    public void keyPressed(KeyEvent e) {
+    }
+
+    public void keyReleased(KeyEvent e) {
+    }
+
+    public void keyTyped(KeyEvent e) {
+    }
+
+}
diff --git a/awt/java/awt/event/KeyEvent.java b/awt/java/awt/event/KeyEvent.java
new file mode 100644
index 0000000..8627f70
--- /dev/null
+++ b/awt/java/awt/event/KeyEvent.java
@@ -0,0 +1,687 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+import java.awt.Toolkit;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class KeyEvent extends InputEvent {
+
+    private static final long serialVersionUID = -2352130953028126954L;
+
+    public static final int KEY_FIRST = 400;
+
+    public static final int KEY_LAST = 402;
+
+    public static final int KEY_TYPED = 400;
+
+    public static final int KEY_PRESSED = 401;
+
+    public static final int KEY_RELEASED = 402;
+
+    public static final int VK_ENTER = 10;
+
+    public static final int VK_BACK_SPACE = 8;
+
+    public static final int VK_TAB = 9;
+
+    public static final int VK_CANCEL = 3;
+
+    public static final int VK_CLEAR = 12;
+
+    public static final int VK_SHIFT = 16;
+
+    public static final int VK_CONTROL = 17;
+
+    public static final int VK_ALT = 18;
+
+    public static final int VK_PAUSE = 19;
+
+    public static final int VK_CAPS_LOCK = 20;
+
+    public static final int VK_ESCAPE = 27;
+
+    public static final int VK_SPACE = 32;
+
+    public static final int VK_PAGE_UP = 33;
+
+    public static final int VK_PAGE_DOWN = 34;
+
+    public static final int VK_END = 35;
+
+    public static final int VK_HOME = 36;
+
+    public static final int VK_LEFT = 37;
+
+    public static final int VK_UP = 38;
+
+    public static final int VK_RIGHT = 39;
+
+    public static final int VK_DOWN = 40;
+
+    public static final int VK_COMMA = 44;
+
+    public static final int VK_MINUS = 45;
+
+    public static final int VK_PERIOD = 46;
+
+    public static final int VK_SLASH = 47;
+
+    public static final int VK_0 = 48;
+
+    public static final int VK_1 = 49;
+
+    public static final int VK_2 = 50;
+
+    public static final int VK_3 = 51;
+
+    public static final int VK_4 = 52;
+
+    public static final int VK_5 = 53;
+
+    public static final int VK_6 = 54;
+
+    public static final int VK_7 = 55;
+
+    public static final int VK_8 = 56;
+
+    public static final int VK_9 = 57;
+
+    public static final int VK_SEMICOLON = 59;
+
+    public static final int VK_EQUALS = 61;
+
+    public static final int VK_A = 65;
+
+    public static final int VK_B = 66;
+
+    public static final int VK_C = 67;
+
+    public static final int VK_D = 68;
+
+    public static final int VK_E = 69;
+
+    public static final int VK_F = 70;
+
+    public static final int VK_G = 71;
+
+    public static final int VK_H = 72;
+
+    public static final int VK_I = 73;
+
+    public static final int VK_J = 74;
+
+    public static final int VK_K = 75;
+
+    public static final int VK_L = 76;
+
+    public static final int VK_M = 77;
+
+    public static final int VK_N = 78;
+
+    public static final int VK_O = 79;
+
+    public static final int VK_P = 80;
+
+    public static final int VK_Q = 81;
+
+    public static final int VK_R = 82;
+
+    public static final int VK_S = 83;
+
+    public static final int VK_T = 84;
+
+    public static final int VK_U = 85;
+
+    public static final int VK_V = 86;
+
+    public static final int VK_W = 87;
+
+    public static final int VK_X = 88;
+
+    public static final int VK_Y = 89;
+
+    public static final int VK_Z = 90;
+
+    public static final int VK_OPEN_BRACKET = 91;
+
+    public static final int VK_BACK_SLASH = 92;
+
+    public static final int VK_CLOSE_BRACKET = 93;
+
+    public static final int VK_NUMPAD0 = 96;
+
+    public static final int VK_NUMPAD1 = 97;
+
+    public static final int VK_NUMPAD2 = 98;
+
+    public static final int VK_NUMPAD3 = 99;
+
+    public static final int VK_NUMPAD4 = 100;
+
+    public static final int VK_NUMPAD5 = 101;
+
+    public static final int VK_NUMPAD6 = 102;
+
+    public static final int VK_NUMPAD7 = 103;
+
+    public static final int VK_NUMPAD8 = 104;
+
+    public static final int VK_NUMPAD9 = 105;
+
+    public static final int VK_MULTIPLY = 106;
+
+    public static final int VK_ADD = 107;
+
+    public static final int VK_SEPARATER = 108;
+
+    public static final int VK_SEPARATOR = 108;
+
+    public static final int VK_SUBTRACT = 109;
+
+    public static final int VK_DECIMAL = 110;
+
+    public static final int VK_DIVIDE = 111;
+
+    public static final int VK_DELETE = 127;
+
+    public static final int VK_NUM_LOCK = 144;
+
+    public static final int VK_SCROLL_LOCK = 145;
+
+    public static final int VK_F1 = 112;
+
+    public static final int VK_F2 = 113;
+
+    public static final int VK_F3 = 114;
+
+    public static final int VK_F4 = 115;
+
+    public static final int VK_F5 = 116;
+
+    public static final int VK_F6 = 117;
+
+    public static final int VK_F7 = 118;
+
+    public static final int VK_F8 = 119;
+
+    public static final int VK_F9 = 120;
+
+    public static final int VK_F10 = 121;
+
+    public static final int VK_F11 = 122;
+
+    public static final int VK_F12 = 123;
+
+    public static final int VK_F13 = 61440;
+
+    public static final int VK_F14 = 61441;
+
+    public static final int VK_F15 = 61442;
+
+    public static final int VK_F16 = 61443;
+
+    public static final int VK_F17 = 61444;
+
+    public static final int VK_F18 = 61445;
+
+    public static final int VK_F19 = 61446;
+
+    public static final int VK_F20 = 61447;
+
+    public static final int VK_F21 = 61448;
+
+    public static final int VK_F22 = 61449;
+
+    public static final int VK_F23 = 61450;
+
+    public static final int VK_F24 = 61451;
+
+    public static final int VK_PRINTSCREEN = 154;
+
+    public static final int VK_INSERT = 155;
+
+    public static final int VK_HELP = 156;
+
+    public static final int VK_META = 157;
+
+    public static final int VK_BACK_QUOTE = 192;
+
+    public static final int VK_QUOTE = 222;
+
+    public static final int VK_KP_UP = 224;
+
+    public static final int VK_KP_DOWN = 225;
+
+    public static final int VK_KP_LEFT = 226;
+
+    public static final int VK_KP_RIGHT = 227;
+
+    public static final int VK_DEAD_GRAVE = 128;
+
+    public static final int VK_DEAD_ACUTE = 129;
+
+    public static final int VK_DEAD_CIRCUMFLEX = 130;
+
+    public static final int VK_DEAD_TILDE = 131;
+
+    public static final int VK_DEAD_MACRON = 132;
+
+    public static final int VK_DEAD_BREVE = 133;
+
+    public static final int VK_DEAD_ABOVEDOT = 134;
+
+    public static final int VK_DEAD_DIAERESIS = 135;
+
+    public static final int VK_DEAD_ABOVERING = 136;
+
+    public static final int VK_DEAD_DOUBLEACUTE = 137;
+
+    public static final int VK_DEAD_CARON = 138;
+
+    public static final int VK_DEAD_CEDILLA = 139;
+
+    public static final int VK_DEAD_OGONEK = 140;
+
+    public static final int VK_DEAD_IOTA = 141;
+
+    public static final int VK_DEAD_VOICED_SOUND = 142;
+
+    public static final int VK_DEAD_SEMIVOICED_SOUND = 143;
+
+    public static final int VK_AMPERSAND = 150;
+
+    public static final int VK_ASTERISK = 151;
+
+    public static final int VK_QUOTEDBL = 152;
+
+    public static final int VK_LESS = 153;
+
+    public static final int VK_GREATER = 160;
+
+    public static final int VK_BRACELEFT = 161;
+
+    public static final int VK_BRACERIGHT = 162;
+
+    public static final int VK_AT = 512;
+
+    public static final int VK_COLON = 513;
+
+    public static final int VK_CIRCUMFLEX = 514;
+
+    public static final int VK_DOLLAR = 515;
+
+    public static final int VK_EURO_SIGN = 516;
+
+    public static final int VK_EXCLAMATION_MARK = 517;
+
+    public static final int VK_INVERTED_EXCLAMATION_MARK = 518;
+
+    public static final int VK_LEFT_PARENTHESIS = 519;
+
+    public static final int VK_NUMBER_SIGN = 520;
+
+    public static final int VK_PLUS = 521;
+
+    public static final int VK_RIGHT_PARENTHESIS = 522;
+
+    public static final int VK_UNDERSCORE = 523;
+
+    public static final int VK_FINAL = 24;
+
+    public static final int VK_WINDOWS = 524; 
+
+    public static final int VK_CONTEXT_MENU = 525;
+
+    public static final int VK_CONVERT = 28;
+
+    public static final int VK_NONCONVERT = 29;
+
+    public static final int VK_ACCEPT = 30;
+
+    public static final int VK_MODECHANGE = 31;
+
+    public static final int VK_KANA = 21;
+
+    public static final int VK_KANJI = 25;
+
+    public static final int VK_ALPHANUMERIC = 240;
+
+    public static final int VK_KATAKANA = 241;
+
+    public static final int VK_HIRAGANA = 242;
+
+    public static final int VK_FULL_WIDTH = 243;
+
+    public static final int VK_HALF_WIDTH = 244;
+
+    public static final int VK_ROMAN_CHARACTERS = 245;
+
+    public static final int VK_ALL_CANDIDATES = 256;
+
+    public static final int VK_PREVIOUS_CANDIDATE = 257;
+
+    public static final int VK_CODE_INPUT = 258;
+
+    public static final int VK_JAPANESE_KATAKANA = 259;
+
+    public static final int VK_JAPANESE_HIRAGANA = 260;
+
+    public static final int VK_JAPANESE_ROMAN = 261;
+
+    public static final int VK_KANA_LOCK = 262;
+
+    public static final int VK_INPUT_METHOD_ON_OFF = 263;
+
+    public static final int VK_CUT = 65489;
+
+    public static final int VK_COPY = 65485;
+
+    public static final int VK_PASTE = 65487;
+
+    public static final int VK_UNDO = 65483;
+
+    public static final int VK_AGAIN = 65481;
+
+    public static final int VK_FIND = 65488;
+
+    public static final int VK_PROPS = 65482;
+
+    public static final int VK_STOP = 65480;
+
+    public static final int VK_COMPOSE = 65312;
+
+    public static final int VK_ALT_GRAPH = 65406;
+
+    public static final int VK_BEGIN = 65368;
+
+    public static final int VK_UNDEFINED = 0;
+
+    public static final char CHAR_UNDEFINED = (char)(-1);
+
+    public static final int KEY_LOCATION_UNKNOWN = 0;
+
+    public static final int KEY_LOCATION_STANDARD = 1;
+
+    public static final int KEY_LOCATION_LEFT = 2;
+
+    public static final int KEY_LOCATION_RIGHT = 3;
+
+    public static final int KEY_LOCATION_NUMPAD = 4;
+
+    private int keyCode;
+    private char keyChar;
+    private int keyLocation;
+
+    public static String getKeyModifiersText(int modifiers) {
+        return getKeyModifiersExText(extractExFlags(modifiers));
+    }
+
+    static String getKeyModifiersExText(int modifiersEx) {
+        String text = ""; //$NON-NLS-1$
+
+        if ((modifiersEx & InputEvent.META_DOWN_MASK) != 0) {
+            text += Toolkit.getProperty("AWT.meta", "Meta"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if ((modifiersEx & InputEvent.CTRL_DOWN_MASK) != 0) {
+            text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+                    Toolkit.getProperty("AWT.control", "Ctrl"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if ((modifiersEx & InputEvent.ALT_DOWN_MASK) != 0) {
+            text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+                    Toolkit.getProperty("AWT.alt", "Alt"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if ((modifiersEx & InputEvent.SHIFT_DOWN_MASK) != 0) {
+            text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+                    Toolkit.getProperty("AWT.shift", "Shift"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if ((modifiersEx & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) {
+            text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+                    Toolkit.getProperty("AWT.altGraph", "Alt Graph"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        return text;
+    }
+
+    public static String getKeyText(int keyCode) {
+        String[] rawName = getPublicStaticFinalIntFieldName(keyCode); //$NON-NLS-1$
+
+        if ((rawName == null) || (rawName.length == 0)) {
+            return ("Unknown keyCode: " + (keyCode >= 0 ? "0x" : "-0x") + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                    Integer.toHexString(Math.abs(keyCode)));
+        }
+
+        String propertyName = getPropertyName(rawName);
+        String defaultName = getDefaultName(rawName);
+
+        return Toolkit.getProperty(propertyName, defaultName);
+    }
+
+    private static String getDefaultName(String[] rawName) {
+        String name = ""; //$NON-NLS-1$
+
+        for (int i = 0; true; i++) {
+            String part = rawName[i];
+
+            name += new String(new char[] {part.charAt(0)}).toUpperCase() +
+                    part.substring(1).toLowerCase();
+
+            if (i == (rawName.length - 1)) {
+                break;
+            }
+            name += " "; //$NON-NLS-1$
+        }
+
+        return name;
+    }
+
+    private static String getPropertyName(String[] rawName) {
+        String name = rawName[0].toLowerCase();
+
+        for (int i = 1; i < rawName.length; i++) {
+            String part = rawName[i];
+
+            name += new String(new char[] {part.charAt(0)}).toUpperCase() +
+                    part.substring(1).toLowerCase();
+        }
+
+        return ("AWT." + name); //$NON-NLS-1$
+    }
+
+    private static String[] getPublicStaticFinalIntFieldName(int value) {
+        Field[] allFields = KeyEvent.class.getDeclaredFields();
+
+        try {
+            for (Field field : allFields) {
+                Class<?> ssalc = field.getType();
+                int modifiers = field.getModifiers();
+
+                if (ssalc.isPrimitive() && ssalc.getName().equals("int") && //$NON-NLS-1$
+                        Modifier.isFinal(modifiers) && Modifier.isPublic(modifiers) &&
+                        Modifier.isStatic(modifiers))
+                {
+                    if (field.getInt(null) == value){
+                        final String name = field.getName();
+                        final int prefixLength = name.indexOf("_") + 1;
+                        return name.substring(prefixLength).split("_"); //$NON-NLS-1$
+                    }
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        return null;
+    }
+
+    @Deprecated
+    public KeyEvent(Component src, int id,
+                    long when, int modifiers,
+                    int keyCode) {
+        this(src, id, when, modifiers, keyCode,
+                (keyCode > (2 << 7) - 1) ? CHAR_UNDEFINED : (char) keyCode);
+    }
+
+    public KeyEvent(Component src, int id,
+                    long when, int modifiers,
+                    int keyCode, char keyChar) {
+        this(src, id, when, modifiers, keyCode, keyChar, KEY_LOCATION_UNKNOWN);
+    }
+
+    public KeyEvent(Component src, int id,
+                    long when, int modifiers,
+                    int keyCode, char keyChar,
+                    int keyLocation) {
+        super(src, id, when, modifiers);
+
+        if (id == KEY_TYPED) {
+            if (keyCode != VK_UNDEFINED) {
+                // awt.191=Invalid keyCode for KEY_TYPED event, must be VK_UNDEFINED
+                throw new IllegalArgumentException(Messages.getString("awt.191")); //$NON-NLS-1$
+            }
+            if (keyChar == CHAR_UNDEFINED) {
+                // awt.192=Invalid keyChar for KEY_TYPED event, can't be CHAR_UNDEFINED
+                throw new IllegalArgumentException(Messages.getString("awt.192")); //$NON-NLS-1$
+            }
+        }
+        
+        if ((keyLocation < KEY_LOCATION_UNKNOWN)
+                || (keyLocation > KEY_LOCATION_NUMPAD)) {
+            // awt.297=Invalid keyLocation
+            throw new IllegalArgumentException(Messages.getString("awt.297")); //$NON-NLS-1$
+        }
+
+        this.keyChar = keyChar;
+        this.keyLocation = keyLocation;
+        this.keyCode = keyCode;
+    }
+
+    public int getKeyCode() {
+        return keyCode;
+    }
+
+    public void setKeyCode(int keyCode) {
+        this.keyCode = keyCode;
+    }
+
+    public char getKeyChar() {
+        return keyChar;
+    }
+
+    public void setKeyChar(char keyChar) {
+        this.keyChar = keyChar;
+    }
+
+    public int getKeyLocation() {
+        return keyLocation;
+    }
+
+    @Override
+    @Deprecated
+    public void setModifiers(int modifiers) {
+        super.setModifiers(modifiers);
+    }
+
+    public boolean isActionKey() {
+        return ((keyChar == CHAR_UNDEFINED) && (keyCode != VK_UNDEFINED) &&
+                !((keyCode == VK_ALT) || (keyCode == VK_ALT_GRAPH) ||
+                    (keyCode == VK_CONTROL) || (keyCode == VK_META) || (keyCode == VK_SHIFT)));
+    }
+
+    @Override
+    public String paramString() {
+        /*
+         * The format is based on 1.5 release behavior
+         * which can be revealed by the following code:
+         *
+         * KeyEvent e = new KeyEvent(new Component() {}, 
+         *       KeyEvent.KEY_PRESSED, 0, 
+         *       KeyEvent.CTRL_DOWN_MASK|KeyEvent.SHIFT_DOWN_MASK, 
+         *       KeyEvent.VK_A, 'A', KeyEvent.KEY_LOCATION_STANDARD);
+         * System.out.println(e);
+         */
+
+        String idString = null;
+        String locString = null;
+        String paramString = null;
+        String keyCharString = (keyChar == '\n') ?
+                keyCharString = getKeyText(VK_ENTER) : "'" + keyChar + "'"; //$NON-NLS-1$ //$NON-NLS-2$
+
+        switch (id) {
+        case KEY_PRESSED:
+            idString = "KEY_PRESSED"; //$NON-NLS-1$
+            break;
+        case KEY_RELEASED:
+            idString = "KEY_RELEASED"; //$NON-NLS-1$
+            break;
+        case KEY_TYPED:
+            idString = "KEY_TYPED"; //$NON-NLS-1$
+            break;
+        default:
+            idString = "unknown type"; //$NON-NLS-1$
+        }
+
+        switch(keyLocation){
+        case KEY_LOCATION_STANDARD:
+            locString = "KEY_LOCATION_STANDARD"; //$NON-NLS-1$
+            break;
+        case KEY_LOCATION_LEFT:
+            locString = "KEY_LOCATION_LEFT"; //$NON-NLS-1$
+            break;
+        case KEY_LOCATION_RIGHT:
+            locString = "KEY_LOCATION_RIGHT"; //$NON-NLS-1$
+            break;
+        case KEY_LOCATION_NUMPAD:
+            locString = "KEY_LOCATION_NUMPAD"; //$NON-NLS-1$
+            break;
+        case KEY_LOCATION_UNKNOWN:
+            locString = "KEY_LOCATION_UNKNOWN"; //$NON-NLS-1$
+            break;
+        default:
+            locString = "unknown type"; //$NON-NLS-1$
+        }
+
+        paramString = idString + ",keyCode=" + keyCode; //$NON-NLS-1$
+        if (isActionKey()) {
+            paramString += "," + getKeyText(keyCode); //$NON-NLS-1$
+        } else {
+            paramString += ",keyChar=" + keyCharString; //$NON-NLS-1$
+        }
+        if (getModifiersEx() > 0) {
+            paramString += ",modifiers=" + getModifiersExText(getModifiersEx()) + //$NON-NLS-1$
+                    ",extModifiers=" + getModifiersExText(getModifiersEx()); //$NON-NLS-1$
+        }
+        paramString += ",keyLocation=" + locString; //$NON-NLS-1$
+
+        return paramString;
+    }
+
+}
diff --git a/awt/java/awt/event/KeyListener.java b/awt/java/awt/event/KeyListener.java
new file mode 100644
index 0000000..ec144df
--- /dev/null
+++ b/awt/java/awt/event/KeyListener.java
@@ -0,0 +1,39 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface KeyListener extends EventListener {
+
+    public void keyPressed(KeyEvent e);
+
+    public void keyReleased(KeyEvent e);
+
+    public void keyTyped(KeyEvent e);
+
+}
diff --git a/awt/java/awt/event/MouseAdapter.java b/awt/java/awt/event/MouseAdapter.java
new file mode 100644
index 0000000..dc19173
--- /dev/null
+++ b/awt/java/awt/event/MouseAdapter.java
@@ -0,0 +1,49 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class MouseAdapter implements MouseListener {
+
+    public MouseAdapter() {
+    }
+
+    public void mouseClicked(MouseEvent e) {
+    }
+
+    public void mouseEntered(MouseEvent e) {
+    }
+
+    public void mouseExited(MouseEvent e) {
+    }
+
+    public void mousePressed(MouseEvent e) {
+    }
+
+    public void mouseReleased(MouseEvent e) {
+    }
+
+}
diff --git a/awt/java/awt/event/MouseEvent.java b/awt/java/awt/event/MouseEvent.java
new file mode 100644
index 0000000..2b1fa8b
--- /dev/null
+++ b/awt/java/awt/event/MouseEvent.java
@@ -0,0 +1,232 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+import java.awt.Point;
+import java.awt.Toolkit;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class MouseEvent extends InputEvent {
+
+    private static final long serialVersionUID = -991214153494842848L;
+
+    public static final int MOUSE_FIRST = 500;
+
+    public static final int MOUSE_LAST = 507;
+
+    public static final int MOUSE_CLICKED = 500;
+
+    public static final int MOUSE_PRESSED = 501;
+
+    public static final int MOUSE_RELEASED = 502;
+
+    public static final int MOUSE_MOVED = 503;
+
+    public static final int MOUSE_ENTERED = 504;
+
+    public static final int MOUSE_EXITED = 505;
+
+    public static final int MOUSE_DRAGGED = 506;
+
+    public static final int MOUSE_WHEEL = 507;
+
+    public static final int NOBUTTON = 0;
+
+    public static final int BUTTON1 = 1;
+
+    public static final int BUTTON2 = 2;
+
+    public static final int BUTTON3 = 3;
+
+    private boolean popupTrigger;
+    private int clickCount;
+    private int button;
+    private int x;
+    private int y;
+
+    public static String getMouseModifiersText(int modifiers) {
+        final StringBuffer text = new StringBuffer();
+
+        if ((modifiers & META_MASK) != 0) {
+            text.append(Toolkit.getProperty("AWT.meta", "Meta")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+        if ((modifiers & SHIFT_MASK) != 0) {
+            text.append(Toolkit.getProperty("AWT.shift", "Shift")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+        if ((modifiers & CTRL_MASK) != 0) {
+            text.append(Toolkit.getProperty("AWT.control", "Ctrl")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+        if ((modifiers & ALT_MASK) != 0) {
+            text.append(Toolkit.getProperty("AWT.alt", "Alt")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+        if ((modifiers & ALT_GRAPH_MASK) != 0) {
+            text.append(Toolkit.getProperty("AWT.altGraph", "Alt Graph")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+        if ((modifiers & BUTTON1_MASK) != 0) {
+            text.append(Toolkit.getProperty("AWT.button1", "Button1")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+        if ((modifiers & BUTTON2_MASK) != 0) {
+            text.append(Toolkit.getProperty("AWT.button2", "Button2")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+        if ((modifiers & BUTTON3_MASK) != 0) {
+            text.append(Toolkit.getProperty("AWT.button3", "Button3")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+
+        return text.length() == 0 ? text.toString() : text.substring(0, text
+                .length() - 1);
+    }
+
+    static String addMouseModifiersExText(String text, int modifiersEx) {
+        if ((modifiersEx & InputEvent.BUTTON1_DOWN_MASK) != 0) {
+            text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+                    Toolkit.getProperty("AWT.button1", "Button1"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if ((modifiersEx & InputEvent.BUTTON2_DOWN_MASK) != 0) {
+            text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+                    Toolkit.getProperty("AWT.button2", "Button2"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if ((modifiersEx & InputEvent.BUTTON3_DOWN_MASK) != 0) {
+            text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+                    Toolkit.getProperty("AWT.button3", "Button3"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        return text;
+    }
+
+    public MouseEvent(Component source, int id, long when,
+                      int modifiers, int x, int y,
+                      int clickCount, boolean popupTrigger) {
+        this(source, id, when, modifiers, x, y,
+             clickCount, popupTrigger, NOBUTTON);
+    }
+
+    public MouseEvent(Component source, int id, long when,
+                      int modifiers, int x, int y,
+                      int clickCount, boolean popupTrigger, int button) {
+        super(source, id, when, modifiers);
+
+        if ((button != NOBUTTON) && (button != BUTTON1) &&
+                (button != BUTTON2) && (button != BUTTON3)) {
+            // awt.18B=Invalid button value
+            throw new IllegalArgumentException(Messages.getString("awt.18B")); //$NON-NLS-1$
+        }
+
+        this.popupTrigger = popupTrigger;
+        this.clickCount = clickCount;
+        this.button = button;
+        this.x = x;
+        this.y = y;
+    }
+
+    public int getButton() {
+        return button;
+    }
+
+    public int getClickCount() {
+        return clickCount;
+    }
+
+    public Point getPoint() {
+        return new Point(x, y);
+    }
+
+    public int getX() {
+        return x;
+    }
+
+    public int getY() {
+        return y;
+    }
+
+    public boolean isPopupTrigger() {
+        return popupTrigger;
+    }
+
+    public void translatePoint(int x, int y) {
+        this.x += x;
+        this.y += y;
+    }
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * MouseEvent e = new MouseEvent(new Component(){}, 
+         *          MouseEvent.MOUSE_PRESSED, 0, 
+         *          MouseEvent.BUTTON1_DOWN_MASK|MouseEvent.CTRL_DOWN_MASK,
+         *          10, 20, 1, false, MouseEvent.BUTTON1);
+         * System.out.println(e);
+         */
+
+        String idString = null;
+        String paramString = null;
+
+        switch (id) {
+        case MOUSE_MOVED:
+            idString = "MOUSE_MOVED"; //$NON-NLS-1$
+            break;
+        case MOUSE_CLICKED:
+            idString = "MOUSE_CLICKED"; //$NON-NLS-1$
+            break;
+        case MOUSE_PRESSED:
+            idString = "MOUSE_PRESSED"; //$NON-NLS-1$
+            break;
+        case MOUSE_RELEASED:
+            idString = "MOUSE_RELEASED"; //$NON-NLS-1$
+            break;
+        case MOUSE_DRAGGED:
+            idString = "MOUSE_DRAGGED"; //$NON-NLS-1$
+            break;
+        case MOUSE_ENTERED:
+            idString = "MOUSE_ENTERED"; //$NON-NLS-1$
+            break;
+        case MOUSE_EXITED:
+            idString = "MOUSE_EXITED"; //$NON-NLS-1$
+            break;
+        case MOUSE_WHEEL:
+            idString = "MOUSE_WHEEL"; //$NON-NLS-1$
+            break;
+        default:
+            idString = "unknown type"; //$NON-NLS-1$
+        }
+
+        paramString = idString + ",(" + getX() + "," + getY() + ")" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                ",button=" + button; //$NON-NLS-1$
+        if (getModifiersEx() > 0) {
+            paramString += 
+                    ",modifiers=" + getModifiersExText(getModifiersEx()) + //$NON-NLS-1$
+                    ",extModifiers=" + getModifiersExText(getModifiersEx()); //$NON-NLS-1$
+        }
+        paramString += ",clickCount=" + getClickCount(); //$NON-NLS-1$
+
+        return paramString;
+    }
+
+}
diff --git a/awt/java/awt/event/MouseListener.java b/awt/java/awt/event/MouseListener.java
new file mode 100644
index 0000000..95879b9
--- /dev/null
+++ b/awt/java/awt/event/MouseListener.java
@@ -0,0 +1,43 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface MouseListener extends EventListener {
+
+    public void mouseClicked(MouseEvent e);
+
+    public void mouseEntered(MouseEvent e);
+
+    public void mouseExited(MouseEvent e);
+
+    public void mousePressed(MouseEvent e);
+
+    public void mouseReleased(MouseEvent e);
+
+}
diff --git a/awt/java/awt/event/MouseMotionAdapter.java b/awt/java/awt/event/MouseMotionAdapter.java
new file mode 100644
index 0000000..1ecd0d5
--- /dev/null
+++ b/awt/java/awt/event/MouseMotionAdapter.java
@@ -0,0 +1,40 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class MouseMotionAdapter implements MouseMotionListener {
+
+    public MouseMotionAdapter() {
+    }
+
+    public void mouseDragged(MouseEvent e) {
+    }
+
+    public void mouseMoved(MouseEvent e) {
+    }
+
+}
diff --git a/awt/java/awt/event/MouseMotionListener.java b/awt/java/awt/event/MouseMotionListener.java
new file mode 100644
index 0000000..e1313c3
--- /dev/null
+++ b/awt/java/awt/event/MouseMotionListener.java
@@ -0,0 +1,37 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface MouseMotionListener extends EventListener {
+
+    public void mouseDragged(MouseEvent e);
+
+    public void mouseMoved(MouseEvent e);
+
+}
diff --git a/awt/java/awt/event/MouseWheelEvent.java b/awt/java/awt/event/MouseWheelEvent.java
new file mode 100644
index 0000000..a3ed424
--- /dev/null
+++ b/awt/java/awt/event/MouseWheelEvent.java
@@ -0,0 +1,103 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class MouseWheelEvent extends MouseEvent {
+
+    private static final long serialVersionUID = -9187413581993563929L;
+
+    public static final int WHEEL_UNIT_SCROLL = 0;
+
+    public static final int WHEEL_BLOCK_SCROLL = 1;
+
+    private int wheelRotation;
+    private int scrollAmount;
+    private int scrollType;
+
+    public MouseWheelEvent(Component source, int id, long when, int modifiers,
+            int x, int y, int clickCount, boolean popupTrigger, int scrollType,
+            int scrollAmount, int wheelRotation) {
+        super(source, id, when, modifiers, x, y, clickCount, popupTrigger);
+
+        this.scrollType = scrollType;
+        this.scrollAmount = scrollAmount;
+        this.wheelRotation = wheelRotation;
+    }
+
+    public int getScrollAmount() {
+        return scrollAmount;
+    }
+
+    public int getScrollType() {
+        return scrollType;
+    }
+
+    public int getWheelRotation() {
+        return wheelRotation;
+    }
+
+    public int getUnitsToScroll() {
+        return (scrollAmount * wheelRotation);
+    }
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * MouseWheelEvent e = new MouseWheelEvent(new Component(){}, 
+         *          MouseWheelEvent.MOUSE_WHEEL, 0, 
+         *          MouseEvent.BUTTON1_DOWN_MASK|MouseEvent.CTRL_DOWN_MASK,
+         *          10, 20, 1, false, MouseWheelEvent.WHEEL_UNIT_SCROLL,
+         *          1, 3);
+         * System.out.println(e);
+         */
+
+        String paramString = super.paramString();
+        String typeString = null;
+
+        switch (scrollType) {
+        case WHEEL_UNIT_SCROLL:
+            typeString = "WHEEL_UNIT_SCROLL"; //$NON-NLS-1$
+            break;
+        case WHEEL_BLOCK_SCROLL:
+            typeString = "WHEEL_BLOCK_SCROLL"; //$NON-NLS-1$
+            break;
+        default:
+            typeString = "unknown type"; //$NON-NLS-1$
+        }
+
+        paramString += ",scrollType=" + typeString + //$NON-NLS-1$
+                ",scrollAmount=" + scrollAmount +  //$NON-NLS-1$
+                ",wheelRotation=" + wheelRotation; //$NON-NLS-1$
+
+        return paramString;
+    }
+
+}
diff --git a/awt/java/awt/event/MouseWheelListener.java b/awt/java/awt/event/MouseWheelListener.java
new file mode 100644
index 0000000..2d6a982
--- /dev/null
+++ b/awt/java/awt/event/MouseWheelListener.java
@@ -0,0 +1,35 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface MouseWheelListener extends EventListener {
+
+    public void mouseWheelMoved(MouseWheelEvent e);
+
+}
diff --git a/awt/java/awt/event/PaintEvent.java b/awt/java/awt/event/PaintEvent.java
new file mode 100644
index 0000000..22ac090
--- /dev/null
+++ b/awt/java/awt/event/PaintEvent.java
@@ -0,0 +1,86 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+import java.awt.Rectangle;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class PaintEvent extends ComponentEvent {
+
+    private static final long serialVersionUID = 1267492026433337593L;
+
+    public static final int PAINT_FIRST = 800;
+
+    public static final int PAINT_LAST = 801;
+
+    public static final int PAINT = 800;
+
+    public static final int UPDATE = 801;
+
+    private Rectangle updateRect;
+
+    public PaintEvent(Component source, int id, Rectangle updateRect) {
+        super(source, id);
+
+        this.updateRect = updateRect;
+    }
+
+    public Rectangle getUpdateRect() {
+        return updateRect;
+    }
+
+    public void setUpdateRect(Rectangle updateRect) {
+        this.updateRect = updateRect;
+    }
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * PaintEvent e = new PaintEvent(new Component(){}, 
+         *          PaintEvent.PAINT, new Rectangle(0, 0, 10, 20)); 
+         * System.out.println(e);
+         */
+
+        String typeString = null;
+
+        switch (id) {
+        case PAINT:
+            typeString = "PAINT"; //$NON-NLS-1$
+            break;
+        case UPDATE:
+            typeString = "UPDATE"; //$NON-NLS-1$
+            break;
+        default:
+            typeString = "unknown type"; //$NON-NLS-1$
+        }
+
+        return typeString + ",updateRect=" + updateRect; //$NON-NLS-1$
+    }
+
+}
diff --git a/awt/java/awt/event/TextEvent.java b/awt/java/awt/event/TextEvent.java
new file mode 100644
index 0000000..2a690ad
--- /dev/null
+++ b/awt/java/awt/event/TextEvent.java
@@ -0,0 +1,59 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class TextEvent extends AWTEvent {
+
+    private static final long serialVersionUID = 6269902291250941179L;
+
+    public static final int TEXT_FIRST = 900;
+
+    public static final int TEXT_LAST = 900;
+
+    public static final int TEXT_VALUE_CHANGED = 900;
+
+    public TextEvent(Object src, int id) {
+        super(src, id);
+    }
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * TextEvent e = new TextEvent(new Component(){}, 
+         *          TextEvent.TEXT_VALUE_CHANGED); 
+         * System.out.println(e);
+         */
+
+        return (id == TEXT_VALUE_CHANGED) ? 
+                "TEXT_VALUE_CHANGED" : "unknown type"; //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+}
diff --git a/awt/java/awt/event/TextListener.java b/awt/java/awt/event/TextListener.java
new file mode 100644
index 0000000..05757c4
--- /dev/null
+++ b/awt/java/awt/event/TextListener.java
@@ -0,0 +1,36 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface TextListener extends EventListener {
+
+    public void textValueChanged(TextEvent e);
+
+}
+
diff --git a/awt/java/awt/event/WindowAdapter.java b/awt/java/awt/event/WindowAdapter.java
new file mode 100644
index 0000000..970aa8d
--- /dev/null
+++ b/awt/java/awt/event/WindowAdapter.java
@@ -0,0 +1,64 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class WindowAdapter implements WindowListener, WindowStateListener, WindowFocusListener {
+
+    public WindowAdapter() {
+    }
+
+    public void windowActivated(WindowEvent e) {
+    }
+
+    public void windowClosed(WindowEvent e) {
+    }
+
+    public void windowClosing(WindowEvent e) {
+    }
+
+    public void windowDeactivated(WindowEvent e) {
+    }
+
+    public void windowDeiconified(WindowEvent e) {
+    }
+
+    public void windowGainedFocus(WindowEvent e) {
+    }
+
+    public void windowIconified(WindowEvent e) {
+    }
+
+    public void windowLostFocus(WindowEvent e) {
+    }
+
+    public void windowOpened(WindowEvent e) {
+    }
+
+    public void windowStateChanged(WindowEvent e) {
+    }
+
+}
diff --git a/awt/java/awt/event/WindowEvent.java b/awt/java/awt/event/WindowEvent.java
new file mode 100644
index 0000000..474d2ac
--- /dev/null
+++ b/awt/java/awt/event/WindowEvent.java
@@ -0,0 +1,168 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+
+//???AWT
+//import java.awt.Window;
+//import java.awt.Frame;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class WindowEvent extends ComponentEvent {
+
+    private static final long serialVersionUID = -1567959133147912127L;
+
+    public static final int WINDOW_FIRST = 200;
+
+    public static final int WINDOW_OPENED = 200;
+
+    public static final int WINDOW_CLOSING = 201;
+
+    public static final int WINDOW_CLOSED = 202;
+
+    public static final int WINDOW_ICONIFIED = 203;
+
+    public static final int WINDOW_DEICONIFIED = 204;
+
+    public static final int WINDOW_ACTIVATED = 205;
+
+    public static final int WINDOW_DEACTIVATED = 206;
+
+    public static final int WINDOW_GAINED_FOCUS = 207;
+
+    public static final int WINDOW_LOST_FOCUS = 208;
+
+    public static final int WINDOW_STATE_CHANGED = 209;
+
+    public static final int WINDOW_LAST = 209;
+
+    //???AWT: private Window oppositeWindow;
+    private int oldState;
+    private int newState;
+
+    //???AWT
+    /*
+    public WindowEvent(Window source, int id) {
+        this(source, id, null);
+    }
+
+    public WindowEvent(Window source, int id, Window opposite) {
+        this(source, id, opposite, Frame.NORMAL, Frame.NORMAL);
+    }
+
+    public WindowEvent(Window source, int id, int oldState, int newState) {
+        this(source, id, null, oldState, newState);
+    }
+
+    public WindowEvent(Window source, int id, Window opposite, 
+                       int oldState, int newState) {
+        super(source, id);
+
+        oppositeWindow = opposite;
+        this.oldState = oldState;
+        this.newState = newState;
+    }
+    */
+    //???AWT: Fake constructor
+    public WindowEvent() {
+        super(null, 0);
+    }
+    
+    public int getNewState() {
+        return newState;
+    }
+
+    public int getOldState() {
+        return oldState;
+    }
+
+    //???AWT
+    /*
+    public Window getOppositeWindow() {
+        return oppositeWindow;
+    }
+
+    public Window getWindow() {
+        return (Window) source;
+    }
+    */
+
+    @Override
+    public String paramString() {
+        /* The format is based on 1.5 release behavior 
+         * which can be revealed by the following code:
+         * 
+         * WindowEvent e = new WindowEvent(new Frame(), 
+         *          WindowEvent.WINDOW_OPENED); 
+         * System.out.println(e);
+         */
+
+        String typeString = null;
+
+        switch (id) {
+        case WINDOW_OPENED:
+            typeString = "WINDOW_OPENED"; //$NON-NLS-1$
+            break;
+        case WINDOW_CLOSING:
+            typeString = "WINDOW_CLOSING"; //$NON-NLS-1$
+            break;
+        case WINDOW_CLOSED:
+            typeString = "WINDOW_CLOSED"; //$NON-NLS-1$
+            break;
+        case WINDOW_ICONIFIED:
+            typeString = "WINDOW_ICONIFIED"; //$NON-NLS-1$
+            break;
+        case WINDOW_DEICONIFIED:
+            typeString = "WINDOW_DEICONIFIED"; //$NON-NLS-1$
+            break;
+        case WINDOW_ACTIVATED:
+            typeString = "WINDOW_ACTIVATED"; //$NON-NLS-1$
+            break;
+        case WINDOW_DEACTIVATED:
+            typeString = "WINDOW_DEACTIVATED"; //$NON-NLS-1$
+            break;
+        case WINDOW_GAINED_FOCUS:
+            typeString = "WINDOW_GAINED_FOCUS"; //$NON-NLS-1$
+            break;
+        case WINDOW_LOST_FOCUS:
+            typeString = "WINDOW_LOST_FOCUS"; //$NON-NLS-1$
+            break;
+        case WINDOW_STATE_CHANGED:
+            typeString = "WINDOW_STATE_CHANGED"; //$NON-NLS-1$
+            break;
+        default:
+            typeString = "unknown type"; //$NON-NLS-1$
+        }
+
+        //???AWT
+        /*
+        return typeString + ",opposite=" + oppositeWindow + //$NON-NLS-1$
+                ",oldState=" + oldState + ",newState=" + newState; //$NON-NLS-1$ //$NON-NLS-2$
+        */
+        return typeString;
+    }
+
+}
diff --git a/awt/java/awt/event/WindowFocusListener.java b/awt/java/awt/event/WindowFocusListener.java
new file mode 100644
index 0000000..528459f
--- /dev/null
+++ b/awt/java/awt/event/WindowFocusListener.java
@@ -0,0 +1,37 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface WindowFocusListener extends EventListener {
+
+    public void windowGainedFocus(WindowEvent e);
+
+    public void windowLostFocus(WindowEvent e);
+
+}
diff --git a/awt/java/awt/event/WindowListener.java b/awt/java/awt/event/WindowListener.java
new file mode 100644
index 0000000..31bd547
--- /dev/null
+++ b/awt/java/awt/event/WindowListener.java
@@ -0,0 +1,47 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface WindowListener extends EventListener {
+
+    public void windowActivated(WindowEvent e);
+
+    public void windowClosed(WindowEvent e);
+
+    public void windowClosing(WindowEvent e);
+
+    public void windowDeactivated(WindowEvent e);
+
+    public void windowDeiconified(WindowEvent e);
+
+    public void windowIconified(WindowEvent e);
+
+    public void windowOpened(WindowEvent e);
+
+}
diff --git a/awt/java/awt/event/WindowStateListener.java b/awt/java/awt/event/WindowStateListener.java
new file mode 100644
index 0000000..ba14d9e
--- /dev/null
+++ b/awt/java/awt/event/WindowStateListener.java
@@ -0,0 +1,36 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface WindowStateListener extends EventListener {
+
+    public void windowStateChanged(WindowEvent e);
+
+}
+
diff --git a/awt/java/awt/font/FontRenderContext.java b/awt/java/awt/font/FontRenderContext.java
new file mode 100644
index 0000000..d7de00f
--- /dev/null
+++ b/awt/java/awt/font/FontRenderContext.java
@@ -0,0 +1,178 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.geom.AffineTransform;
+
+/**
+ * The FontRenderContext class contains the information about text measurement.
+ * Anti-aliasing and fractional-metrics modes are defined by an application and
+ * affect the size of a character.
+ * 
+ * @since Android 1.0
+ */
+public class FontRenderContext {
+
+    // Affine transform of this mode
+    /**
+     * The transform.
+     */
+    private AffineTransform transform;
+
+    // Is the anti-aliased mode used
+    /**
+     * The anti aliased.
+     */
+    private boolean fAntiAliased;
+
+    // Is the fractional metrics used
+    /**
+     * The fractional metrics.
+     */
+    private boolean fFractionalMetrics;
+
+
+    /**
+     * Instantiates a new FontRenderContext object with the specified
+     * AffineTransform, anti-aliasing and fractional metrics flags.
+     * 
+     * @param trans
+     *            the AffineTransform.
+     * @param antiAliased
+     *            the anti-aliasing flag.
+     * @param usesFractionalMetrics
+     *            the fractional metrics flag.
+     */
+    public FontRenderContext(AffineTransform trans, boolean antiAliased, 
+            boolean usesFractionalMetrics) {
+        if (trans != null){
+            transform = new AffineTransform(trans);
+        }
+        fAntiAliased = antiAliased;
+        fFractionalMetrics = usesFractionalMetrics;
+    }
+
+    /**
+     * Instantiates a new FontRenderContext object.
+     */
+    protected FontRenderContext() {
+    }
+
+    /**
+     * Compares the specified Object with current FontRenderContext object.
+     * 
+     * @param obj
+     *            the Object to be compared.
+     * @return true, if the specified Object is equal to current
+     *         FontRenderContext object.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj != null) {
+            try {
+                return equals((FontRenderContext) obj);
+            } catch (ClassCastException e) {
+                return false;
+            }
+        }
+        return false;
+
+    }
+
+    /**
+     * Gets the transform which is used for scaling typographical points to
+     * pixels in this FontRenderContext.
+     * 
+     * @return the AffineTransform which is used for scaling typographical
+     *         points to pixels in this FontRenderContext.
+     */
+    public AffineTransform getTransform() {
+        if (transform != null){
+            return new AffineTransform(transform);
+        }
+        return new AffineTransform();
+    }
+
+    /**
+     * Compares the specified FontRenderContext object with current
+     * FontRenderContext.
+     * 
+     * @param frc
+     *            the FontRenderContext object to be compared.
+     * @return true, if the specified FontRenderContext object is equal to
+     *         current FontRenderContext.
+     */
+    public boolean equals(FontRenderContext frc) {
+        if (this == frc){
+            return true;
+        }
+
+        if (frc == null){
+            return false;
+        }
+
+        if (!frc.getTransform().equals(this.getTransform()) &&
+            !frc.isAntiAliased() == this.fAntiAliased &&
+            !frc.usesFractionalMetrics() == this.fFractionalMetrics){
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns true if the text fractional metrics are used in this
+     * FontRenderContext.
+     * 
+     * @return true, if the text fractional metrics are used in this
+     *         FontRenderContext, false otherwise.
+     */
+    public boolean usesFractionalMetrics() {
+        return this.fFractionalMetrics;
+    }
+
+    /**
+     * Returns true if anti-aliasing is used in this FontRenderContext.
+     * 
+     * @return true, if is anti-aliasing is used in this FontRenderContext,
+     *         false otherwise.
+     */
+    public boolean isAntiAliased() {
+        return this.fAntiAliased;
+    }
+
+    /**
+     * Returns hash code of the FontRenderContext object.
+     * 
+     * @return the hash code of the FontRenderContext object.
+     */
+    @Override
+    public int hashCode() {
+        return this.getTransform().hashCode() ^
+                new Boolean(this.fFractionalMetrics).hashCode() ^
+                new Boolean(this.fAntiAliased).hashCode();
+    }
+
+}
+
diff --git a/awt/java/awt/font/GlyphJustificationInfo.java b/awt/java/awt/font/GlyphJustificationInfo.java
new file mode 100644
index 0000000..b03de0a
--- /dev/null
+++ b/awt/java/awt/font/GlyphJustificationInfo.java
@@ -0,0 +1,197 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GlyphJustificationInfo class provides information about the glyph's
+ * justification properties. There are four justification properties: weight,
+ * priority, absorb, and limit.
+ * <p>
+ * There are two sets of metrics: growing and shrinking. Growing metrics are
+ * used when the glyphs are to be spread apart to fit a larger width. Shrinking
+ * metrics are used when the glyphs are to be moved together to fit a smaller
+ * width.
+ * </p>
+ * 
+ * @since Android 1.0
+ */
+public final class GlyphJustificationInfo {
+
+    /**
+     * The Constant PRIORITY_KASHIDA indicates the highest justification
+     * priority.
+     */
+    public static final int PRIORITY_KASHIDA = 0;
+
+    /**
+     * The Constant PRIORITY_WHITESPACE indicates the second highest
+     * justification priority.
+     */
+    public static final int PRIORITY_WHITESPACE = 1;
+
+    /**
+     * The Constant PRIORITY_INTERCHAR indicates the second lowest justification
+     * priority.
+     */
+    public static final int PRIORITY_INTERCHAR = 2;
+
+    /**
+     * The Constant PRIORITY_NONE indicates the lowest justification priority.
+     */
+    public static final int PRIORITY_NONE = 3;
+
+    /**
+     * The grow absorb flag indicates if this glyph absorbs all extra space at
+     * this and lower priority levels when it grows.
+     */
+    public final boolean growAbsorb;
+
+    /**
+     * The grow left limit value represents the maximum value by which the left
+     * side of this glyph grows.
+     */
+    public final float growLeftLimit;
+
+    /**
+     * The grow right limit value repesents the maximum value by which the right
+     * side of this glyph grows.
+     */
+    public final float growRightLimit;
+
+    /**
+     * The grow priority value represents the priority level of this glyph as it
+     * is growing.
+     */
+    public final int growPriority;
+
+    /**
+     * The shrink absorb fleg indicates this glyph absorbs all remaining
+     * shrinkage at this and lower priority levels as it shrinks.
+     */
+    public final boolean shrinkAbsorb;
+
+    /**
+     * The shrink left limit value represents the maximum value by which the
+     * left side of this glyph shrinks.
+     */
+    public final float shrinkLeftLimit;
+
+    /**
+     * The shrink right limit value represents the maximum value by which the
+     * right side of this glyph shrinks.
+     */
+    public final float shrinkRightLimit;
+
+    /**
+     * The shrink priority represents the glyth's priority level as it is
+     * shrinking.
+     */
+    public final int shrinkPriority;
+
+    /**
+     * The weight of the glyph.
+     */
+    public final float weight;
+
+    /**
+     * Instantiates a new GlyphJustificationInfo object which contains glyph's
+     * justification properties.
+     * 
+     * @param weight
+     *            the weight of glyph.
+     * @param growAbsorb
+     *            indicates if this glyph contais all space at this priority and
+     *            lower priority levels when it grows.
+     * @param growPriority
+     *            indicates the priority level of this glyph when it grows.
+     * @param growLeftLimit
+     *            indicates the maximum value of which the left side of this
+     *            glyph can grow.
+     * @param growRightLimit
+     *            the maximum value of which the right side of this glyph can
+     *            grow.
+     * @param shrinkAbsorb
+     *            indicates if this glyph contains all remaining shrinkage at
+     *            this and lower priority levels when it shrinks.
+     * @param shrinkPriority
+     *            indicates the glyph's priority level when it shrinks.
+     * @param shrinkLeftLimit
+     *            indicates the maximum value of which the left side of this
+     *            glyph can shrink.
+     * @param shrinkRightLimit
+     *            indicates the maximum amount by which the right side of this
+     *            glyph can shrink.
+     */
+    public GlyphJustificationInfo(float weight, boolean growAbsorb, int growPriority,
+            float growLeftLimit, float growRightLimit, boolean shrinkAbsorb, int shrinkPriority,
+            float shrinkLeftLimit, float shrinkRightLimit) {
+
+        if (weight < 0) {
+            // awt.19C=weight must be a positive number
+            throw new IllegalArgumentException(Messages.getString("awt.19C")); //$NON-NLS-1$
+        }
+        this.weight = weight;
+
+        if (growLeftLimit < 0) {
+            // awt.19D=growLeftLimit must be a positive number
+            throw new IllegalArgumentException(Messages.getString("awt.19D")); //$NON-NLS-1$
+        }
+        this.growLeftLimit = growLeftLimit;
+
+        if (growRightLimit < 0) {
+            // awt.19E=growRightLimit must be a positive number
+            throw new IllegalArgumentException(Messages.getString("awt.19E")); //$NON-NLS-1$
+        }
+        this.growRightLimit = growRightLimit;
+
+        if ((shrinkPriority < 0) || (shrinkPriority > PRIORITY_NONE)) {
+            // awt.19F=incorrect value for shrinkPriority, more than
+            // PRIORITY_NONE or less than PRIORITY_KASHIDA value
+            throw new IllegalArgumentException(Messages.getString("awt.19F")); //$NON-NLS-1$
+        }
+        this.shrinkPriority = shrinkPriority;
+
+        if ((growPriority < 0) || (growPriority > PRIORITY_NONE)) {
+            // awt.200=incorrect value for growPriority, more than PRIORITY_NONE
+            // or less than PRIORITY_KASHIDA value
+            throw new IllegalArgumentException(Messages.getString("awt.200")); //$NON-NLS-1$
+        }
+        this.growPriority = growPriority;
+
+        if (shrinkLeftLimit < 0) {
+            // awt.201=shrinkLeftLimit must be a positive number
+            throw new IllegalArgumentException(Messages.getString("awt.201")); //$NON-NLS-1$
+        }
+        this.shrinkLeftLimit = shrinkLeftLimit;
+
+        if (shrinkRightLimit < 0) {
+            // awt.202=shrinkRightLimit must be a positive number
+            throw new IllegalArgumentException(Messages.getString("awt.202")); //$NON-NLS-1$
+        }
+        this.shrinkRightLimit = shrinkRightLimit;
+
+        this.shrinkAbsorb = shrinkAbsorb;
+        this.growAbsorb = growAbsorb;
+    }
+}
diff --git a/awt/java/awt/font/GlyphMetrics.java b/awt/java/awt/font/GlyphMetrics.java
new file mode 100644
index 0000000..2871722
--- /dev/null
+++ b/awt/java/awt/font/GlyphMetrics.java
@@ -0,0 +1,266 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The GlyphMetrics class provides information about the size and shape of a
+ * single glyph. Each glyph has information to specify whether its baseline is
+ * horizontal or vertical as well as information on how it interacts with other
+ * characters in a text, given as one of the following types: STANDARD,
+ * LIGATURE, COMBINING, or COMPONENT.
+ * 
+ * @since Android 1.0
+ */
+public final class GlyphMetrics {
+
+    // advance width of the glyph character cell
+    /**
+     * The advance x.
+     */
+    private float advanceX;
+
+    // advance height of the glyph character cell
+    /**
+     * The advance y.
+     */
+    private float advanceY;
+
+    // flag if the glyph horizontal
+    /**
+     * The horizontal.
+     */
+    private boolean horizontal;
+
+    // glyph type code
+    /**
+     * The glyph type.
+     */
+    private byte glyphType;
+
+    // bounding box for outline of the glyph
+    /**
+     * The bounds.
+     */
+    private Rectangle2D.Float bounds;
+
+    /**
+     * The Constant STANDARD indicates a glyph that represents a single
+     * character.
+     */
+    public static final byte STANDARD = 0;
+
+    /**
+     * The Constant LIGATURE indicates a glyph that represents multiple
+     * characters as a ligature.
+     */
+    public static final byte LIGATURE = 1;
+
+    /**
+     * The Constant COMBINING indicates a glyph which has no caret position
+     * between glyphs (for example umlaut).
+     */
+    public static final byte COMBINING = 2;
+
+    /**
+     * The Constant COMPONENT indicates a glyph with no corresponding character
+     * in the backing store.
+     */
+    public static final byte COMPONENT = 3;
+
+    /**
+     * The Constant WHITESPACE indicates a glyph without visual representation.
+     */
+    public static final byte WHITESPACE = 4;
+
+    /**
+     * Instantiates a new GlyphMetrics object with the specified parameters.
+     * 
+     * @param horizontal
+     *            specifies if metrics are for a horizontal baseline (true
+     *            value), or a vertical baseline (false value).
+     * @param advanceX
+     *            the X component of the glyph's advance.
+     * @param advanceY
+     *            the Y component of the glyph's advance.
+     * @param bounds
+     *            the glyph's bounds.
+     * @param glyphType
+     *            the glyph's type.
+     */
+    public GlyphMetrics(boolean horizontal, float advanceX, float advanceY, Rectangle2D bounds,
+            byte glyphType) {
+        this.horizontal = horizontal;
+        this.advanceX = advanceX;
+        this.advanceY = advanceY;
+
+        this.bounds = new Rectangle2D.Float();
+        this.bounds.setRect(bounds);
+
+        this.glyphType = glyphType;
+    }
+
+    /**
+     * Instantiates a new horizontal GlyphMetrics with the specified parameters.
+     * 
+     * @param advanceX
+     *            the X component of the glyph's advance.
+     * @param bounds
+     *            the glyph's bounds.
+     * @param glyphType
+     *            the glyph's type.
+     */
+    public GlyphMetrics(float advanceX, Rectangle2D bounds, byte glyphType) {
+        this.advanceX = advanceX;
+        this.advanceY = 0;
+
+        this.horizontal = true;
+
+        this.bounds = new Rectangle2D.Float();
+        this.bounds.setRect(bounds);
+
+        this.glyphType = glyphType;
+    }
+
+    /**
+     * Gets the glyph's bounds.
+     * 
+     * @return glyph's bounds.
+     */
+    public Rectangle2D getBounds2D() {
+        return (Rectangle2D.Float)this.bounds.clone();
+    }
+
+    /**
+     * Checks if this glyph is whitespace or not.
+     * 
+     * @return true, if this glyph is whitespace, false otherwise.
+     */
+    public boolean isWhitespace() {
+        return ((this.glyphType & 4) == WHITESPACE);
+    }
+
+    /**
+     * Checks if this glyph is standard or not.
+     * 
+     * @return true, if this glyph is standard, false otherwise.
+     */
+    public boolean isStandard() {
+        return ((this.glyphType & 3) == STANDARD);
+    }
+
+    /**
+     * Checks if this glyph is ligature or not.
+     * 
+     * @return true, if this glyph is ligature, false otherwise.
+     */
+    public boolean isLigature() {
+        return ((this.glyphType & 3) == LIGATURE);
+    }
+
+    /**
+     * Checks if this glyph is component or not.
+     * 
+     * @return true, if this glyph is component, false otherwise.
+     */
+    public boolean isComponent() {
+        return ((this.glyphType & 3) == COMPONENT);
+    }
+
+    /**
+     * Checks if this glyph is combining or not.
+     * 
+     * @return true, if this glyph is combining, false otherwise.
+     */
+    public boolean isCombining() {
+        return ((this.glyphType & 3) == COMBINING);
+    }
+
+    /**
+     * Gets the glyph's type.
+     * 
+     * @return the glyph's type.
+     */
+    public int getType() {
+        return this.glyphType;
+    }
+
+    /**
+     * Gets the distance from the right (for horizontal) or bottom (for
+     * vertical) of the glyph bounds to the advance.
+     * 
+     * @return the distance from the right (for horizontal) or bottom (for
+     *         vertical) of the glyph bounds to the advance.
+     */
+    public float getRSB() {
+        if (this.horizontal) {
+            return this.advanceX - this.bounds.x - (float)this.bounds.getWidth();
+        }
+        return this.advanceY - this.bounds.y - (float)this.bounds.getHeight();
+    }
+
+    /**
+     * Gets the distance from 0, 0 to the left (for horizontal) or top (for
+     * vertical) of the glyph bounds.
+     * 
+     * @return the distance from 0, 0 to the left (for horizontal) or top (for
+     *         vertical) of the glyph bounds.
+     */
+    public float getLSB() {
+        if (this.horizontal) {
+            return this.bounds.x;
+        }
+        return this.bounds.y;
+    }
+
+    /**
+     * Gets the Y component of the glyph's advance.
+     * 
+     * @return the Y component of the glyph's advance.
+     */
+    public float getAdvanceY() {
+        return this.advanceY;
+    }
+
+    /**
+     * Gets the X component of the glyph's advance.
+     * 
+     * @return the X component of the glyph's advance.
+     */
+    public float getAdvanceX() {
+        return this.advanceX;
+    }
+
+    /**
+     * Gets the glyph's advance along the baseline.
+     * 
+     * @return the glyph's advance.
+     */
+    public float getAdvance() {
+        if (this.horizontal) {
+            return this.advanceX;
+        }
+        return this.advanceY;
+    }
+
+}
diff --git a/awt/java/awt/font/GlyphVector.java b/awt/java/awt/font/GlyphVector.java
new file mode 100644
index 0000000..a72b774
--- /dev/null
+++ b/awt/java/awt/font/GlyphVector.java
@@ -0,0 +1,403 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.awt.Font;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The GlyphVector class contains a collection of glyphs with geometric
+ * information and each glyph's location. Each GlyphVector can be associated
+ * with only one Font. GlyphVector contains the following properties for each
+ * glyph:
+ * <ul>
+ * <li>the glyph position;</li>
+ * <li>the transform of the glyph;</li>
+ * <li>the metrics of the glyph in the context of the GlyphVector.</li>
+ * </ul>
+ * 
+ * @since Android 1.0
+ */
+public abstract class GlyphVector implements Cloneable {
+
+    /**
+     * The Constant FLAG_HAS_TRANSFORMS indicates that this GlyphVector has
+     * per-glyph transforms.
+     */
+    public static final int FLAG_HAS_TRANSFORMS = 1;
+
+    /**
+     * The Constant FLAG_HAS_POSITION_ADJUSTMENTS indicates that the GlyphVector
+     * has per-glyph position adjustments.
+     */
+    public static final int FLAG_HAS_POSITION_ADJUSTMENTS = 2;
+
+    /**
+     * The Constant FLAG_RUN_RTL indicates that this GlyphVector has a right to
+     * left run direction.
+     */
+    public static final int FLAG_RUN_RTL = 4;
+
+    /**
+     * The Constant FLAG_COMPLEX_GLYPHS indicates that this GlyphVector has a
+     * complex glyph to char mapping.
+     */
+    public static final int FLAG_COMPLEX_GLYPHS = 8;
+
+    /**
+     * The Constant FLAG_MASK indicates a mask for supported flags from
+     * getLayoutFlags.
+     */
+    public static final int FLAG_MASK = 15; // (|) mask of other flags
+
+    /**
+     * Instantiates a new GlyphVector.
+     */
+    public GlyphVector() {
+    }
+
+    /**
+     * Gets the pixel bounds of the GlyphVector when rendered at the specified
+     * location with the specified FontRenderContext.
+     * 
+     * @param frc
+     *            the FontRenderContext.
+     * @param x
+     *            the X coordinate of the GlyphVector's location.
+     * @param y
+     *            the Y coordinate of the GlyphVector's location.
+     * @return the pixel bounds
+     */
+    public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) {
+        // default implementation - integer Rectangle, that encloses visual
+        // bounds rectangle
+        Rectangle2D visualRect = getVisualBounds();
+
+        int minX = (int)Math.floor(visualRect.getMinX() + x);
+        int minY = (int)Math.floor(visualRect.getMinY() + y);
+        int width = (int)Math.ceil(visualRect.getMaxX() + x) - minX;
+        int height = (int)Math.ceil(visualRect.getMaxY() + y) - minY;
+
+        return new Rectangle(minX, minY, width, height);
+    }
+
+    /**
+     * Gets the pixel bounds of the glyph with the specified index in this
+     * GlyphVector which is rendered with the specified FontRenderContext at the
+     * specified location.
+     * 
+     * @param index
+     *            the glyph index in this GlyphVector.
+     * @param frc
+     *            the FontRenderContext.
+     * @param x
+     *            the X coordinate of the GlyphVector's location.
+     * @param y
+     *            the Y coordinate of the GlyphVector's location.
+     * @return a Rectangle bounds.
+     */
+    public Rectangle getGlyphPixelBounds(int index, FontRenderContext frc, float x, float y) {
+        Rectangle2D visualRect = getGlyphVisualBounds(index).getBounds2D();
+
+        int minX = (int)Math.floor(visualRect.getMinX() + x);
+        int minY = (int)Math.floor(visualRect.getMinY() + y);
+        int width = (int)Math.ceil(visualRect.getMaxX() + x) - minX;
+        int height = (int)Math.ceil(visualRect.getMaxY() + y) - minY;
+
+        return new Rectangle(minX, minY, width, height);
+    }
+
+    /**
+     * Gets the visual bounds of the GlyphVector.
+     * 
+     * @return the visual bounds of the GlyphVector.
+     */
+    public abstract Rectangle2D getVisualBounds();
+
+    /**
+     * Gets the logical bounds of the GlyphVector.
+     * 
+     * @return the logical bounds of the GlyphVector.
+     */
+    public abstract Rectangle2D getLogicalBounds();
+
+    /**
+     * Sets the position of the specified glyph in this GlyphVector.
+     * 
+     * @param glyphIndex
+     *            the glyph index in this GlyphVector.
+     * @param newPos
+     *            the new position of the glyph at the specified glyphIndex.
+     */
+    public abstract void setGlyphPosition(int glyphIndex, Point2D newPos);
+
+    /**
+     * Gets the position of the specified glyph in this GlyphVector.
+     * 
+     * @param glyphIndex
+     *            the glyph index in this GlyphVector.
+     * @return the position of the specified glyph in this GlyphVector.
+     */
+    public abstract Point2D getGlyphPosition(int glyphIndex);
+
+    /**
+     * Sets the affine transform to a glyph with the specified index in this
+     * GlyphVector.
+     * 
+     * @param glyphIndex
+     *            the glyth index in this GlyphVector.
+     * @param trans
+     *            the AffineTransform to be assigned to the specified glyph.
+     */
+    public abstract void setGlyphTransform(int glyphIndex, AffineTransform trans);
+
+    /**
+     * Gets the transform of the specified glyph in this GlyphVector.
+     * 
+     * @param glyphIndex
+     *            the glyph index in this GlyphVector.
+     * @return the new transform of the glyph.
+     */
+    public abstract AffineTransform getGlyphTransform(int glyphIndex);
+
+    /**
+     * Compares this GlyphVector with the specified GlyphVector objects.
+     * 
+     * @param glyphVector
+     *            the GlyphVector object to be compared.
+     * @return true, if this GlyphVector is equal to the specified GlyphVector
+     *         object, false otherwise.
+     */
+    public abstract boolean equals(GlyphVector glyphVector);
+
+    /**
+     * Gets the metrics of the glyph with the specified index in this
+     * GlyphVector.
+     * 
+     * @param glyphIndex
+     *            index in this GlyphVector.
+     * @return the metrics of the glyph with the specified index in this
+     *         GlyphVector.
+     */
+    public abstract GlyphMetrics getGlyphMetrics(int glyphIndex);
+
+    /**
+     * Gets the justification information of the glyph whose index is specified.
+     * 
+     * @param glyphIndex
+     *            the glyph index.
+     * @return the GlyphJustificationInfo for the specified glyph.
+     */
+    public abstract GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex);
+
+    /**
+     * Gets the FontRenderContext of this GlyphVector.
+     * 
+     * @return the FontRenderContext of this GlyphVector.
+     */
+    public abstract FontRenderContext getFontRenderContext();
+
+    /**
+     * Gets a Shape object which defines the visual representation of the
+     * specified glyph in this GlyphVector, translated a distance of x in the X
+     * direction and y in the Y direction.
+     * 
+     * @param glyphIndex
+     *            the glyth index in this GlyphVector.
+     * @param x
+     *            the distance in the X direction to translate the shape object
+     *            before returning it.
+     * @param y
+     *            the distance in the Y direction to translate the shape object
+     *            before returning it.
+     * @return a Shape object which represents the visual representation of the
+     *         specified glyph in this GlyphVector - glyph outline.
+     */
+    public Shape getGlyphOutline(int glyphIndex, float x, float y) {
+        Shape initialShape = getGlyphOutline(glyphIndex);
+        AffineTransform trans = AffineTransform.getTranslateInstance(x, y);
+        return trans.createTransformedShape(initialShape);
+    }
+
+    /**
+     * Gets the visual bounds of the specified glyph in the GlyphVector.
+     * 
+     * @param glyphIndex
+     *            the glyph index in this GlyphVector.
+     * @return the glyph visual bounds of the glyph with the specified index in
+     *         the GlyphVector.
+     */
+    public abstract Shape getGlyphVisualBounds(int glyphIndex);
+
+    /**
+     * Gets a Shape object which defines the visual representation of the
+     * specified glyph in this GlyphVector.
+     * 
+     * @param glyphIndex
+     *            the glyth index in this GlyphVector.
+     * @return a Shape object which represents the visual representation of the
+     *         specified glyph in this GlyphVector - glyph outline.
+     */
+    public abstract Shape getGlyphOutline(int glyphIndex);
+
+    /**
+     * Gets the logical bounds of the specified glyph in the GlyphVector.
+     * 
+     * @param glyphIndex
+     *            the index in this GlyphVector of the glyph from which to
+     *            retrieve its logical bounds
+     * @return the logical bounds of the specified glyph in the GlyphVector.
+     */
+    public abstract Shape getGlyphLogicalBounds(int glyphIndex);
+
+    /**
+     * Gets the visual representation of this GlyphVector rendered in x, y
+     * location as a Shape object.
+     * 
+     * @param x
+     *            the x coordinate of the GlyphVector.
+     * @param y
+     *            the y coordinate of the GlyphVector.
+     * @return the visual representation of this GlyphVector as a Shape object.
+     */
+    public abstract Shape getOutline(float x, float y);
+
+    /**
+     * Gets the visual representation of this GlyphVector as a Shape object.
+     * 
+     * @return the visual representation of this GlyphVector as a Shape object.
+     */
+    public abstract Shape getOutline();
+
+    /**
+     * Gets the font of this GlyphVector.
+     * 
+     * @return the font of this GlyphVector.
+     */
+    public abstract Font getFont();
+
+    /**
+     * Gets an array of the glyph codes of the specified glyphs.
+     * 
+     * @param beginGlyphIndex
+     *            the index into this GlyphVector at which to start retrieving
+     *            glyph codes.
+     * @param numEntries
+     *            the number of glyph codes.
+     * @param codeReturn
+     *            the array into which the resulting glyphcodes will be written.
+     * @return the array of the glyph codes.
+     */
+    public abstract int[] getGlyphCodes(int beginGlyphIndex, int numEntries, int[] codeReturn);
+
+    /**
+     * Gets an array of the character indices of the specified glyphs.
+     * 
+     * @param beginGlyphIndex
+     *            the index of the first glyph to return information for.
+     * @param numEntries
+     *            the number of glyph indices to return.
+     * @param codeReturn
+     *            the array into which the resulting character indices will be
+     *            written.
+     * @return an array of character indices for the specifies glyphs.
+     */
+    public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries, int[] codeReturn) {
+        if (codeReturn == null) {
+            codeReturn = new int[numEntries];
+        }
+
+        for (int i = 0; i < numEntries; i++) {
+            codeReturn[i] = getGlyphCharIndex(i + beginGlyphIndex);
+        }
+        return codeReturn;
+    }
+
+    /**
+     * Gets an array of the positions of the specified glyphs in this
+     * GlyphVector.
+     * 
+     * @param beginGlyphIndex
+     *            the index of the first glyph to return information for.
+     * @param numEntries
+     *            the number of glyphs to return information for.
+     * @param positionReturn
+     *            the array where the result will be stored.
+     * @return an array of glyph positions.
+     */
+    public abstract float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
+            float[] positionReturn);
+
+    /**
+     * Gets the glyph code of the specified glyph.
+     * 
+     * @param glyphIndex
+     *            the index in this GlyphVector which corresponds to the glyph
+     *            from which to retrieve the glyphcode.
+     * @return the glyphcode of the specified glyph.
+     */
+    public abstract int getGlyphCode(int glyphIndex);
+
+    /**
+     * Gets the first logical character's index of the specified glyph.
+     * 
+     * @param glyphIndex
+     *            the glyph index.
+     * @return the the first logical character's index.
+     */
+    public int getGlyphCharIndex(int glyphIndex) {
+        // default implemetation one-to-one
+        return glyphIndex;
+    }
+
+    /**
+     * Sets default layout to this GlyphVector.
+     */
+    public abstract void performDefaultLayout();
+
+    /**
+     * Gets the number of glyphs in the GlyphVector.
+     * 
+     * @return the number of glyphs in the GlyphVector.
+     */
+    public abstract int getNumGlyphs();
+
+    /**
+     * Gets flags which describe the global state of the GlyphVector. The
+     * default implementation returns 0.
+     * 
+     * @return the layout flags
+     */
+    public int getLayoutFlags() {
+        // default implementation - returned value is 0
+        return 0;
+    }
+
+}
diff --git a/awt/java/awt/font/GraphicAttribute.java b/awt/java/awt/font/GraphicAttribute.java
new file mode 100644
index 0000000..8480e0f
--- /dev/null
+++ b/awt/java/awt/font/GraphicAttribute.java
@@ -0,0 +1,179 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GraphicAttribute abstract class provides an opportunity to insert
+ * graphical elements in printed text.
+ * 
+ * @since Android 1.0
+ */
+public abstract class GraphicAttribute {
+
+    /**
+     * The Constant TOP_ALIGNMENT indicates using the top line to calculate
+     * placement of graphics.
+     */
+    public static final int TOP_ALIGNMENT = -1;
+
+    /**
+     * The Constant BOTTOM_ALIGNMENT indicates using the bottom line to
+     * calculate placement of graphics.
+     */
+    public static final int BOTTOM_ALIGNMENT = -2;
+
+    /**
+     * The Constant ROMAN_BASELINE indicates the placement of the roman baseline
+     * with respect to the graphics origin.
+     */
+    public static final int ROMAN_BASELINE = 0;
+
+    /**
+     * The Constant CENTER_BASELINE indicates the placement of the center
+     * baseline with respect to the graphics origin.
+     */
+    public static final int CENTER_BASELINE = 1;
+
+    /**
+     * The Constant HANGING_BASELINE indicates the placement of the hanging
+     * baseline with respect to the graphics origin.
+     */
+    public static final int HANGING_BASELINE = 2;
+
+    // the alignment of this GraphicAttribute
+    /**
+     * The alignment.
+     */
+    private int alignment;
+
+    /**
+     * Instantiates a new graphic attribute with the specified alignment.
+     * 
+     * @param align
+     *            the specified alignment.
+     */
+    protected GraphicAttribute(int align) {
+        if ((align < BOTTOM_ALIGNMENT) || (align > HANGING_BASELINE)) {
+            // awt.198=Illegal alignment argument
+            throw new IllegalArgumentException(Messages.getString("awt.198")); //$NON-NLS-1$
+        }
+        this.alignment = align;
+    }
+
+    /**
+     * Draws the GraphicAttribute at the specified location.
+     * 
+     * @param graphics
+     *            the Graphics.
+     * @param x
+     *            the X coordinate of GraphicAttribute location.
+     * @param y
+     *            the Y coordinate of GraphicAttribute location.
+     */
+    public abstract void draw(Graphics2D graphics, float x, float y);
+
+    /**
+     * Gets the GraphicAttribute's advance. It's the distance from the point at
+     * which the graphic is rendered and the point where the next character or
+     * graphic is rendered.
+     * 
+     * @return the GraphicAttribute's advance.
+     */
+    public abstract float getAdvance();
+
+    /**
+     * Gets the alignment of this GraphicAttribute.
+     * 
+     * @return the alignment of this GraphicAttribute.
+     */
+    public final int getAlignment() {
+        return this.alignment;
+    }
+
+    /**
+     * Gets the ascent of this GraphicAttribute.
+     * 
+     * @return the ascent of this GraphicAttribute.
+     */
+    public abstract float getAscent();
+
+    /**
+     * Gets the bounds of this GraphicAttribute.
+     * 
+     * @return the bounds of this GraphicAttribute.
+     */
+    public Rectangle2D getBounds() {
+        float ascent = getAscent();
+        float advance = getAdvance();
+        float descent = getDescent();
+
+        // Default implementation - see API documentation.
+        return new Rectangle2D.Float(0, -ascent, advance, ascent + descent);
+    }
+
+    /**
+     * Gets the descent of this GraphicAttribute.
+     * 
+     * @return the descent of this GraphicAttribute.
+     */
+    public abstract float getDescent();
+
+    /**
+     * Gets the GlyphJustificationInfo of this GraphicAttribute.
+     * 
+     * @return the GlyphJustificationInfo of this GraphicAttribute.
+     */
+    public GlyphJustificationInfo getJustificationInfo() {
+
+        /*
+         * Default implementation. Since documentation doesn't describe default
+         * values, they were calculated based on 1.5 release behavior and can be
+         * obtained using next test sample: // Create GraphicAttribute class
+         * implementation public class MyGraphicAttribute extends
+         * GraphicAttribute { protected MyGraphicAttribute(int align) {
+         * super(align); } public float getDescent() { return 0; } public float
+         * getAdvance() { return 1; } public void draw(Graphics2D g2, float x,
+         * float y) { } public float getAscent() { return 0; } }
+         * MyGraphicAttribute myGA = gat.new MyGraphicAttribute(0); // print
+         * justification parameters
+         * System.out.println(myGA.getJustificationInfo().growAbsorb);
+         * System.out.println(myGA.getJustificationInfo().shrinkAbsorb);
+         * System.out.println(myGA.getJustificationInfo().growLeftLimit);
+         * System.out.println(myGA.getJustificationInfo().growPriority);
+         * System.out.println(myGA.getJustificationInfo().growRightLimit);
+         * System.out.println(myGA.getJustificationInfo().shrinkLeftLimit);
+         * System.out.println(myGA.getJustificationInfo().shrinkPriority);
+         * System.out.println(myGA.getJustificationInfo().shrinkRightLimit);
+         * System.out.println(myGA.getJustificationInfo().weight);
+         */
+        float advance = getAdvance();
+        return new GlyphJustificationInfo(advance, false,
+                GlyphJustificationInfo.PRIORITY_INTERCHAR, advance / 3, advance / 3, false,
+                GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, 0);
+    }
+
+}
diff --git a/awt/java/awt/font/ImageGraphicAttribute.java b/awt/java/awt/font/ImageGraphicAttribute.java
new file mode 100644
index 0000000..d6d4758
--- /dev/null
+++ b/awt/java/awt/font/ImageGraphicAttribute.java
@@ -0,0 +1,185 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The ImageGraphicAttribute class provides an opportunity to insert images to a
+ * text.
+ * 
+ * @since Android 1.0
+ */
+public final class ImageGraphicAttribute extends GraphicAttribute {
+
+    // Image object rendered by this ImageGraphicAttribute
+    /**
+     * The image.
+     */
+    private Image fImage;
+
+    // X coordinate of the origin point
+    /**
+     * The origin x.
+     */
+    private float fOriginX;
+
+    // Y coordinate of the origin point
+    /**
+     * The origin y.
+     */
+    private float fOriginY;
+
+    // the width of the image object
+    /**
+     * The img width.
+     */
+    private float fImgWidth;
+
+    // the height of the image object
+    /**
+     * The img height.
+     */
+    private float fImgHeight;
+
+    /**
+     * Instantiates a new ImageGraphicAttribute with the specified image,
+     * alignment and origins.
+     * 
+     * @param image
+     *            the Image to be rendered by ImageGraphicAttribute.
+     * @param alignment
+     *            the alignment of the ImageGraphicAttribute.
+     * @param originX
+     *            the origin X coordinate in the image of ImageGraphicAttribute.
+     * @param originY
+     *            the origin Y coordinate in the image of ImageGraphicAttribute.
+     */
+    public ImageGraphicAttribute(Image image, int alignment, float originX, float originY) {
+        super(alignment);
+
+        this.fImage = image;
+        this.fOriginX = originX;
+        this.fOriginY = originY;
+
+        this.fImgWidth = fImage.getWidth(null);
+        this.fImgHeight = fImage.getHeight(null);
+
+    }
+
+    /**
+     * Instantiates a new ImageGraphicAttribute with the specified image and
+     * alignment.
+     * 
+     * @param image
+     *            the Image to be rendered by ImageGraphicAttribute.
+     * @param alignment
+     *            the alignment of the ImageGraphicAttribute.
+     */
+    public ImageGraphicAttribute(Image image, int alignment) {
+        this(image, alignment, 0, 0);
+    }
+
+    /**
+     * Returns a hash code of this ImageGraphicAttribute object.
+     * 
+     * @return the hash code of this ImageGraphicAttribute object.
+     */
+    @Override
+    public int hashCode() {
+        HashCode hash = new HashCode();
+
+        hash.append(fImage.hashCode());
+        hash.append(getAlignment());
+        return hash.hashCode();
+    }
+
+    /**
+     * Compares the specified ImageGraphicAttribute object with this
+     * ImageGraphicAttribute object.
+     * 
+     * @param iga
+     *            the ImageGraphicAttribute object to be compared.
+     * @return true, if the specified ImageGraphicAttribute object is equal to
+     *         this ImageGraphicAttribute object, false otherwise.
+     */
+    public boolean equals(ImageGraphicAttribute iga) {
+        if (iga == null) {
+            return false;
+        }
+
+        if (iga == this) {
+            return true;
+        }
+
+        return (fOriginX == iga.fOriginX && fOriginY == iga.fOriginY
+                && getAlignment() == iga.getAlignment() && fImage.equals(iga.fImage));
+    }
+
+    /**
+     * Compares the specified Object with this ImageGraphicAttribute object.
+     * 
+     * @param obj
+     *            the Object to be compared.
+     * @return true, if the specified Object is equal to this
+     *         ImageGraphicAttribute object, false otherwise.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        try {
+            return equals((ImageGraphicAttribute)obj);
+        } catch (ClassCastException e) {
+            return false;
+        }
+
+    }
+
+    @Override
+    public void draw(Graphics2D g2, float x, float y) {
+        g2.drawImage(fImage, (int)(x - fOriginX), (int)(y - fOriginY), null);
+    }
+
+    @Override
+    public float getAdvance() {
+        return Math.max(0, fImgWidth - fOriginX);
+    }
+
+    @Override
+    public float getAscent() {
+        return Math.max(0, fOriginY);
+    }
+
+    @Override
+    public Rectangle2D getBounds() {
+        return new Rectangle2D.Float(-fOriginX, -fOriginY, fImgWidth, fImgHeight);
+    }
+
+    @Override
+    public float getDescent() {
+        return Math.max(0, fImgHeight - fOriginY);
+    }
+
+}
diff --git a/awt/java/awt/font/LineBreakMeasurer.java b/awt/java/awt/font/LineBreakMeasurer.java
new file mode 100644
index 0000000..4800093
--- /dev/null
+++ b/awt/java/awt/font/LineBreakMeasurer.java
@@ -0,0 +1,238 @@
+/*
+ *  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.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.text.AttributedCharacterIterator; //???AWT: import java.text.BreakIterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The class LineBreakMeasurer provides methods to measure the graphical
+ * representation of a text in order to determine where to add line breaks so
+ * the resulting line of text fits its wrapping width. The wrapping width
+ * defines the visual width of the paragraph.
+ * 
+ * @since Android 1.0
+ */
+public final class LineBreakMeasurer {
+
+    /**
+     * The tm.
+     */
+    private TextMeasurer tm = null;
+
+    // ???AWT private BreakIterator bi = null;
+    /**
+     * The position.
+     */
+    private int position = 0;
+
+    /**
+     * The maxpos.
+     */
+    int maxpos = 0;
+
+    /**
+     * Instantiates a new LineBreakMeasurer object for the specified text.
+     * 
+     * @param text
+     *            the AttributedCharacterIterator object which contains text
+     *            with at least one character.
+     * @param frc
+     *            the FontRenderContext represented information about graphic
+     *            device.
+     */
+    public LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc) {
+        // ???AWT: this(text, BreakIterator.getLineInstance(), frc);
+    }
+
+    /*
+     * ???AWT public LineBreakMeasurer( AttributedCharacterIterator text,
+     * BreakIterator bi, FontRenderContext frc ) { tm = new TextMeasurer(text,
+     * frc); this.bi = bi; this.bi.setText(text); position =
+     * text.getBeginIndex(); maxpos = tm.aci.getEndIndex(); }
+     */
+
+    /**
+     * Deletes a character from the specified position of the text, updates this
+     * LineBreakMeasurer object.
+     * 
+     * @param newText
+     *            the new text.
+     * @param pos
+     *            the position of the character which is deleted.
+     */
+    public void deleteChar(AttributedCharacterIterator newText, int pos) {
+        tm.deleteChar(newText, pos);
+        // ???AWT: bi.setText(newText);
+
+        position = newText.getBeginIndex();
+
+        maxpos--;
+    }
+
+    /**
+     * Gets current position of this LineBreakMeasurer.
+     * 
+     * @return the current position of this LineBreakMeasurer
+     */
+    public int getPosition() {
+        return position;
+    }
+
+    /**
+     * Inserts a character at the specified position in the text, updates this
+     * LineBreakMeasurer object.
+     * 
+     * @param newText
+     *            the new text.
+     * @param pos
+     *            the position of the character which is inserted.
+     */
+    public void insertChar(AttributedCharacterIterator newText, int pos) {
+        tm.insertChar(newText, pos);
+        // ???AWT: bi.setText(newText);
+
+        position = newText.getBeginIndex();
+
+        maxpos++;
+    }
+
+    /**
+     * Returns the next line of text, updates current position in this
+     * LineBreakMeasurer.
+     * 
+     * @param wrappingWidth
+     *            the maximum visible line width.
+     * @param offsetLimit
+     *            the limit point within the text indicating that no further
+     *            text should be included on the line; the paragraph break.
+     * @param requireNextWord
+     *            if true, null is returned (the entire word at the current
+     *            position does not fit within the wrapping width); if false, a
+     *            valid layout is returned that includes at least the character
+     *            at the current position.
+     * @return the next TextLayout which begins at the current position and
+     *         represents the next line of text with width wrappingWidth, null
+     *         is returned if the entire word at the current position does not
+     *         fit within the wrapping width.
+     */
+    public TextLayout nextLayout(float wrappingWidth, int offsetLimit, boolean requireNextWord) {
+        if (position == maxpos) {
+            return null;
+        }
+
+        int nextPosition = nextOffset(wrappingWidth, offsetLimit, requireNextWord);
+
+        if (nextPosition == position) {
+            return null;
+        }
+        TextLayout layout = tm.getLayout(position, nextPosition);
+        position = nextPosition;
+        return layout;
+    }
+
+    /**
+     * Returns the next line of text.
+     * 
+     * @param wrappingWidth
+     *            the maximum visible line width.
+     * @return the next line of text.
+     */
+    public TextLayout nextLayout(float wrappingWidth) {
+        return nextLayout(wrappingWidth, maxpos, false);
+    }
+
+    /**
+     * Returns the end position of the next line of text.
+     * 
+     * @param wrappingWidth
+     *            the maximum visible line width.
+     * @return the end position of the next line of text.
+     */
+    public int nextOffset(float wrappingWidth) {
+        return nextOffset(wrappingWidth, maxpos, false);
+    }
+
+    /**
+     * Returns the end position of the next line of text.
+     * 
+     * @param wrappingWidth
+     *            the maximum visible line width.
+     * @param offsetLimit
+     *            the limit point withing the text indicating that no further
+     *            text should be included on the line; the paragraph break.
+     * @param requireNextWord
+     *            if true, the current position is returned if the entire next
+     *            word does not fit within wrappingWidth; if false, the offset
+     *            returned is at least one greater than the current position.
+     * @return the end position of the next line of text.
+     * @throws IllegalArgumentException
+     *             if the offsetLimit is less than the current position.
+     */
+    public int nextOffset(float wrappingWidth, int offsetLimit, boolean requireNextWord) {
+        if (offsetLimit <= position) {
+            // awt.203=Offset limit should be greater than current position.
+            throw new IllegalArgumentException(Messages.getString("awt.203")); //$NON-NLS-1$
+        }
+
+        if (position == maxpos) {
+            return position;
+        }
+
+        int breakPos = tm.getLineBreakIndex(position, wrappingWidth);
+        int correctedPos = breakPos;
+
+        // This check is required because bi.preceding(maxpos) throws an
+        // exception
+        /*
+         * ???AWT if (breakPos == maxpos) { correctedPos = maxpos; } else if
+         * (Character.isWhitespace(bi.getText().setIndex(breakPos))) {
+         * correctedPos = bi.following(breakPos); } else { correctedPos =
+         * bi.preceding(breakPos); }
+         */
+
+        if (position >= correctedPos) {
+            if (requireNextWord) {
+                correctedPos = position;
+            } else {
+                correctedPos = Math.max(position + 1, breakPos);
+            }
+        }
+
+        return Math.min(correctedPos, offsetLimit);
+    }
+
+    /**
+     * Sets the new position of this LineBreakMeasurer.
+     * 
+     * @param pos
+     *            the new position of this LineBreakMeasurer.
+     */
+    public void setPosition(int pos) {
+        if (tm.aci.getBeginIndex() > pos || maxpos < pos) {
+            // awt.33=index is out of range
+            throw new IllegalArgumentException(Messages.getString("awt.33")); //$NON-NLS-1$
+        }
+        position = pos;
+    }
+}
diff --git a/awt/java/awt/font/LineMetrics.java b/awt/java/awt/font/LineMetrics.java
new file mode 100644
index 0000000..4b03e5d
--- /dev/null
+++ b/awt/java/awt/font/LineMetrics.java
@@ -0,0 +1,116 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+/**
+ * The LineMetrics class provides information such as concerning how the text is
+ * positioned with respect to the base line, such as ascent, descent, and
+ * leading.
+ * 
+ * @since Android 1.0
+ */
+public abstract class LineMetrics {
+
+    /**
+     * Gets the baseline offsets of the text according to the the baseline of
+     * this text.
+     * 
+     * @return the baseline offsets of the text according to the the baseline of
+     *         this text.
+     */
+    public abstract float[] getBaselineOffsets();
+
+    /**
+     * Gets the number of characters of the text.
+     * 
+     * @return the number of characters of the text.
+     */
+    public abstract int getNumChars();
+
+    /**
+     * Gets the baseline index, returns one of the following index:
+     * ROMAN_BASELINE, CENTER_BASELINE, HANGING_BASELINE.
+     * 
+     * @return the baseline index: ROMAN_BASELINE, CENTER_BASELINE or
+     *         HANGING_BASELINE.
+     */
+    public abstract int getBaselineIndex();
+
+    /**
+     * Gets the thickness of the underline.
+     * 
+     * @return the thickness of the underline.
+     */
+    public abstract float getUnderlineThickness();
+
+    /**
+     * Gets the offset of the underline.
+     * 
+     * @return the offset of the underline.
+     */
+    public abstract float getUnderlineOffset();
+
+    /**
+     * Gets the thickness of strike through line.
+     * 
+     * @return the thickness of strike through line.
+     */
+    public abstract float getStrikethroughThickness();
+
+    /**
+     * Gets the offset of the strike through line.
+     * 
+     * @return the offset of the strike through line.
+     */
+    public abstract float getStrikethroughOffset();
+
+    /**
+     * Gets the leading of the text.
+     * 
+     * @return the leading of the text.
+     */
+    public abstract float getLeading();
+
+    /**
+     * Gets the height of the text as a sum of the ascent, the descent and the
+     * leading.
+     * 
+     * @return the height of the text as a sum of the ascent, the descent and
+     *         the leading.
+     */
+    public abstract float getHeight();
+
+    /**
+     * Gets the descent of the text.
+     * 
+     * @return the descent of the text.
+     */
+    public abstract float getDescent();
+
+    /**
+     * Gets the ascent of the text.
+     * 
+     * @return the ascent of the text.
+     */
+    public abstract float getAscent();
+
+}
diff --git a/awt/java/awt/font/MultipleMaster.java b/awt/java/awt/font/MultipleMaster.java
new file mode 100644
index 0000000..d264f24
--- /dev/null
+++ b/awt/java/awt/font/MultipleMaster.java
@@ -0,0 +1,91 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.awt.Font;
+
+/**
+ * The MultipleMaster interface provides methods to manipulate MultipleMaster
+ * type fonts and retrieve graphical and design data from them.
+ * 
+ * @since Android 1.0
+ */
+public interface MultipleMaster {
+
+    /**
+     * Derives a new multiple master font based on the specified parameters.
+     * 
+     * @param glyphWidths
+     *            float array which represents width of each glyph in font
+     *            space.
+     * @param avgStemWidth
+     *            the average stem width in font space.
+     * @param typicalCapHeight
+     *            the typical upper case char height.
+     * @param typicalXHeight
+     *            the typical lower case char height.
+     * @param italicAngle
+     *            the slope angle for italics.
+     * @return a MultipleMaster font.
+     */
+    public Font deriveMMFont(float[] glyphWidths, float avgStemWidth, float typicalCapHeight,
+            float typicalXHeight, float italicAngle);
+
+    /**
+     * Derives a new multiple master font based on the design axis values
+     * contained in the specified array.
+     * 
+     * @param axes
+     *            an float array which contains axis values.
+     * @return a MultipleMaster font.
+     */
+    public Font deriveMMFont(float[] axes);
+
+    /**
+     * Gets default design values for the axes.
+     * 
+     * @return the default design values for the axes.
+     */
+    public float[] getDesignAxisDefaults();
+
+    /**
+     * Gets the array of design axis names.
+     * 
+     * @return the array of design axis names.
+     */
+    public String[] getDesignAxisNames();
+
+    /**
+     * Gets the array of design axis ranges.
+     * 
+     * @return the array of design axis ranges.
+     */
+    public float[] getDesignAxisRanges();
+
+    /**
+     * Gets the number of multiple master design controls.
+     * 
+     * @return the number of multiple master design controls.
+     */
+    public int getNumDesignAxes();
+
+}
diff --git a/awt/java/awt/font/OpenType.java b/awt/java/awt/font/OpenType.java
new file mode 100644
index 0000000..db66911
--- /dev/null
+++ b/awt/java/awt/font/OpenType.java
@@ -0,0 +1,418 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+/**
+ * The OpenType interface provides constants and methods for getting instance
+ * data for fonts of type OpenType and TrueType. For more information, see the
+ * <a
+ * href="http://partners.adobe.com/public/developer/opentype/index_spec.html">
+ * OpenType specification</a>.
+ * 
+ * @since Android 1.0
+ */
+public interface OpenType {
+
+    /**
+     * The Constant TAG_ACNT indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_ACNT = 1633906292;
+
+    /**
+     * The Constant TAG_AVAR indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_AVAR = 1635148146;
+
+    /**
+     * The Constant TAG_BASE indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_BASE = 1111577413;
+
+    /**
+     * The Constant TAG_BDAT indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_BDAT = 1650745716;
+
+    /**
+     * The Constant TAG_BLOC indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_BLOC = 1651273571;
+
+    /**
+     * The Constant TAG_BSLN indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_BSLN = 1651731566;
+
+    /**
+     * The Constant TAG_CFF indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_CFF = 1128678944;
+
+    /**
+     * The Constant TAG_CMAP indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_CMAP = 1668112752;
+
+    /**
+     * The Constant TAG_CVAR indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_CVAR = 1668702578;
+
+    /**
+     * The Constant TAG_CVT indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_CVT = 1668707360;
+
+    /**
+     * The Constant TAG_DSIG indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_DSIG = 1146308935;
+
+    /**
+     * The Constant TAG_EBDT indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_EBDT = 1161970772;
+
+    /**
+     * The Constant TAG_EBLC indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_EBLC = 1161972803;
+
+    /**
+     * The Constant TAG_EBSC indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_EBSC = 1161974595;
+
+    /**
+     * The Constant TAG_FDSC indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_FDSC = 1717859171;
+
+    /**
+     * The Constant TAG_FEAT indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_FEAT = 1717920116;
+
+    /**
+     * The Constant TAG_FMTX indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_FMTX = 1718449272;
+
+    /**
+     * The Constant TAG_FPGM indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_FPGM = 1718642541;
+
+    /**
+     * The Constant TAG_FVAR indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_FVAR = 1719034226;
+
+    /**
+     * The Constant TAG_GASP indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_GASP = 1734439792;
+
+    /**
+     * The Constant TAG_GDEF indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_GDEF = 1195656518;
+
+    /**
+     * The Constant TAG_GLYF indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_GLYF = 1735162214;
+
+    /**
+     * The Constant TAG_GPOS indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_GPOS = 1196445523;
+
+    /**
+     * The Constant TAG_GSUB indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_GSUB = 1196643650;
+
+    /**
+     * The Constant TAG_GVAR indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_GVAR = 1735811442;
+
+    /**
+     * The Constant TAG_HDMX indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_HDMX = 1751412088;
+
+    /**
+     * The Constant TAG_HEAD indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_HEAD = 1751474532;
+
+    /**
+     * The Constant TAG_HHEA indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_HHEA = 1751672161;
+
+    /**
+     * The Constant TAG_HMTX indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_HMTX = 1752003704;
+
+    /**
+     * The Constant TAG_JSTF indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_JSTF = 1246975046;
+
+    /**
+     * The Constant TAG_JUST indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_JUST = 1786082164;
+
+    /**
+     * The Constant TAG_KERN indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_KERN = 1801810542;
+
+    /**
+     * The Constant TAG_LCAR indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_LCAR = 1818452338;
+
+    /**
+     * The Constant TAG_LOCA indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_LOCA = 1819239265;
+
+    /**
+     * The Constant TAG_LTSH indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_LTSH = 1280594760;
+
+    /**
+     * The Constant TAG_MAXP indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_MAXP = 1835104368;
+
+    /**
+     * The Constant TAG_MMFX indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_MMFX = 1296909912;
+
+    /**
+     * The Constant TAG_MMSD indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_MMSD = 1296913220;
+
+    /**
+     * The Constant TAG_MORT indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_MORT = 1836020340;
+
+    /**
+     * The Constant TAG_NAME indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_NAME = 1851878757;
+
+    /**
+     * The Constant TAG_OPBD indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_OPBD = 1836020340;
+
+    /**
+     * The Constant TAG_OS2 indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_OS2 = 1330851634;
+
+    /**
+     * The Constant TAG_PCLT indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_PCLT = 1346587732;
+
+    /**
+     * The Constant TAG_POST indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_POST = 1886352244;
+
+    /**
+     * The Constant TAG_PREP indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_PREP = 1886545264;
+
+    /**
+     * The Constant TAG_PROP indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_PROP = 1886547824;
+
+    /**
+     * The Constant TAG_TRAK indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_TRAK = 1953653099;
+
+    /**
+     * The Constant TAG_TYP1 indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_TYP1 = 1954115633;
+
+    /**
+     * The Constant TAG_VDMX indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_VDMX = 1447316824;
+
+    /**
+     * The Constant TAG_VHEA indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_VHEA = 1986553185;
+
+    /**
+     * The Constant TAG_VMTX indicates corresponding table tag in the Open Type
+     * Specification.
+     */
+    public static final int TAG_VMTX = 1986884728;
+
+    /**
+     * Returns the OpenType font version.
+     * 
+     * @return the the OpenType font version.
+     */
+    public int getVersion();
+
+    /**
+     * Gets the table for a specified tag. Sfnt tables include cmap, name and
+     * head items.
+     * 
+     * @param sfntTag
+     *            the sfnt tag.
+     * @return a byte array contains the font data corresponding to the
+     *         specified tag.
+     */
+    public byte[] getFontTable(int sfntTag);
+
+    /**
+     * Gets the table for a specified tag. Sfnt tables include cmap, name and
+     * head items.
+     * 
+     * @param sfntTag
+     *            the sfnt tag.
+     * @param offset
+     *            the offset of the returned table.
+     * @param count
+     *            the number of returned table.
+     * @return the table corresponding to sfntTag and containing the bytes
+     *         starting at offset byte and including count bytes.
+     */
+    public byte[] getFontTable(int sfntTag, int offset, int count);
+
+    /**
+     * Gets the table for a specified tag. Sfnt tables include cmap, name and
+     * head items.
+     * 
+     * @param strSfntTag
+     *            the str sfnt tag as a String.
+     * @return a byte array contains the font data corresponding to the
+     *         specified tag.
+     */
+    public byte[] getFontTable(String strSfntTag);
+
+    /**
+     * Gets the table for a specified tag. Sfnt tables include cmap, name and
+     * head items.
+     * 
+     * @param strSfntTag
+     *            the sfnt tag as a String.
+     * @param offset
+     *            the offset of the returned table.
+     * @param count
+     *            the number of returned table.
+     * @return the table corresponding to sfntTag and containing the bytes
+     *         starting at offset byte and including count bytes.
+     */
+    public byte[] getFontTable(String strSfntTag, int offset, int count);
+
+    /**
+     * Gets the table size for a specified tag.
+     * 
+     * @param strSfntTag
+     *            the sfnt tag as a String.
+     * @return the table size for a specified tag.
+     */
+    public int getFontTableSize(String strSfntTag);
+
+    /**
+     * Gets the table size for a specified tag.
+     * 
+     * @param sfntTag
+     *            the sfnt tag.
+     * @return the table size for a specified tag.
+     */
+    public int getFontTableSize(int sfntTag);
+
+}
diff --git a/awt/java/awt/font/ShapeGraphicAttribute.java b/awt/java/awt/font/ShapeGraphicAttribute.java
new file mode 100644
index 0000000..182bffd
--- /dev/null
+++ b/awt/java/awt/font/ShapeGraphicAttribute.java
@@ -0,0 +1,206 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.awt.BasicStroke;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The ShapeGraphicAttribute class provides an opportunity to insert shapes to a
+ * text.
+ * 
+ * @since Android 1.0
+ */
+public final class ShapeGraphicAttribute extends GraphicAttribute {
+
+    // shape to render
+    /**
+     * The shape.
+     */
+    private Shape fShape;
+
+    // flag, if the shape should be stroked (true) or filled (false)
+    /**
+     * The stroke.
+     */
+    private boolean fStroke;
+
+    // bounds of the shape
+    /**
+     * The bounds.
+     */
+    private Rectangle2D fBounds;
+
+    // X coordinate of the origin point
+    /**
+     * The origin x.
+     */
+    private float fOriginX;
+
+    // Y coordinate of the origin point
+    /**
+     * The origin y.
+     */
+    private float fOriginY;
+
+    // width of the shape
+    /**
+     * The shape width.
+     */
+    private float fShapeWidth;
+
+    // height of the shape
+    /**
+     * The shape height.
+     */
+    private float fShapeHeight;
+
+    /**
+     * The Constant STROKE indicates whether the Shape is stroked or not.
+     */
+    public static final boolean STROKE = true;
+
+    /**
+     * The Constant FILL indicates whether the Shape is filled or not.
+     */
+    public static final boolean FILL = false;
+
+    /**
+     * Instantiates a new ShapeGraphicAttribute object for the specified Shape.
+     * 
+     * @param shape
+     *            the shape to be rendered by this ShapeGraphicAttribute.
+     * @param alignment
+     *            the alignment of this ShapeGraphicAttribute.
+     * @param stroke
+     *            true if the Shape is stroked, false if the Shape is filled.
+     */
+    public ShapeGraphicAttribute(Shape shape, int alignment, boolean stroke) {
+        super(alignment);
+
+        this.fShape = shape;
+        this.fStroke = stroke;
+
+        this.fBounds = fShape.getBounds2D();
+
+        this.fOriginX = (float)fBounds.getMinX();
+        this.fOriginY = (float)fBounds.getMinY();
+
+        this.fShapeWidth = (float)fBounds.getWidth();
+        this.fShapeHeight = (float)fBounds.getHeight();
+    }
+
+    /**
+     * Returns a hash code of this ShapeGraphicAttribute object.
+     * 
+     * @return a hash code of this ShapeGraphicAttribute object.
+     */
+    @Override
+    public int hashCode() {
+        HashCode hash = new HashCode();
+
+        hash.append(fShape.hashCode());
+        hash.append(getAlignment());
+        return hash.hashCode();
+    }
+
+    /**
+     * Compares this ShapeGraphicAttribute object to the specified
+     * ShapeGraphicAttribute object.
+     * 
+     * @param sga
+     *            the ShapeGraphicAttribute object to be compared.
+     * @return true, if this ShapeGraphicAttribute object is equal to the
+     *         specified ShapeGraphicAttribute object, false otherwise.
+     */
+    public boolean equals(ShapeGraphicAttribute sga) {
+        if (sga == null) {
+            return false;
+        }
+
+        if (sga == this) {
+            return true;
+        }
+
+        return (fStroke == sga.fStroke && getAlignment() == sga.getAlignment() && fShape
+                .equals(sga.fShape));
+
+    }
+
+    /**
+     * Compares this ShapeGraphicAttribute object to the specified Object.
+     * 
+     * @param obj
+     *            the Object to be compared.
+     * @return true, if this ShapeGraphicAttribute object is equal to the
+     *         specified Object, false otherwise.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        try {
+            return equals((ShapeGraphicAttribute)obj);
+        } catch (ClassCastException e) {
+            return false;
+        }
+    }
+
+    @Override
+    public void draw(Graphics2D g2, float x, float y) {
+        AffineTransform at = AffineTransform.getTranslateInstance(x, y);
+        if (fStroke == STROKE) {
+            Stroke oldStroke = g2.getStroke();
+            g2.setStroke(new BasicStroke());
+            g2.draw(at.createTransformedShape(fShape));
+            g2.setStroke(oldStroke);
+        } else {
+            g2.fill(at.createTransformedShape(fShape));
+        }
+
+    }
+
+    @Override
+    public float getAdvance() {
+        return Math.max(0, fShapeWidth + fOriginX);
+    }
+
+    @Override
+    public float getAscent() {
+        return Math.max(0, -fOriginY);
+    }
+
+    @Override
+    public Rectangle2D getBounds() {
+        return (Rectangle2D)fBounds.clone();
+    }
+
+    @Override
+    public float getDescent() {
+        return Math.max(0, fShapeHeight + fOriginY);
+    }
+
+}
diff --git a/awt/java/awt/font/TextHitInfo.java b/awt/java/awt/font/TextHitInfo.java
new file mode 100644
index 0000000..6460eba
--- /dev/null
+++ b/awt/java/awt/font/TextHitInfo.java
@@ -0,0 +1,215 @@
+/*
+ *  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.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The TextHitInfo class provides information about a caret position in a text
+ * model for insertion or deletion of a character in a text. The TextHitInfo
+ * defines two biases of the character: leading or trailing. Leading position
+ * means the left edge of the specified character (TextHitInfo.leading(2) method
+ * for "text" returns the left side of "x"). Trailing position means the right
+ * edge of the specified character (TextHitInfo.trailing(2) method for "text"
+ * returns the right side of "x").
+ * 
+ * @since Android 1.0
+ */
+public final class TextHitInfo {
+
+    /**
+     * The char idx.
+     */
+    private int charIdx; // Represents character index in the line
+
+    /**
+     * The is trailing.
+     */
+    private boolean isTrailing;
+
+    /**
+     * Instantiates a new text hit info.
+     * 
+     * @param idx
+     *            the idx.
+     * @param isTrailing
+     *            the is trailing.
+     */
+    private TextHitInfo(int idx, boolean isTrailing) {
+        charIdx = idx;
+        this.isTrailing = isTrailing;
+    }
+
+    /**
+     * Returns the textual string representation of this TextHitInfo instance.
+     * 
+     * @return the string representation.
+     */
+    @Override
+    public String toString() {
+        return new String("TextHitInfo[" + charIdx + ", " + //$NON-NLS-1$ //$NON-NLS-2$
+                (isTrailing ? "Trailing" : "Leading") + "]" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        );
+    }
+
+    /**
+     * Compares this TextHitInfo object with the specified object.
+     * 
+     * @param obj
+     *            the Object to be compared.
+     * @return true, if the specified object is a TextHitInfo object with the
+     *         same data values as this TextHitInfo, false otherwise.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof TextHitInfo) {
+            return equals((TextHitInfo)obj);
+        }
+        return false;
+    }
+
+    /**
+     * Compares this TextHitInfo object with the specified TextHitInfo object.
+     * 
+     * @param thi
+     *            the TextHitInfo object to be compared.
+     * @return true, if this TextHitInfo object has the same data values as the
+     *         specified TextHitInfo object, false otherwise.
+     */
+    public boolean equals(TextHitInfo thi) {
+        return thi != null && thi.charIdx == charIdx && thi.isTrailing == isTrailing;
+    }
+
+    /**
+     * Gets a TextHitInfo object with its character index at the specified
+     * offset from the character index of this TextHitInfo.
+     * 
+     * @param offset
+     *            the offset.
+     * @return the TextHitInfo.
+     */
+    public TextHitInfo getOffsetHit(int offset) {
+        return new TextHitInfo(charIdx + offset, isTrailing);
+    }
+
+    /**
+     * Gets a TextHitInfo associated with the other side of the insertion point.
+     * 
+     * @return the other hit.
+     */
+    public TextHitInfo getOtherHit() {
+        return isTrailing ? new TextHitInfo(charIdx + 1, false)
+                : new TextHitInfo(charIdx - 1, true);
+    }
+
+    /**
+     * Returns true if the leading edge of the character is hit, false if the
+     * trailing edge of the character is hit.
+     * 
+     * @return true if the leading edge of the character is hit, false if the
+     *         trailing edge of the character is hit.
+     */
+    public boolean isLeadingEdge() {
+        return !isTrailing;
+    }
+
+    /**
+     * Returns the hash code value of this TextHitInfo instance.
+     * 
+     * @return the hash code value.
+     */
+    @Override
+    public int hashCode() {
+        return HashCode.combine(charIdx, isTrailing);
+    }
+
+    /**
+     * Gets the insertion index.
+     * 
+     * @return the insertion index: character index if the leading edge is hit,
+     *         or character index + 1 if the trailing edge is hit.
+     */
+    public int getInsertionIndex() {
+        return isTrailing ? charIdx + 1 : charIdx;
+    }
+
+    /**
+     * Gets the index of the character hit.
+     * 
+     * @return the character hit's index.
+     */
+    public int getCharIndex() {
+        return charIdx;
+    }
+
+    /**
+     * Returns a TextHitInfo associated with the trailing edge of the character
+     * at the specified char index.
+     * 
+     * @param charIndex
+     *            the char index.
+     * @return the TextHitInfo associated with the trailing edge of the
+     *         character at the specified char index.
+     */
+    public static TextHitInfo trailing(int charIndex) {
+        return new TextHitInfo(charIndex, true);
+    }
+
+    /**
+     * Returns a TextHitInfo object associated with the leading edge of the
+     * character at the specified char index.
+     * 
+     * @param charIndex
+     *            the char index.
+     * @return the TextHitInfo object associated with the leading edge of the
+     *         character at the specified char index.
+     */
+    public static TextHitInfo leading(int charIndex) {
+        return new TextHitInfo(charIndex, false);
+    }
+
+    /**
+     * Returns a (trailing) TextHitInfo object associated with the character
+     * before the specified offset.
+     * 
+     * @param offset
+     *            the offset.
+     * @return the TextHitInfo object associated with the character before the
+     *         specified offset.
+     */
+    public static TextHitInfo beforeOffset(int offset) {
+        return new TextHitInfo(offset - 1, true);
+    }
+
+    /**
+     * Returns a (leading) TextHitInfo object associated with the character
+     * after the specified offset.
+     * 
+     * @param offset
+     *            the offset.
+     * @return the TextHitInfo object associated with the character after the
+     *         specified offset.
+     */
+    public static TextHitInfo afterOffset(int offset) {
+        return new TextHitInfo(offset, false);
+    }
+}
diff --git a/awt/java/awt/font/TextLayout.java b/awt/java/awt/font/TextLayout.java
new file mode 100644
index 0000000..cc6f0ba
--- /dev/null
+++ b/awt/java/awt/font/TextLayout.java
@@ -0,0 +1,927 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.GeneralPath;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java.util.Map;
+
+import org.apache.harmony.awt.gl.font.BasicMetrics;
+import org.apache.harmony.awt.gl.font.CaretManager;
+import org.apache.harmony.awt.gl.font.TextMetricsCalculator;
+import org.apache.harmony.awt.gl.font.TextRunBreaker;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The TextLayout class defines the graphical representation of character data.
+ * This class provides method for obtaining information about cursor positioning
+ * and movement, split cursors for text with different directions, logical and
+ * visual highlighting, multiple baselines, hits, justification, ascent,
+ * descent, and advance, and rendering. A TextLayout object can be rendered
+ * using Graphics context.
+ * 
+ * @since Android 1.0
+ */
+public final class TextLayout implements Cloneable {
+
+    /**
+     * The CaretPolicy class provides a policy for obtaining the caret location.
+     * The single getStrongCaret method specifies the policy.
+     */
+    public static class CaretPolicy {
+
+        /**
+         * Instantiates a new CaretPolicy.
+         */
+        public CaretPolicy() {
+            // Nothing to do
+        }
+
+        /**
+         * Returns whichever of the two specified TextHitInfo objects has the
+         * stronger caret (higher character level) in the specified TextLayout.
+         * 
+         * @param hit1
+         *            the first TextHitInfo of the specified TextLayout.
+         * @param hit2
+         *            the second TextHitInfo of the specified TextLayout.
+         * @param layout
+         *            the TextLayout.
+         * @return the TextHitInfo with the stronger caret.
+         */
+        public TextHitInfo getStrongCaret(TextHitInfo hit1, TextHitInfo hit2, TextLayout layout) {
+            // Stronger hit is the one with greater level.
+            // If the level is same, leading edge is stronger.
+
+            int level1 = layout.getCharacterLevel(hit1.getCharIndex());
+            int level2 = layout.getCharacterLevel(hit2.getCharIndex());
+
+            if (level1 == level2) {
+                return (hit2.isLeadingEdge() && (!hit1.isLeadingEdge())) ? hit2 : hit1;
+            }
+            return level1 > level2 ? hit1 : hit2;
+        }
+
+    }
+
+    /**
+     * The Constant DEFAULT_CARET_POLICY indicates the default caret policy.
+     */
+    public static final TextLayout.CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy();
+
+    /**
+     * The breaker.
+     */
+    private TextRunBreaker breaker;
+
+    /**
+     * The metrics valid.
+     */
+    private boolean metricsValid = false;
+
+    /**
+     * The tmc.
+     */
+    private TextMetricsCalculator tmc;
+
+    /**
+     * The metrics.
+     */
+    private BasicMetrics metrics;
+
+    /**
+     * The caret manager.
+     */
+    private CaretManager caretManager;
+
+    /**
+     * The justification width.
+     */
+    float justificationWidth = -1;
+
+    /**
+     * Instantiates a new TextLayout object from the specified string and Font.
+     * 
+     * @param string
+     *            the string to be displayed.
+     * @param font
+     *            the font of the text.
+     * @param frc
+     *            the FontRenderContext object for obtaining information about a
+     *            graphics device.
+     */
+    public TextLayout(String string, Font font, FontRenderContext frc) {
+        if (string == null) {
+            // awt.01='{0}' parameter is null
+            throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        if (font == null) {
+            // awt.01='{0}' parameter is null
+            throw new IllegalArgumentException(Messages.getString("awt.01", "font")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        if (string.length() == 0) {
+            // awt.02='{0}' parameter has zero length
+            throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        AttributedString as = new AttributedString(string);
+        as.addAttribute(TextAttribute.FONT, font);
+        this.breaker = new TextRunBreaker(as.getIterator(), frc);
+        caretManager = new CaretManager(breaker);
+    }
+
+    /**
+     * Instantiates a new TextLayout from the specified text and a map of
+     * attributes.
+     * 
+     * @param string
+     *            the string to be displayed.
+     * @param attributes
+     *            the attributes to be used for obtaining the text style.
+     * @param frc
+     *            the FontRenderContext object for obtaining information about a
+     *            graphics device.
+     */
+    public TextLayout(String string,
+            Map<? extends java.text.AttributedCharacterIterator.Attribute, ?> attributes,
+            FontRenderContext frc) {
+        if (string == null) {
+            // awt.01='{0}' parameter is null
+            throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        if (attributes == null) {
+            // awt.01='{0}' parameter is null
+            throw new IllegalArgumentException(Messages.getString("awt.01", "attributes")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        if (string.length() == 0) {
+            // awt.02='{0}' parameter has zero length
+            throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        AttributedString as = new AttributedString(string);
+        as.addAttributes(attributes, 0, string.length());
+        this.breaker = new TextRunBreaker(as.getIterator(), frc);
+        caretManager = new CaretManager(breaker);
+    }
+
+    /**
+     * Instantiates a new TextLayout from the AttributedCharacterIterator.
+     * 
+     * @param text
+     *            the AttributedCharacterIterator.
+     * @param frc
+     *            the FontRenderContext object for obtaining information about a
+     *            graphics device.
+     */
+    public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) {
+        if (text == null) {
+            // awt.03='{0}' iterator parameter is null
+            throw new IllegalArgumentException(Messages.getString("awt.03", "text")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        if (text.getBeginIndex() == text.getEndIndex()) {
+            // awt.04='{0}' iterator parameter has zero length
+            throw new IllegalArgumentException(Messages.getString("awt.04", "text")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        this.breaker = new TextRunBreaker(text, frc);
+        caretManager = new CaretManager(breaker);
+    }
+
+    /**
+     * Instantiates a new text layout.
+     * 
+     * @param breaker
+     *            the breaker.
+     */
+    TextLayout(TextRunBreaker breaker) {
+        this.breaker = breaker;
+        caretManager = new CaretManager(this.breaker);
+    }
+
+    /**
+     * Returns a hash code of this TextLayout object.
+     * 
+     * @return a hash code of this TextLayout object.
+     */
+    @Override
+    public int hashCode() {
+        return breaker.hashCode();
+    }
+
+    /**
+     * Returns a copy of this object.
+     * 
+     * @return a copy of this object.
+     */
+    @Override
+    protected Object clone() {
+        TextLayout res = new TextLayout((TextRunBreaker)breaker.clone());
+
+        if (justificationWidth >= 0) {
+            res.handleJustify(justificationWidth);
+        }
+
+        return res;
+    }
+
+    /**
+     * Compares this TextLayout object to the specified TextLayout object.
+     * 
+     * @param layout
+     *            the TextLayout object to be compared.
+     * @return true, if this TextLayout object is equal to the specified
+     *         TextLayout object, false otherwise.
+     */
+    public boolean equals(TextLayout layout) {
+        if (layout == null) {
+            return false;
+        }
+        return this.breaker.equals(layout.breaker);
+    }
+
+    /**
+     * Compares this TextLayout object to the specified Object.
+     * 
+     * @param obj
+     *            the Object to be compared.
+     * @return true, if this TextLayout object is equal to the specified Object,
+     *         false otherwise.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof TextLayout ? equals((TextLayout)obj) : false;
+    }
+
+    /**
+     * Gets the string representation for this TextLayout.
+     * 
+     * @return the string representation for this TextLayout.
+     */
+    @Override
+    public String toString() { // what for?
+        return super.toString();
+    }
+
+    /**
+     * Draws this TextLayout at the specified location with the specified
+     * Graphics2D context.
+     * 
+     * @param g2d
+     *            the Graphics2D object which renders this TextLayout.
+     * @param x
+     *            the X coordinate of the TextLayout origin.
+     * @param y
+     *            the Y coordinate of the TextLayout origin.
+     */
+    public void draw(Graphics2D g2d, float x, float y) {
+        updateMetrics();
+        breaker.drawSegments(g2d, x, y);
+    }
+
+    /**
+     * Update metrics.
+     */
+    private void updateMetrics() {
+        if (!metricsValid) {
+            breaker.createAllSegments();
+            tmc = new TextMetricsCalculator(breaker);
+            metrics = tmc.createMetrics();
+            metricsValid = true;
+        }
+    }
+
+    /**
+     * Gets the advance of this TextLayout object.
+     * 
+     * @return the advance of this TextLayout object.
+     */
+    public float getAdvance() {
+        updateMetrics();
+        return metrics.getAdvance();
+    }
+
+    /**
+     * Gets the ascent of this TextLayout object.
+     * 
+     * @return the ascent of this TextLayout object.
+     */
+    public float getAscent() {
+        updateMetrics();
+        return metrics.getAscent();
+    }
+
+    /**
+     * Gets the baseline of this TextLayout object.
+     * 
+     * @return the baseline of this TextLayout object.
+     */
+    public byte getBaseline() {
+        updateMetrics();
+        return (byte)metrics.getBaseLineIndex();
+    }
+
+    /**
+     * Gets the float array of offsets for the baselines which are used in this
+     * TextLayout.
+     * 
+     * @return the float array of offsets for the baselines which are used in
+     *         this TextLayout.
+     */
+    public float[] getBaselineOffsets() {
+        updateMetrics();
+        return tmc.getBaselineOffsets();
+    }
+
+    /**
+     * Gets the black box bounds of the characters in the specified area. The
+     * black box bounds is an Shape which contains all bounding boxes of all the
+     * glyphs of the characters between firstEndpoint and secondEndpoint
+     * parameters values.
+     * 
+     * @param firstEndpoint
+     *            the first point of the area.
+     * @param secondEndpoint
+     *            the second point of the area.
+     * @return the Shape which contains black box bounds.
+     */
+    public Shape getBlackBoxBounds(int firstEndpoint, int secondEndpoint) {
+        updateMetrics();
+        if (firstEndpoint < secondEndpoint) {
+            return breaker.getBlackBoxBounds(firstEndpoint, secondEndpoint);
+        }
+        return breaker.getBlackBoxBounds(secondEndpoint, firstEndpoint);
+    }
+
+    /**
+     * Gets the bounds of this TextLayout.
+     * 
+     * @return the bounds of this TextLayout.
+     */
+    public Rectangle2D getBounds() {
+        updateMetrics();
+        return breaker.getVisualBounds();
+    }
+
+    /**
+     * Gets information about the caret of the specified TextHitInfo.
+     * 
+     * @param hitInfo
+     *            the TextHitInfo.
+     * @return the information about the caret of the specified TextHitInfo.
+     */
+    public float[] getCaretInfo(TextHitInfo hitInfo) {
+        updateMetrics();
+        return caretManager.getCaretInfo(hitInfo);
+    }
+
+    /**
+     * Gets information about the caret of the specified TextHitInfo of a
+     * character in this TextLayout.
+     * 
+     * @param hitInfo
+     *            the TextHitInfo of a character in this TextLayout.
+     * @param bounds
+     *            the bounds to which the caret info is constructed.
+     * @return the caret of the specified TextHitInfo.
+     */
+    public float[] getCaretInfo(TextHitInfo hitInfo, Rectangle2D bounds) {
+        updateMetrics();
+        return caretManager.getCaretInfo(hitInfo);
+    }
+
+    /**
+     * Gets a Shape which represents the caret of the specified TextHitInfo in
+     * the bounds of this TextLayout.
+     * 
+     * @param hitInfo
+     *            the TextHitInfo.
+     * @param bounds
+     *            the bounds to which the caret info is constructed.
+     * @return the Shape which represents the caret.
+     */
+    public Shape getCaretShape(TextHitInfo hitInfo, Rectangle2D bounds) {
+        updateMetrics();
+        return caretManager.getCaretShape(hitInfo, this);
+    }
+
+    /**
+     * Gets a Shape which represents the caret of the specified TextHitInfo in
+     * the bounds of this TextLayout.
+     * 
+     * @param hitInfo
+     *            the TextHitInfo.
+     * @return the Shape which represents the caret.
+     */
+    public Shape getCaretShape(TextHitInfo hitInfo) {
+        updateMetrics();
+        return caretManager.getCaretShape(hitInfo, this);
+    }
+
+    /**
+     * Gets two Shapes for the strong and weak carets with default caret policy
+     * and null bounds: the first element is the strong caret, the second is the
+     * weak caret or null.
+     * 
+     * @param offset
+     *            an offset in the TextLayout.
+     * @return an array of two Shapes corresponded to the strong and weak
+     *         carets.
+     */
+    public Shape[] getCaretShapes(int offset) {
+        return getCaretShapes(offset, null, TextLayout.DEFAULT_CARET_POLICY);
+    }
+
+    /**
+     * Gets two Shapes for the strong and weak carets with the default caret
+     * policy: the first element is the strong caret, the second is the weak
+     * caret or null.
+     * 
+     * @param offset
+     *            an offset in the TextLayout.
+     * @param bounds
+     *            the bounds to which to extend the carets.
+     * @return an array of two Shapes corresponded to the strong and weak
+     *         carets.
+     */
+    public Shape[] getCaretShapes(int offset, Rectangle2D bounds) {
+        return getCaretShapes(offset, bounds, TextLayout.DEFAULT_CARET_POLICY);
+    }
+
+    /**
+     * Gets two Shapes for the strong and weak carets: the first element is the
+     * strong caret, the second is the weak caret or null.
+     * 
+     * @param offset
+     *            an offset in the TextLayout.
+     * @param bounds
+     *            the bounds to which to extend the carets.
+     * @param policy
+     *            the specified CaretPolicy.
+     * @return an array of two Shapes corresponded to the strong and weak
+     *         carets.
+     */
+    public Shape[] getCaretShapes(int offset, Rectangle2D bounds, TextLayout.CaretPolicy policy) {
+        if (offset < 0 || offset > breaker.getCharCount()) {
+            // awt.195=Offset is out of bounds
+            throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$
+        }
+
+        updateMetrics();
+        return caretManager.getCaretShapes(offset, bounds, policy, this);
+    }
+
+    /**
+     * Gets the number of characters in this TextLayout.
+     * 
+     * @return the number of characters in this TextLayout.
+     */
+    public int getCharacterCount() {
+        return breaker.getCharCount();
+    }
+
+    /**
+     * Gets the level of the character with the specified index.
+     * 
+     * @param index
+     *            the specified index of the character.
+     * @return the level of the character.
+     */
+    public byte getCharacterLevel(int index) {
+        if (index == -1 || index == getCharacterCount()) {
+            return (byte)breaker.getBaseLevel();
+        }
+        return breaker.getLevel(index);
+    }
+
+    /**
+     * Gets the descent of this TextLayout.
+     * 
+     * @return the descent of this TextLayout.
+     */
+    public float getDescent() {
+        updateMetrics();
+        return metrics.getDescent();
+    }
+
+    /**
+     * Gets the TextLayout wich is justified with the specified width related to
+     * this TextLayout.
+     * 
+     * @param justificationWidth
+     *            the width which is used for justification.
+     * @return a TextLayout justified to the specified width.
+     * @throws Error
+     *             the error occures if this TextLayout has been already
+     *             justified.
+     */
+    public TextLayout getJustifiedLayout(float justificationWidth) throws Error {
+        float justification = breaker.getJustification();
+
+        if (justification < 0) {
+            // awt.196=Justification impossible, layout already justified
+            throw new Error(Messages.getString("awt.196")); //$NON-NLS-1$
+        } else if (justification == 0) {
+            return this;
+        }
+
+        TextLayout justifiedLayout = new TextLayout((TextRunBreaker)breaker.clone());
+        justifiedLayout.handleJustify(justificationWidth);
+        return justifiedLayout;
+    }
+
+    /**
+     * Gets the leading of this TextLayout.
+     * 
+     * @return the leading of this TextLayout.
+     */
+    public float getLeading() {
+        updateMetrics();
+        return metrics.getLeading();
+    }
+
+    /**
+     * Gets a Shape representing the logical selection betweeen the specified
+     * endpoints and extended to the natural bounds of this TextLayout.
+     * 
+     * @param firstEndpoint
+     *            the first selected endpoint within the area of characters
+     * @param secondEndpoint
+     *            the second selected endpoint within the area of characters
+     * @return a Shape represented the logical selection betweeen the specified
+     *         endpoints.
+     */
+    public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint) {
+        updateMetrics();
+        return getLogicalHighlightShape(firstEndpoint, secondEndpoint, breaker.getLogicalBounds());
+    }
+
+    /**
+     * Gets a Shape representing the logical selection betweeen the specified
+     * endpoints and extended to the specified bounds of this TextLayout.
+     * 
+     * @param firstEndpoint
+     *            the first selected endpoint within the area of characters
+     * @param secondEndpoint
+     *            the second selected endpoint within the area of characters
+     * @param bounds
+     *            the specified bounds of this TextLayout.
+     * @return a Shape represented the logical selection betweeen the specified
+     *         endpoints.
+     */
+    public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint, Rectangle2D bounds) {
+        updateMetrics();
+
+        if (firstEndpoint > secondEndpoint) {
+            if (secondEndpoint < 0 || firstEndpoint > breaker.getCharCount()) {
+                // awt.197=Endpoints are out of range
+                throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$
+            }
+            return caretManager.getLogicalHighlightShape(secondEndpoint, firstEndpoint, bounds,
+                    this);
+        }
+        if (firstEndpoint < 0 || secondEndpoint > breaker.getCharCount()) {
+            // awt.197=Endpoints are out of range
+            throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$
+        }
+        return caretManager.getLogicalHighlightShape(firstEndpoint, secondEndpoint, bounds, this);
+    }
+
+    /**
+     * Gets the logical ranges of text which corresponds to a visual selection.
+     * 
+     * @param hit1
+     *            the first endpoint of the visual range.
+     * @param hit2
+     *            the second endpoint of the visual range.
+     * @return the logical ranges of text which corresponds to a visual
+     *         selection.
+     */
+    public int[] getLogicalRangesForVisualSelection(TextHitInfo hit1, TextHitInfo hit2) {
+        return caretManager.getLogicalRangesForVisualSelection(hit1, hit2);
+    }
+
+    /**
+     * Gets the TextHitInfo for the next caret to the left (or up at the end of
+     * the line) of the specified offset.
+     * 
+     * @param offset
+     *            the offset in this TextLayout.
+     * @return the TextHitInfo for the next caret to the left (or up at the end
+     *         of the line) of the specified hit, or null if there is no hit.
+     */
+    public TextHitInfo getNextLeftHit(int offset) {
+        return getNextLeftHit(offset, DEFAULT_CARET_POLICY);
+    }
+
+    /**
+     * Gets the TextHitInfo for the next caret to the left (or up at the end of
+     * the line) of the specified hit.
+     * 
+     * @param hitInfo
+     *            the initial hit.
+     * @return the TextHitInfo for the next caret to the left (or up at the end
+     *         of the line) of the specified hit, or null if there is no hit.
+     */
+    public TextHitInfo getNextLeftHit(TextHitInfo hitInfo) {
+        breaker.createAllSegments();
+        return caretManager.getNextLeftHit(hitInfo);
+    }
+
+    /**
+     * Gets the TextHitInfo for the next caret to the left (or up at the end of
+     * the line) of the specified offset, given the specified caret policy.
+     * 
+     * @param offset
+     *            the offset in this TextLayout.
+     * @param policy
+     *            the policy to be used for obtaining the strong caret.
+     * @return the TextHitInfo for the next caret to the left of the specified
+     *         offset, or null if there is no hit.
+     */
+    public TextHitInfo getNextLeftHit(int offset, TextLayout.CaretPolicy policy) {
+        if (offset < 0 || offset > breaker.getCharCount()) {
+            // awt.195=Offset is out of bounds
+            throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$
+        }
+
+        TextHitInfo hit = TextHitInfo.afterOffset(offset);
+        TextHitInfo strongHit = policy.getStrongCaret(hit, hit.getOtherHit(), this);
+        TextHitInfo nextLeftHit = getNextLeftHit(strongHit);
+
+        if (nextLeftHit != null) {
+            return policy.getStrongCaret(getVisualOtherHit(nextLeftHit), nextLeftHit, this);
+        }
+        return null;
+    }
+
+    /**
+     * Gets the TextHitInfo for the next caret to the right (or down at the end
+     * of the line) of the specified hit.
+     * 
+     * @param hitInfo
+     *            the initial hit.
+     * @return the TextHitInfo for the next caret to the right (or down at the
+     *         end of the line) of the specified hit, or null if there is no
+     *         hit.
+     */
+    public TextHitInfo getNextRightHit(TextHitInfo hitInfo) {
+        breaker.createAllSegments();
+        return caretManager.getNextRightHit(hitInfo);
+    }
+
+    /**
+     * Gets the TextHitInfo for the next caret to the right (or down at the end
+     * of the line) of the specified offset.
+     * 
+     * @param offset
+     *            the offset in this TextLayout.
+     * @return the TextHitInfo for the next caret to the right of the specified
+     *         offset, or null if there is no hit.
+     */
+    public TextHitInfo getNextRightHit(int offset) {
+        return getNextRightHit(offset, DEFAULT_CARET_POLICY);
+    }
+
+    /**
+     * Gets the TextHitInfo for the next caret to the right (or down at the end
+     * of the line) of the specified offset, given the specified caret policy.
+     * 
+     * @param offset
+     *            the offset in this TextLayout.
+     * @param policy
+     *            the policy to be used for obtaining the strong caret.
+     * @return the TextHitInfo for the next caret to the right of the specified
+     *         offset, or null if there is no hit.
+     */
+    public TextHitInfo getNextRightHit(int offset, TextLayout.CaretPolicy policy) {
+        if (offset < 0 || offset > breaker.getCharCount()) {
+            // awt.195=Offset is out of bounds
+            throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$
+        }
+
+        TextHitInfo hit = TextHitInfo.afterOffset(offset);
+        TextHitInfo strongHit = policy.getStrongCaret(hit, hit.getOtherHit(), this);
+        TextHitInfo nextRightHit = getNextRightHit(strongHit);
+
+        if (nextRightHit != null) {
+            return policy.getStrongCaret(getVisualOtherHit(nextRightHit), nextRightHit, this);
+        }
+        return null;
+    }
+
+    /**
+     * Gets the outline of this TextLayout as a Shape.
+     * 
+     * @param xform
+     *            the AffineTransform to be used to transform the outline before
+     *            returning it, or null if no transformation is desired.
+     * @return the outline of this TextLayout as a Shape.
+     */
+    public Shape getOutline(AffineTransform xform) {
+        breaker.createAllSegments();
+
+        GeneralPath outline = breaker.getOutline();
+
+        if (outline != null && xform != null) {
+            outline.transform(xform);
+        }
+
+        return outline;
+    }
+
+    /**
+     * Gets the visible advance of this TextLayout which is defined as diffence
+     * between leading (advance) and trailing whitespace.
+     * 
+     * @return the visible advance of this TextLayout.
+     */
+    public float getVisibleAdvance() {
+        updateMetrics();
+
+        // Trailing whitespace _SHOULD_ be reordered (Unicode spec) to
+        // base direction, so it is also trailing
+        // in logical representation. We use this fact.
+        int lastNonWhitespace = breaker.getLastNonWhitespace();
+
+        if (lastNonWhitespace < 0) {
+            return 0;
+        } else if (lastNonWhitespace == getCharacterCount() - 1) {
+            return getAdvance();
+        } else if (justificationWidth >= 0) { // Layout is justified
+            return justificationWidth;
+        } else {
+            breaker.pushSegments(breaker.getACI().getBeginIndex(), lastNonWhitespace
+                    + breaker.getACI().getBeginIndex() + 1);
+
+            breaker.createAllSegments();
+
+            float visAdvance = tmc.createMetrics().getAdvance();
+
+            breaker.popSegments();
+            return visAdvance;
+        }
+    }
+
+    /**
+     * Gets a Shape which corresponds to the highlighted (selected) area based
+     * on two hit locations within the text and extends to the bounds.
+     * 
+     * @param hit1
+     *            the first text hit location.
+     * @param hit2
+     *            the second text hit location.
+     * @param bounds
+     *            the rectangle that the highlighted area should be extended or
+     *            restricted to.
+     * @return a Shape which corresponds to the highlighted (selected) area.
+     */
+    public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2, Rectangle2D bounds) {
+        return caretManager.getVisualHighlightShape(hit1, hit2, bounds, this);
+    }
+
+    /**
+     * Gets a Shape which corresponds to the highlighted (selected) area based
+     * on two hit locations within the text.
+     * 
+     * @param hit1
+     *            the first text hit location.
+     * @param hit2
+     *            the second text hit location.
+     * @return a Shape which corresponds to the highlighted (selected) area.
+     */
+    public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2) {
+        breaker.createAllSegments();
+        return caretManager.getVisualHighlightShape(hit1, hit2, breaker.getLogicalBounds(), this);
+    }
+
+    /**
+     * Gets the TextHitInfo for a hit on the opposite side of the specified
+     * hit's caret.
+     * 
+     * @param hitInfo
+     *            the specified TextHitInfo.
+     * @return the TextHitInfo for a hit on the opposite side of the specified
+     *         hit's caret.
+     */
+    public TextHitInfo getVisualOtherHit(TextHitInfo hitInfo) {
+        return caretManager.getVisualOtherHit(hitInfo);
+    }
+
+    /**
+     * Justifies the text; this method should be overridden by subclasses.
+     * 
+     * @param justificationWidth
+     *            the width for justification.
+     */
+    protected void handleJustify(float justificationWidth) {
+        float justification = breaker.getJustification();
+
+        if (justification < 0) {
+            // awt.196=Justification impossible, layout already justified
+            throw new IllegalStateException(Messages.getString("awt.196")); //$NON-NLS-1$
+        } else if (justification == 0) {
+            return;
+        }
+
+        float gap = (justificationWidth - getVisibleAdvance()) * justification;
+        breaker.justify(gap);
+        this.justificationWidth = justificationWidth;
+
+        // Correct metrics
+        tmc = new TextMetricsCalculator(breaker);
+        tmc.correctAdvance(metrics);
+    }
+
+    /**
+     * Returns a TextHitInfo object that gives information on which division
+     * point (between two characters) is corresponds to a hit (such as a mouse
+     * click) at the specified coordinates.
+     * 
+     * @param x
+     *            the X coordinate in this TextLayout.
+     * @param y
+     *            the Y coordinate in this TextLayout. TextHitInfo object
+     *            corresponding to the given coordinates within the text.
+     * @return the information about the character at the specified position.
+     */
+    public TextHitInfo hitTestChar(float x, float y) {
+        return hitTestChar(x, y, getBounds());
+    }
+
+    /**
+     * Returns a TextHitInfo object that gives information on which division
+     * point (between two characters) is corresponds to a hit (such as a mouse
+     * click) at the specified coordinates within the specified text rectangle.
+     * 
+     * @param x
+     *            the X coordinate in this TextLayout.
+     * @param y
+     *            the Y coordinate in this TextLayout.
+     * @param bounds
+     *            the bounds of the text area. TextHitInfo object corresponding
+     *            to the given coordinates within the text.
+     * @return the information about the character at the specified position.
+     */
+    public TextHitInfo hitTestChar(float x, float y, Rectangle2D bounds) {
+        if (x > bounds.getMaxX()) {
+            return breaker.isLTR() ? TextHitInfo.trailing(breaker.getCharCount() - 1) : TextHitInfo
+                    .leading(0);
+        }
+
+        if (x < bounds.getMinX()) {
+            return breaker.isLTR() ? TextHitInfo.leading(0) : TextHitInfo.trailing(breaker
+                    .getCharCount() - 1);
+        }
+
+        return breaker.hitTest(x, y);
+    }
+
+    /**
+     * Returns true if this TextLayout has a "left to right" direction.
+     * 
+     * @return true if this TextLayout has a "left to right" direction, false if
+     *         this TextLayout has a "right to left" direction.
+     */
+    public boolean isLeftToRight() {
+        return breaker.isLTR();
+    }
+
+    /**
+     * Returns true if this TextLayout is vertical, false otherwise.
+     * 
+     * @return true if this TextLayout is vertical, false if horizontal.
+     */
+    public boolean isVertical() {
+        return false;
+    }
+}
diff --git a/awt/java/awt/font/TextMeasurer.java b/awt/java/awt/font/TextMeasurer.java
new file mode 100644
index 0000000..9741f59
--- /dev/null
+++ b/awt/java/awt/font/TextMeasurer.java
@@ -0,0 +1,182 @@
+/*
+ *  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.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.text.AttributedCharacterIterator;
+
+import org.apache.harmony.awt.gl.font.TextMetricsCalculator;
+import org.apache.harmony.awt.gl.font.TextRunBreaker;
+
+/**
+ * The TextMeasurer class provides utilities for line break operations.
+ * 
+ * @since Android 1.0
+ */
+public final class TextMeasurer implements Cloneable {
+
+    /**
+     * The aci.
+     */
+    AttributedCharacterIterator aci;
+
+    /**
+     * The frc.
+     */
+    FontRenderContext frc;
+
+    /**
+     * The breaker.
+     */
+    TextRunBreaker breaker = null;
+
+    /**
+     * The tmc.
+     */
+    TextMetricsCalculator tmc = null;
+
+    /**
+     * Instantiates a new text measurer from the specified text.
+     * 
+     * @param text
+     *            the source text.
+     * @param frc
+     *            the FontRenderContext.
+     */
+    public TextMeasurer(AttributedCharacterIterator text, FontRenderContext frc) {
+        this.aci = text;
+        this.frc = frc;
+        breaker = new TextRunBreaker(aci, this.frc);
+        tmc = new TextMetricsCalculator(breaker);
+    }
+
+    /**
+     * Replaces the current text with the new text, inserting a break character
+     * at the specified insert position.
+     * 
+     * @param newParagraph
+     *            the new paragraph text.
+     * @param insertPos
+     *            the position in the text where the character is inserted.
+     */
+    public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) {
+        AttributedCharacterIterator oldAci = aci;
+        aci = newParagraph;
+        if ((oldAci.getEndIndex() - oldAci.getBeginIndex())
+                - (aci.getEndIndex() - aci.getBeginIndex()) != -1) {
+            breaker = new TextRunBreaker(aci, this.frc);
+            tmc = new TextMetricsCalculator(breaker);
+        } else {
+            breaker.insertChar(newParagraph, insertPos);
+        }
+    }
+
+    /**
+     * Replaces the current text with the new text and deletes a character at
+     * the specified position.
+     * 
+     * @param newParagraph
+     *            the paragraph text after deletion.
+     * @param deletePos
+     *            the position in the text where the character is removed.
+     */
+    public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) {
+        AttributedCharacterIterator oldAci = aci;
+        aci = newParagraph;
+        if ((oldAci.getEndIndex() - oldAci.getBeginIndex())
+                - (aci.getEndIndex() - aci.getBeginIndex()) != 1) {
+            breaker = new TextRunBreaker(aci, this.frc);
+            tmc = new TextMetricsCalculator(breaker);
+        } else {
+            breaker.deleteChar(newParagraph, deletePos);
+        }
+    }
+
+    /**
+     * Returns a copy of this object.
+     * 
+     * @return a copy of this object.
+     */
+    @Override
+    protected Object clone() {
+        return new TextMeasurer((AttributedCharacterIterator)aci.clone(), frc);
+    }
+
+    /**
+     * Returns a TextLayout of the specified character range.
+     * 
+     * @param start
+     *            the index of the first character.
+     * @param limit
+     *            the index after the last character.
+     * @return a TextLayout for the characters beginning at "start" up to "end".
+     */
+    public TextLayout getLayout(int start, int limit) {
+        breaker.pushSegments(start - aci.getBeginIndex(), limit - aci.getBeginIndex());
+
+        breaker.createAllSegments();
+        TextLayout layout = new TextLayout((TextRunBreaker)breaker.clone());
+
+        breaker.popSegments();
+        return layout;
+    }
+
+    /**
+     * Returns the graphical width of a line beginning at "start" parameter and
+     * including characters up to "end" parameter. "start" and "end" are
+     * absolute indices, not relative to the "start" of the paragraph.
+     * 
+     * @param start
+     *            the character index at which to start measuring.
+     * @param end
+     *            the character index at which to stop measuring.
+     * @return the graphical width of a line beginning at "start" and including
+     *         characters up to "end".
+     */
+    public float getAdvanceBetween(int start, int end) {
+        breaker.pushSegments(start - aci.getBeginIndex(), end - aci.getBeginIndex());
+
+        breaker.createAllSegments();
+        float retval = tmc.createMetrics().getAdvance();
+
+        breaker.popSegments();
+        return retval;
+    }
+
+    /**
+     * Returns the index of the first character which is not fit on a line
+     * beginning at start and possible measuring up to maxAdvance in graphical
+     * width.
+     * 
+     * @param start
+     *            he character index at which to start measuring.
+     * @param maxAdvance
+     *            the graphical width in which the line must fit.
+     * @return the index after the last character that is fit on a line
+     *         beginning at start, which is not longer than maxAdvance in
+     *         graphical width.
+     */
+    public int getLineBreakIndex(int start, float maxAdvance) {
+        breaker.createAllSegments();
+        return breaker.getLineBreakIndex(start - aci.getBeginIndex(), maxAdvance)
+                + aci.getBeginIndex();
+    }
+}
diff --git a/awt/java/awt/font/TransformAttribute.java b/awt/java/awt/font/TransformAttribute.java
new file mode 100644
index 0000000..ff2caa2
--- /dev/null
+++ b/awt/java/awt/font/TransformAttribute.java
@@ -0,0 +1,86 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.awt.geom.AffineTransform;
+import java.io.Serializable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The TransformAttribute class is a wrapper for the AffineTransform class in
+ * order to use it as attribute.
+ * 
+ * @since Android 1.0
+ */
+public final class TransformAttribute implements Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 3356247357827709530L;
+
+    // affine transform of this TransformAttribute instance
+    /**
+     * The transform.
+     */
+    private AffineTransform fTransform;
+
+    /**
+     * Instantiates a new TransformAttribute from the specified AffineTransform.
+     * 
+     * @param transform
+     *            the AffineTransform to be wrapped.
+     */
+    public TransformAttribute(AffineTransform transform) {
+        if (transform == null) {
+            // awt.94=transform can not be null
+            throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$
+        }
+        if (!transform.isIdentity()) {
+            this.fTransform = new AffineTransform(transform);
+        }
+    }
+
+    /**
+     * Gets the initial AffineTransform which is wrapped.
+     * 
+     * @return the initial AffineTransform which is wrapped.
+     */
+    public AffineTransform getTransform() {
+        if (fTransform != null) {
+            return new AffineTransform(fTransform);
+        }
+        return new AffineTransform();
+    }
+
+    /**
+     * Checks if this transform is an identity transform.
+     * 
+     * @return true, if this transform is an identity transform, false
+     *         otherwise.
+     */
+    public boolean isIdentity() {
+        return (fTransform == null);
+    }
+
+}
diff --git a/awt/java/awt/font/package.html b/awt/java/awt/font/package.html
new file mode 100644
index 0000000..788dcc0
--- /dev/null
+++ b/awt/java/awt/font/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      This package contains classes to support the representation of different types of fonts for example TrueType fonts.
+    </p>
+    @since Android 1.0
+  </body>
+</html>
diff --git a/awt/java/awt/geom/AffineTransform.java b/awt/java/awt/geom/AffineTransform.java
new file mode 100644
index 0000000..8a6938c
--- /dev/null
+++ b/awt/java/awt/geom/AffineTransform.java
@@ -0,0 +1,1267 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import java.awt.Shape;
+import java.io.IOException;
+import java.io.Serializable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Class AffineTransform represents a linear transformation (rotation,
+ * scaling, or shear) followed by a translation that acts on a coordinate space.
+ * It preserves collinearity of points and ratios of distances between collinear
+ * points: so if A, B, and C are on a line, then after the space has been
+ * transformed via the affine transform, the images of the three points will
+ * still be on a line, and the ratio of the distance from A to B with the
+ * distance from B to C will be the same as the corresponding ratio in the image
+ * space.
+ * 
+ * @since Android 1.0
+ */
+public class AffineTransform implements Cloneable, Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 1330973210523860834L;
+
+    /**
+     * The Constant TYPE_IDENTITY.
+     */
+    public static final int TYPE_IDENTITY = 0;
+
+    /**
+     * The Constant TYPE_TRANSLATION.
+     */
+    public static final int TYPE_TRANSLATION = 1;
+
+    /**
+     * The Constant TYPE_UNIFORM_SCALE.
+     */
+    public static final int TYPE_UNIFORM_SCALE = 2;
+
+    /**
+     * The Constant TYPE_GENERAL_SCALE.
+     */
+    public static final int TYPE_GENERAL_SCALE = 4;
+
+    /**
+     * The Constant TYPE_QUADRANT_ROTATION.
+     */
+    public static final int TYPE_QUADRANT_ROTATION = 8;
+
+    /**
+     * The Constant TYPE_GENERAL_ROTATION.
+     */
+    public static final int TYPE_GENERAL_ROTATION = 16;
+
+    /**
+     * The Constant TYPE_GENERAL_TRANSFORM.
+     */
+    public static final int TYPE_GENERAL_TRANSFORM = 32;
+
+    /**
+     * The Constant TYPE_FLIP.
+     */
+    public static final int TYPE_FLIP = 64;
+
+    /**
+     * The Constant TYPE_MASK_SCALE.
+     */
+    public static final int TYPE_MASK_SCALE = TYPE_UNIFORM_SCALE | TYPE_GENERAL_SCALE;
+
+    /**
+     * The Constant TYPE_MASK_ROTATION.
+     */
+    public static final int TYPE_MASK_ROTATION = TYPE_QUADRANT_ROTATION | TYPE_GENERAL_ROTATION;
+
+    /**
+     * The <code>TYPE_UNKNOWN</code> is an initial type value.
+     */
+    static final int TYPE_UNKNOWN = -1;
+
+    /**
+     * The min value equivalent to zero. If absolute value less then ZERO it
+     * considered as zero.
+     */
+    static final double ZERO = 1E-10;
+
+    /**
+     * The values of transformation matrix.
+     */
+    double m00;
+
+    /**
+     * The m10.
+     */
+    double m10;
+
+    /**
+     * The m01.
+     */
+    double m01;
+
+    /**
+     * The m11.
+     */
+    double m11;
+
+    /**
+     * The m02.
+     */
+    double m02;
+
+    /**
+     * The m12.
+     */
+    double m12;
+
+    /**
+     * The transformation <code>type</code>.
+     */
+    transient int type;
+
+    /**
+     * Instantiates a new affine transform of type <code>TYPE_IDENTITY</code>
+     * (which leaves coordinates unchanged).
+     */
+    public AffineTransform() {
+        type = TYPE_IDENTITY;
+        m00 = m11 = 1.0;
+        m10 = m01 = m02 = m12 = 0.0;
+    }
+
+    /**
+     * Instantiates a new affine transform that has the same data as the given
+     * AffineTransform.
+     * 
+     * @param t
+     *            the transform to copy.
+     */
+    public AffineTransform(AffineTransform t) {
+        this.type = t.type;
+        this.m00 = t.m00;
+        this.m10 = t.m10;
+        this.m01 = t.m01;
+        this.m11 = t.m11;
+        this.m02 = t.m02;
+        this.m12 = t.m12;
+    }
+
+    /**
+     * Instantiates a new affine transform by specifying the values of the 2x3
+     * transformation matrix as floats. The type is set to the default type:
+     * <code>TYPE_UNKNOWN</code>
+     * 
+     * @param m00
+     *            the m00 entry in the transformation matrix.
+     * @param m10
+     *            the m10 entry in the transformation matrix.
+     * @param m01
+     *            the m01 entry in the transformation matrix.
+     * @param m11
+     *            the m11 entry in the transformation matrix.
+     * @param m02
+     *            the m02 entry in the transformation matrix.
+     * @param m12
+     *            the m12 entry in the transformation matrix.
+     */
+    public AffineTransform(float m00, float m10, float m01, float m11, float m02, float m12) {
+        this.type = TYPE_UNKNOWN;
+        this.m00 = m00;
+        this.m10 = m10;
+        this.m01 = m01;
+        this.m11 = m11;
+        this.m02 = m02;
+        this.m12 = m12;
+    }
+
+    /**
+     * Instantiates a new affine transform by specifying the values of the 2x3
+     * transformation matrix as doubles. The type is set to the default type:
+     * <code>TYPE_UNKNOWN</code>
+     * 
+     * @param m00
+     *            the m00 entry in the transformation matrix.
+     * @param m10
+     *            the m10 entry in the transformation matrix.
+     * @param m01
+     *            the m01 entry in the transformation matrix.
+     * @param m11
+     *            the m11 entry in the transformation matrix.
+     * @param m02
+     *            the m02 entry in the transformation matrix.
+     * @param m12
+     *            the m12 entry in the transformation matrix.
+     */
+    public AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12) {
+        this.type = TYPE_UNKNOWN;
+        this.m00 = m00;
+        this.m10 = m10;
+        this.m01 = m01;
+        this.m11 = m11;
+        this.m02 = m02;
+        this.m12 = m12;
+    }
+
+    /**
+     * Instantiates a new affine transform by reading the values of the
+     * transformation matrix from an array of floats. The mapping from the array
+     * to the matrix starts with <code>matrix[0]</code> giving the top-left
+     * entry of the matrix and proceeds with the usual left-to-right and
+     * top-down ordering.
+     * <p>
+     * If the array has only four entries, then the two entries of the last row
+     * of the transformation matrix default to zero.
+     * 
+     * @param matrix
+     *            the array of four or six floats giving the values of the
+     *            matrix.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if the size of the array is 0, 1, 2, 3, or 5.
+     */
+    public AffineTransform(float[] matrix) {
+        this.type = TYPE_UNKNOWN;
+        m00 = matrix[0];
+        m10 = matrix[1];
+        m01 = matrix[2];
+        m11 = matrix[3];
+        if (matrix.length > 4) {
+            m02 = matrix[4];
+            m12 = matrix[5];
+        }
+    }
+
+    /**
+     * Instantiates a new affine transform by reading the values of the
+     * transformation matrix from an array of doubles. The mapping from the
+     * array to the matrix starts with <code>matrix[0]</code> giving the
+     * top-left entry of the matrix and proceeds with the usual left-to-right
+     * and top-down ordering.
+     * <p>
+     * If the array has only four entries, then the two entries of the last row
+     * of the transformation matrix default to zero.
+     * 
+     * @param matrix
+     *            the array of four or six doubles giving the values of the
+     *            matrix.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if the size of the array is 0, 1, 2, 3, or 5.
+     */
+    public AffineTransform(double[] matrix) {
+        this.type = TYPE_UNKNOWN;
+        m00 = matrix[0];
+        m10 = matrix[1];
+        m01 = matrix[2];
+        m11 = matrix[3];
+        if (matrix.length > 4) {
+            m02 = matrix[4];
+            m12 = matrix[5];
+        }
+    }
+
+    /**
+     * Returns type of the affine transformation.
+     * <p>
+     * The type is computed as follows: Label the entries of the transformation
+     * matrix as three rows (m00, m01), (m10, m11), and (m02, m12). Then if the
+     * original basis vectors are (1, 0) and (0, 1), the new basis vectors after
+     * transformation are given by (m00, m01) and (m10, m11), and the
+     * translation vector is (m02, m12).
+     * <p>
+     * The types are classified as follows: <br/> TYPE_IDENTITY - no change<br/>
+     * TYPE_TRANSLATION - The translation vector isn't zero<br/>
+     * TYPE_UNIFORM_SCALE - The new basis vectors have equal length<br/>
+     * TYPE_GENERAL_SCALE - The new basis vectors dont' have equal length<br/>
+     * TYPE_FLIP - The new basis vector orientation differs from the original
+     * one<br/> TYPE_QUADRANT_ROTATION - The new basis is a rotation of the
+     * original by 90, 180, 270, or 360 degrees<br/> TYPE_GENERAL_ROTATION - The
+     * new basis is a rotation of the original by an arbitrary angle<br/>
+     * TYPE_GENERAL_TRANSFORM - The transformation can't be inverted.<br/>
+     * <p>
+     * Note that multiple types are possible, thus the types can be combined
+     * using bitwise combinations.
+     * 
+     * @return the type of the Affine Transform.
+     */
+    public int getType() {
+        if (type != TYPE_UNKNOWN) {
+            return type;
+        }
+
+        int type = 0;
+
+        if (m00 * m01 + m10 * m11 != 0.0) {
+            type |= TYPE_GENERAL_TRANSFORM;
+            return type;
+        }
+
+        if (m02 != 0.0 || m12 != 0.0) {
+            type |= TYPE_TRANSLATION;
+        } else if (m00 == 1.0 && m11 == 1.0 && m01 == 0.0 && m10 == 0.0) {
+            type = TYPE_IDENTITY;
+            return type;
+        }
+
+        if (m00 * m11 - m01 * m10 < 0.0) {
+            type |= TYPE_FLIP;
+        }
+
+        double dx = m00 * m00 + m10 * m10;
+        double dy = m01 * m01 + m11 * m11;
+        if (dx != dy) {
+            type |= TYPE_GENERAL_SCALE;
+        } else if (dx != 1.0) {
+            type |= TYPE_UNIFORM_SCALE;
+        }
+
+        if ((m00 == 0.0 && m11 == 0.0) || (m10 == 0.0 && m01 == 0.0 && (m00 < 0.0 || m11 < 0.0))) {
+            type |= TYPE_QUADRANT_ROTATION;
+        } else if (m01 != 0.0 || m10 != 0.0) {
+            type |= TYPE_GENERAL_ROTATION;
+        }
+
+        return type;
+    }
+
+    /**
+     * Gets the scale x entry of the transformation matrix (the upper left
+     * matrix entry).
+     * 
+     * @return the scale x value.
+     */
+    public double getScaleX() {
+        return m00;
+    }
+
+    /**
+     * Gets the scale y entry of the transformation matrix (the lower right
+     * entry of the linear transformation).
+     * 
+     * @return the scale y value.
+     */
+    public double getScaleY() {
+        return m11;
+    }
+
+    /**
+     * Gets the shear x entry of the transformation matrix (the upper right
+     * entry of the linear transformation).
+     * 
+     * @return the shear x value.
+     */
+    public double getShearX() {
+        return m01;
+    }
+
+    /**
+     * Gets the shear y entry of the transformation matrix (the lower left entry
+     * of the linear transformation).
+     * 
+     * @return the shear y value.
+     */
+    public double getShearY() {
+        return m10;
+    }
+
+    /**
+     * Gets the x coordinate of the translation vector.
+     * 
+     * @return the x coordinate of the translation vector.
+     */
+    public double getTranslateX() {
+        return m02;
+    }
+
+    /**
+     * Gets the y coordinate of the translation vector.
+     * 
+     * @return the y coordinate of the translation vector.
+     */
+    public double getTranslateY() {
+        return m12;
+    }
+
+    /**
+     * Checks if the AffineTransformation is the identity.
+     * 
+     * @return true, if the AffineTransformation is the identity.
+     */
+    public boolean isIdentity() {
+        return getType() == TYPE_IDENTITY;
+    }
+
+    /**
+     * Writes the values of the transformation matrix into the given array of
+     * doubles. If the array has length 4, only the linear transformation part
+     * will be written into it. If it has length greater than 4, the translation
+     * vector will be included as well.
+     * 
+     * @param matrix
+     *            the array to fill with the values of the matrix.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if the size of the array is 0, 1, 2, 3, or 5.
+     */
+    public void getMatrix(double[] matrix) {
+        matrix[0] = m00;
+        matrix[1] = m10;
+        matrix[2] = m01;
+        matrix[3] = m11;
+        if (matrix.length > 4) {
+            matrix[4] = m02;
+            matrix[5] = m12;
+        }
+    }
+
+    /**
+     * Gets the determinant of the linear transformation matrix.
+     * 
+     * @return the determinant of the linear transformation matrix.
+     */
+    public double getDeterminant() {
+        return m00 * m11 - m01 * m10;
+    }
+
+    /**
+     * Sets the transform in terms of a list of double values.
+     * 
+     * @param m00
+     *            the m00 coordinate of the transformation matrix.
+     * @param m10
+     *            the m10 coordinate of the transformation matrix.
+     * @param m01
+     *            the m01 coordinate of the transformation matrix.
+     * @param m11
+     *            the m11 coordinate of the transformation matrix.
+     * @param m02
+     *            the m02 coordinate of the transformation matrix.
+     * @param m12
+     *            the m12 coordinate of the transformation matrix.
+     */
+    public void setTransform(double m00, double m10, double m01, double m11, double m02, double m12) {
+        this.type = TYPE_UNKNOWN;
+        this.m00 = m00;
+        this.m10 = m10;
+        this.m01 = m01;
+        this.m11 = m11;
+        this.m02 = m02;
+        this.m12 = m12;
+    }
+
+    /**
+     * Sets the transform's data to match the data of the transform sent as a
+     * parameter.
+     * 
+     * @param t
+     *            the transform that gives the new values.
+     */
+    public void setTransform(AffineTransform t) {
+        type = t.type;
+        setTransform(t.m00, t.m10, t.m01, t.m11, t.m02, t.m12);
+    }
+
+    /**
+     * Sets the transform to the identity transform.
+     */
+    public void setToIdentity() {
+        type = TYPE_IDENTITY;
+        m00 = m11 = 1.0;
+        m10 = m01 = m02 = m12 = 0.0;
+    }
+
+    /**
+     * Sets the transformation to a translation alone. Sets the linear part of
+     * the transformation to identity and the translation vector to the values
+     * sent as parameters. Sets the type to <code>TYPE_IDENTITY</code> if the
+     * resulting AffineTransformation is the identity transformation, otherwise
+     * sets it to <code>TYPE_TRANSLATION</code>.
+     * 
+     * @param mx
+     *            the distance to translate in the x direction.
+     * @param my
+     *            the distance to translate in the y direction.
+     */
+    public void setToTranslation(double mx, double my) {
+        m00 = m11 = 1.0;
+        m01 = m10 = 0.0;
+        m02 = mx;
+        m12 = my;
+        if (mx == 0.0 && my == 0.0) {
+            type = TYPE_IDENTITY;
+        } else {
+            type = TYPE_TRANSLATION;
+        }
+    }
+
+    /**
+     * Sets the transformation to being a scale alone, eliminating rotation,
+     * shear, and translation elements. Sets the type to
+     * <code>TYPE_IDENTITY</code> if the resulting AffineTransformation is the
+     * identity transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>.
+     * 
+     * @param scx
+     *            the scaling factor in the x direction.
+     * @param scy
+     *            the scaling factor in the y direction.
+     */
+    public void setToScale(double scx, double scy) {
+        m00 = scx;
+        m11 = scy;
+        m10 = m01 = m02 = m12 = 0.0;
+        if (scx != 1.0 || scy != 1.0) {
+            type = TYPE_UNKNOWN;
+        } else {
+            type = TYPE_IDENTITY;
+        }
+    }
+
+    /**
+     * Sets the transformation to being a shear alone, eliminating rotation,
+     * scaling, and translation elements. Sets the type to
+     * <code>TYPE_IDENTITY</code> if the resulting AffineTransformation is the
+     * identity transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>.
+     * 
+     * @param shx
+     *            the shearing factor in the x direction.
+     * @param shy
+     *            the shearing factor in the y direction.
+     */
+    public void setToShear(double shx, double shy) {
+        m00 = m11 = 1.0;
+        m02 = m12 = 0.0;
+        m01 = shx;
+        m10 = shy;
+        if (shx != 0.0 || shy != 0.0) {
+            type = TYPE_UNKNOWN;
+        } else {
+            type = TYPE_IDENTITY;
+        }
+    }
+
+    /**
+     * Sets the transformation to being a rotation alone, eliminating shearing,
+     * scaling, and translation elements. Sets the type to
+     * <code>TYPE_IDENTITY</code> if the resulting AffineTransformation is the
+     * identity transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>.
+     * 
+     * @param angle
+     *            the angle of rotation in radians.
+     */
+    public void setToRotation(double angle) {
+        double sin = Math.sin(angle);
+        double cos = Math.cos(angle);
+        if (Math.abs(cos) < ZERO) {
+            cos = 0.0;
+            sin = sin > 0.0 ? 1.0 : -1.0;
+        } else if (Math.abs(sin) < ZERO) {
+            sin = 0.0;
+            cos = cos > 0.0 ? 1.0 : -1.0;
+        }
+        m00 = m11 = cos;
+        m01 = -sin;
+        m10 = sin;
+        m02 = m12 = 0.0;
+        type = TYPE_UNKNOWN;
+    }
+
+    /**
+     * Sets the transformation to being a rotation followed by a translation.
+     * Sets the type to <code>TYPE_UNKNOWN</code>.
+     * 
+     * @param angle
+     *            the angle of rotation in radians.
+     * @param px
+     *            the distance to translate in the x direction.
+     * @param py
+     *            the distance to translate in the y direction.
+     */
+    public void setToRotation(double angle, double px, double py) {
+        setToRotation(angle);
+        m02 = px * (1.0 - m00) + py * m10;
+        m12 = py * (1.0 - m00) - px * m10;
+        type = TYPE_UNKNOWN;
+    }
+
+    /**
+     * Creates a new AffineTransformation that is a translation alone with the
+     * translation vector given by the values sent as parameters. The new
+     * transformation's type is <code>TYPE_IDENTITY</code> if the
+     * AffineTransformation is the identity transformation, otherwise it's
+     * <code>TYPE_TRANSLATION</code>.
+     * 
+     * @param mx
+     *            the distance to translate in the x direction.
+     * @param my
+     *            the distance to translate in the y direction.
+     * @return the new AffineTransformation.
+     */
+    public static AffineTransform getTranslateInstance(double mx, double my) {
+        AffineTransform t = new AffineTransform();
+        t.setToTranslation(mx, my);
+        return t;
+    }
+
+    /**
+     * Creates a new AffineTransformation that is a scale alone. The new
+     * transformation's type is <code>TYPE_IDENTITY</code> if the
+     * AffineTransformation is the identity transformation, otherwise it's
+     * <code>TYPE_UNKNOWN</code>.
+     * 
+     * @param scx
+     *            the scaling factor in the x direction.
+     * @param scY
+     *            the scaling factor in the y direction.
+     * @return the new AffineTransformation.
+     */
+    public static AffineTransform getScaleInstance(double scx, double scY) {
+        AffineTransform t = new AffineTransform();
+        t.setToScale(scx, scY);
+        return t;
+    }
+
+    /**
+     * Creates a new AffineTransformation that is a shear alone. The new
+     * transformation's type is <code>TYPE_IDENTITY</code> if the
+     * AffineTransformation is the identity transformation, otherwise it's
+     * <code>TYPE_UNKNOWN</code>.
+     * 
+     * @param shx
+     *            the shearing factor in the x direction.
+     * @param shy
+     *            the shearing factor in the y direction.
+     * @return the new AffineTransformation.
+     */
+    public static AffineTransform getShearInstance(double shx, double shy) {
+        AffineTransform m = new AffineTransform();
+        m.setToShear(shx, shy);
+        return m;
+    }
+
+    /**
+     * Creates a new AffineTransformation that is a rotation alone. The new
+     * transformation's type is <code>TYPE_IDENTITY</code> if the
+     * AffineTransformation is the identity transformation, otherwise it's
+     * <code>TYPE_UNKNOWN</code>.
+     * 
+     * @param angle
+     *            the angle of rotation in radians.
+     * @return the new AffineTransformation.
+     */
+    public static AffineTransform getRotateInstance(double angle) {
+        AffineTransform t = new AffineTransform();
+        t.setToRotation(angle);
+        return t;
+    }
+
+    /**
+     * Creates a new AffineTransformation that is a rotation followed by a
+     * translation. Sets the type to <code>TYPE_UNKNOWN</code>.
+     * 
+     * @param angle
+     *            the angle of rotation in radians.
+     * @param x
+     *            the distance to translate in the x direction.
+     * @param y
+     *            the distance to translate in the y direction.
+     * @return the new AffineTransformation.
+     */
+    public static AffineTransform getRotateInstance(double angle, double x, double y) {
+        AffineTransform t = new AffineTransform();
+        t.setToRotation(angle, x, y);
+        return t;
+    }
+
+    /**
+     * Applies a translation to this AffineTransformation.
+     * 
+     * @param mx
+     *            the distance to translate in the x direction.
+     * @param my
+     *            the distance to translate in the y direction.
+     */
+    public void translate(double mx, double my) {
+        concatenate(AffineTransform.getTranslateInstance(mx, my));
+    }
+
+    /**
+     * Applies a scaling transformation to this AffineTransformation.
+     * 
+     * @param scx
+     *            the scaling factor in the x direction.
+     * @param scy
+     *            the scaling factor in the y direction.
+     */
+    public void scale(double scx, double scy) {
+        concatenate(AffineTransform.getScaleInstance(scx, scy));
+    }
+
+    /**
+     * Applies a shearing transformation to this AffineTransformation.
+     * 
+     * @param shx
+     *            the shearing factor in the x direction.
+     * @param shy
+     *            the shearing factor in the y direction.
+     */
+    public void shear(double shx, double shy) {
+        concatenate(AffineTransform.getShearInstance(shx, shy));
+    }
+
+    /**
+     * Applies a rotation transformation to this AffineTransformation.
+     * 
+     * @param angle
+     *            the angle of rotation in radians.
+     */
+    public void rotate(double angle) {
+        concatenate(AffineTransform.getRotateInstance(angle));
+    }
+
+    /**
+     * Applies a rotation and translation transformation to this
+     * AffineTransformation.
+     * 
+     * @param angle
+     *            the angle of rotation in radians.
+     * @param px
+     *            the distance to translate in the x direction.
+     * @param py
+     *            the distance to translate in the y direction.
+     */
+    public void rotate(double angle, double px, double py) {
+        concatenate(AffineTransform.getRotateInstance(angle, px, py));
+    }
+
+    /**
+     * Multiplies the matrix representations of two AffineTransform objects.
+     * 
+     * @param t1
+     *            - the AffineTransform object is a multiplicand
+     * @param t2
+     *            - the AffineTransform object is a multiplier
+     * @return an AffineTransform object that is the result of t1 multiplied by
+     *         the matrix t2.
+     */
+    AffineTransform multiply(AffineTransform t1, AffineTransform t2) {
+        return new AffineTransform(t1.m00 * t2.m00 + t1.m10 * t2.m01, // m00
+                t1.m00 * t2.m10 + t1.m10 * t2.m11, // m01
+                t1.m01 * t2.m00 + t1.m11 * t2.m01, // m10
+                t1.m01 * t2.m10 + t1.m11 * t2.m11, // m11
+                t1.m02 * t2.m00 + t1.m12 * t2.m01 + t2.m02, // m02
+                t1.m02 * t2.m10 + t1.m12 * t2.m11 + t2.m12);// m12
+    }
+
+    /**
+     * Applies the given AffineTransform to this AffineTransform via matrix
+     * multiplication.
+     * 
+     * @param t
+     *            the AffineTransform to apply to this AffineTransform.
+     */
+    public void concatenate(AffineTransform t) {
+        setTransform(multiply(t, this));
+    }
+
+    /**
+     * Changes the current AffineTransform the one obtained by taking the
+     * transform t and applying this AffineTransform to it.
+     * 
+     * @param t
+     *            the AffineTransform that this AffineTransform is multiplied
+     *            by.
+     */
+    public void preConcatenate(AffineTransform t) {
+        setTransform(multiply(this, t));
+    }
+
+    /**
+     * Creates an AffineTransform that is the inverse of this transform.
+     * 
+     * @return the affine transform that is the inverse of this AffineTransform.
+     * @throws NoninvertibleTransformException
+     *             if this AffineTransform cannot be inverted (the determinant
+     *             of the linear transformation part is zero).
+     */
+    public AffineTransform createInverse() throws NoninvertibleTransformException {
+        double det = getDeterminant();
+        if (Math.abs(det) < ZERO) {
+            // awt.204=Determinant is zero
+            throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$
+        }
+        return new AffineTransform(m11 / det, // m00
+                -m10 / det, // m10
+                -m01 / det, // m01
+                m00 / det, // m11
+                (m01 * m12 - m11 * m02) / det, // m02
+                (m10 * m02 - m00 * m12) / det // m12
+        );
+    }
+
+    /**
+     * Apply the current AffineTransform to the point.
+     * 
+     * @param src
+     *            the original point.
+     * @param dst
+     *            Point2D object to be filled with the destination coordinates
+     *            (where the original point is sent by this AffineTransform).
+     *            May be null.
+     * @return the point in the AffineTransform's image space where the original
+     *         point is sent.
+     */
+    public Point2D transform(Point2D src, Point2D dst) {
+        if (dst == null) {
+            if (src instanceof Point2D.Double) {
+                dst = new Point2D.Double();
+            } else {
+                dst = new Point2D.Float();
+            }
+        }
+
+        double x = src.getX();
+        double y = src.getY();
+
+        dst.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12);
+        return dst;
+    }
+
+    /**
+     * Applies this AffineTransform to an array of points.
+     * 
+     * @param src
+     *            the array of points to be transformed.
+     * @param srcOff
+     *            the offset in the source point array of the first point to be
+     *            transformed.
+     * @param dst
+     *            the point array where the images of the points (after applying
+     *            the AffineTransformation) should be placed.
+     * @param dstOff
+     *            the offset in the destination array where the new values
+     *            should be written.
+     * @param length
+     *            the number of points to transform.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if <code>srcOff + length > src.length</code> or
+     *             <code>dstOff + length > dst.length</code>.
+     */
+    public void transform(Point2D[] src, int srcOff, Point2D[] dst, int dstOff, int length) {
+        while (--length >= 0) {
+            Point2D srcPoint = src[srcOff++];
+            double x = srcPoint.getX();
+            double y = srcPoint.getY();
+            Point2D dstPoint = dst[dstOff];
+            if (dstPoint == null) {
+                if (srcPoint instanceof Point2D.Double) {
+                    dstPoint = new Point2D.Double();
+                } else {
+                    dstPoint = new Point2D.Float();
+                }
+            }
+            dstPoint.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12);
+            dst[dstOff++] = dstPoint;
+        }
+    }
+
+    /**
+     * Applies this AffineTransform to a set of points given as an array of
+     * double values where every two values in the array give the coordinates of
+     * a point; the even-indexed values giving the x coordinates and the
+     * odd-indexed values giving the y coordinates.
+     * 
+     * @param src
+     *            the array of points to be transformed.
+     * @param srcOff
+     *            the offset in the source point array of the first point to be
+     *            transformed.
+     * @param dst
+     *            the point array where the images of the points (after applying
+     *            the AffineTransformation) should be placed.
+     * @param dstOff
+     *            the offset in the destination array where the new values
+     *            should be written.
+     * @param length
+     *            the number of points to transform.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if <code>srcOff + length*2 > src.length</code> or
+     *             <code>dstOff + length*2 > dst.length</code>.
+     */
+    public void transform(double[] src, int srcOff, double[] dst, int dstOff, int length) {
+        int step = 2;
+        if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) {
+            srcOff = srcOff + length * 2 - 2;
+            dstOff = dstOff + length * 2 - 2;
+            step = -2;
+        }
+        while (--length >= 0) {
+            double x = src[srcOff + 0];
+            double y = src[srcOff + 1];
+            dst[dstOff + 0] = x * m00 + y * m01 + m02;
+            dst[dstOff + 1] = x * m10 + y * m11 + m12;
+            srcOff += step;
+            dstOff += step;
+        }
+    }
+
+    /**
+     * Applies this AffineTransform to a set of points given as an array of
+     * float values where every two values in the array give the coordinates of
+     * a point; the even-indexed values giving the x coordinates and the
+     * odd-indexed values giving the y coordinates.
+     * 
+     * @param src
+     *            the array of points to be transformed.
+     * @param srcOff
+     *            the offset in the source point array of the first point to be
+     *            transformed.
+     * @param dst
+     *            the point array where the images of the points (after applying
+     *            the AffineTransformation) should be placed.
+     * @param dstOff
+     *            the offset in the destination array where the new values
+     *            should be written.
+     * @param length
+     *            the number of points to transform.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if <code>srcOff + length*2 > src.length</code> or
+     *             <code>dstOff + length*2 > dst.length</code>.
+     */
+    public void transform(float[] src, int srcOff, float[] dst, int dstOff, int length) {
+        int step = 2;
+        if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) {
+            srcOff = srcOff + length * 2 - 2;
+            dstOff = dstOff + length * 2 - 2;
+            step = -2;
+        }
+        while (--length >= 0) {
+            float x = src[srcOff + 0];
+            float y = src[srcOff + 1];
+            dst[dstOff + 0] = (float)(x * m00 + y * m01 + m02);
+            dst[dstOff + 1] = (float)(x * m10 + y * m11 + m12);
+            srcOff += step;
+            dstOff += step;
+        }
+    }
+
+    /**
+     * Applies this AffineTransform to a set of points given as an array of
+     * float values where every two values in the array give the coordinates of
+     * a point; the even-indexed values giving the x coordinates and the
+     * odd-indexed values giving the y coordinates. The destination coordinates
+     * are given as values of type <code>double</code>.
+     * 
+     * @param src
+     *            the array of points to be transformed.
+     * @param srcOff
+     *            the offset in the source point array of the first point to be
+     *            transformed.
+     * @param dst
+     *            the point array where the images of the points (after applying
+     *            the AffineTransformation) should be placed.
+     * @param dstOff
+     *            the offset in the destination array where the new values
+     *            should be written.
+     * @param length
+     *            the number of points to transform.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if <code>srcOff + length*2 > src.length</code> or
+     *             <code>dstOff + length*2 > dst.length</code>.
+     */
+    public void transform(float[] src, int srcOff, double[] dst, int dstOff, int length) {
+        while (--length >= 0) {
+            float x = src[srcOff++];
+            float y = src[srcOff++];
+            dst[dstOff++] = x * m00 + y * m01 + m02;
+            dst[dstOff++] = x * m10 + y * m11 + m12;
+        }
+    }
+
+    /**
+     * Applies this AffineTransform to a set of points given as an array of
+     * double values where every two values in the array give the coordinates of
+     * a point; the even-indexed values giving the x coordinates and the
+     * odd-indexed values giving the y coordinates. The destination coordinates
+     * are given as values of type <code>float</code>.
+     * 
+     * @param src
+     *            the array of points to be transformed.
+     * @param srcOff
+     *            the offset in the source point array of the first point to be
+     *            transformed.
+     * @param dst
+     *            the point array where the images of the points (after applying
+     *            the AffineTransformation) should be placed.
+     * @param dstOff
+     *            the offset in the destination array where the new values
+     *            should be written.
+     * @param length
+     *            the number of points to transform.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if <code>srcOff + length*2 > src.length</code> or
+     *             <code>dstOff + length*2 > dst.length</code>.
+     */
+    public void transform(double[] src, int srcOff, float[] dst, int dstOff, int length) {
+        while (--length >= 0) {
+            double x = src[srcOff++];
+            double y = src[srcOff++];
+            dst[dstOff++] = (float)(x * m00 + y * m01 + m02);
+            dst[dstOff++] = (float)(x * m10 + y * m11 + m12);
+        }
+    }
+
+    /**
+     * Transforms the point according to the linear transformation part of this
+     * AffineTransformation (without applying the translation).
+     * 
+     * @param src
+     *            the original point.
+     * @param dst
+     *            the point object where the result of the delta transform is
+     *            written.
+     * @return the result of applying the delta transform (linear part only) to
+     *         the original point.
+     */
+    // TODO: is this right? if dst is null, we check what it's an
+    // instance of? Shouldn't it be src instanceof Point2D.Double?
+    public Point2D deltaTransform(Point2D src, Point2D dst) {
+        if (dst == null) {
+            if (dst instanceof Point2D.Double) {
+                dst = new Point2D.Double();
+            } else {
+                dst = new Point2D.Float();
+            }
+        }
+
+        double x = src.getX();
+        double y = src.getY();
+
+        dst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
+        return dst;
+    }
+
+    /**
+     * Applies the linear transformation part of this AffineTransform (ignoring
+     * the translation part) to a set of points given as an array of double
+     * values where every two values in the array give the coordinates of a
+     * point; the even-indexed values giving the x coordinates and the
+     * odd-indexed values giving the y coordinates.
+     * 
+     * @param src
+     *            the array of points to be transformed.
+     * @param srcOff
+     *            the offset in the source point array of the first point to be
+     *            transformed.
+     * @param dst
+     *            the point array where the images of the points (after applying
+     *            the delta transformation) should be placed.
+     * @param dstOff
+     *            the offset in the destination array where the new values
+     *            should be written.
+     * @param length
+     *            the number of points to transform.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if <code>srcOff + length*2 > src.length</code> or
+     *             <code>dstOff + length*2 > dst.length</code>.
+     */
+    public void deltaTransform(double[] src, int srcOff, double[] dst, int dstOff, int length) {
+        while (--length >= 0) {
+            double x = src[srcOff++];
+            double y = src[srcOff++];
+            dst[dstOff++] = x * m00 + y * m01;
+            dst[dstOff++] = x * m10 + y * m11;
+        }
+    }
+
+    /**
+     * Transforms the point according to the inverse of this
+     * AffineTransformation.
+     * 
+     * @param src
+     *            the original point.
+     * @param dst
+     *            the point object where the result of the inverse transform is
+     *            written (may be null).
+     * @return the result of applying the inverse transform. Inverse transform.
+     * @throws NoninvertibleTransformException
+     *             if this AffineTransform cannot be inverted (the determinant
+     *             of the linear transformation part is zero).
+     */
+    public Point2D inverseTransform(Point2D src, Point2D dst)
+            throws NoninvertibleTransformException {
+        double det = getDeterminant();
+        if (Math.abs(det) < ZERO) {
+            // awt.204=Determinant is zero
+            throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$
+        }
+
+        if (dst == null) {
+            if (src instanceof Point2D.Double) {
+                dst = new Point2D.Double();
+            } else {
+                dst = new Point2D.Float();
+            }
+        }
+
+        double x = src.getX() - m02;
+        double y = src.getY() - m12;
+
+        dst.setLocation((x * m11 - y * m01) / det, (y * m00 - x * m10) / det);
+        return dst;
+    }
+
+    /**
+     * Applies the inverse of this AffineTransform to a set of points given as
+     * an array of double values where every two values in the array give the
+     * coordinates of a point; the even-indexed values giving the x coordinates
+     * and the odd-indexed values giving the y coordinates.
+     * 
+     * @param src
+     *            the array of points to be transformed.
+     * @param srcOff
+     *            the offset in the source point array of the first point to be
+     *            transformed.
+     * @param dst
+     *            the point array where the images of the points (after applying
+     *            the inverse of the AffineTransformation) should be placed.
+     * @param dstOff
+     *            the offset in the destination array where the new values
+     *            should be written.
+     * @param length
+     *            the number of points to transform.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if <code>srcOff + length*2 > src.length</code> or
+     *             <code>dstOff + length*2 > dst.length</code>.
+     * @throws NoninvertibleTransformException
+     *             if this AffineTransform cannot be inverted (the determinant
+     *             of the linear transformation part is zero).
+     */
+    public void inverseTransform(double[] src, int srcOff, double[] dst, int dstOff, int length)
+            throws NoninvertibleTransformException {
+        double det = getDeterminant();
+        if (Math.abs(det) < ZERO) {
+            // awt.204=Determinant is zero
+            throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$
+        }
+
+        while (--length >= 0) {
+            double x = src[srcOff++] - m02;
+            double y = src[srcOff++] - m12;
+            dst[dstOff++] = (x * m11 - y * m01) / det;
+            dst[dstOff++] = (y * m00 - x * m10) / det;
+        }
+    }
+
+    /**
+     * Creates a new shape whose data is given by applying this AffineTransform
+     * to the specified shape.
+     * 
+     * @param src
+     *            the original shape whose data is to be transformed.
+     * @return the new shape found by applying this AffineTransform to the
+     *         original shape.
+     */
+    public Shape createTransformedShape(Shape src) {
+        if (src == null) {
+            return null;
+        }
+        if (src instanceof GeneralPath) {
+            return ((GeneralPath)src).createTransformedShape(this);
+        }
+        PathIterator path = src.getPathIterator(this);
+        GeneralPath dst = new GeneralPath(path.getWindingRule());
+        dst.append(path, false);
+        return dst;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getName() + "[[" + m00 + ", " + m01 + ", " + m02 + "], [" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+                + m10 + ", " + m11 + ", " + m12 + "]]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        HashCode hash = new HashCode();
+        hash.append(m00);
+        hash.append(m01);
+        hash.append(m02);
+        hash.append(m10);
+        hash.append(m11);
+        hash.append(m12);
+        return hash.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof AffineTransform) {
+            AffineTransform t = (AffineTransform)obj;
+            return m00 == t.m00 && m01 == t.m01 && m02 == t.m02 && m10 == t.m10 && m11 == t.m11
+                    && m12 == t.m12;
+        }
+        return false;
+    }
+
+    /**
+     * Writes the AffineTrassform object to the output steam.
+     * 
+     * @param stream
+     *            - the output stream.
+     * @throws IOException
+     *             - if there are I/O errors while writing to the output stream.
+     */
+    private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
+        stream.defaultWriteObject();
+    }
+
+    /**
+     * Read the AffineTransform object from the input stream.
+     * 
+     * @param stream
+     *            - the input stream.
+     * @throws IOException
+     *             - if there are I/O errors while reading from the input
+     *             stream.
+     * @throws ClassNotFoundException
+     *             - if class could not be found.
+     */
+    private void readObject(java.io.ObjectInputStream stream) throws IOException,
+            ClassNotFoundException {
+        stream.defaultReadObject();
+        type = TYPE_UNKNOWN;
+    }
+
+}
diff --git a/awt/java/awt/geom/Arc2D.java b/awt/java/awt/geom/Arc2D.java
new file mode 100644
index 0000000..56f5cd3
--- /dev/null
+++ b/awt/java/awt/geom/Arc2D.java
@@ -0,0 +1,1157 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class Arc2D represents a segment of a curve inscribed in a rectangle. The
+ * curve is defined by a start angle and an extent angle (the end angle minus
+ * the start angle) as a pie wedge whose point is in the center of the
+ * rectangle. The Arc2D as a shape may be either OPEN (including nothing but the
+ * curved arc segment itself), CHORD (the curved arc segment closed by a
+ * connecting segment from the end to the beginning of the arc, or PIE (the
+ * segments from the end of the arc to the center of the rectangle and from the
+ * center of the rectangle back to the arc's start point are included).
+ * 
+ * @since Android 1.0
+ */
+public abstract class Arc2D extends RectangularShape {
+
+    /**
+     * The arc type OPEN indicates that the shape includes only the curved arc
+     * segment.
+     */
+    public final static int OPEN = 0;
+
+    /**
+     * The arc type CHORD indicates that as a shape the connecting segment from
+     * the end point of the curved arc to the beginning point is included.
+     */
+    public final static int CHORD = 1;
+
+    /**
+     * The arc type PIE indicates that as a shape the two segments from the
+     * arc's endpoint to the center of the rectangle and from the center of the
+     * rectangle to the arc's endpoint are included.
+     */
+    public final static int PIE = 2;
+
+    /**
+     * The Class Float is a subclass of Arc2D in which all of the data values
+     * are given as floats.
+     * 
+     * @see Arc2D.Double
+     * @since Android 1.0
+     */
+    public static class Float extends Arc2D {
+
+        /**
+         * The x coordinate of the upper left corner of the rectangle that
+         * contains the arc.
+         */
+        public float x;
+
+        /**
+         * The y coordinate of the upper left corner of the rectangle that
+         * contains the arc.
+         */
+        public float y;
+
+        /**
+         * The width of the rectangle that contains the arc.
+         */
+        public float width;
+
+        /**
+         * The height of the rectangle that contains the arc.
+         */
+        public float height;
+
+        /**
+         * The start angle of the arc in degrees.
+         */
+        public float start;
+
+        /**
+         * The width angle of the arc in degrees.
+         */
+        public float extent;
+
+        /**
+         * Instantiates a new Arc2D of type OPEN with float values.
+         */
+        public Float() {
+            super(OPEN);
+        }
+
+        /**
+         * Instantiates a new Arc2D of the specified type with float values.
+         * 
+         * @param type
+         *            the type of the new Arc2D, either {@link Arc2D#OPEN},
+         *            {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+         */
+        public Float(int type) {
+            super(type);
+        }
+
+        /**
+         * Instantiates a Arc2D with the specified float-valued data.
+         * 
+         * @param x
+         *            the x coordinate of the upper left corner of the rectangle
+         *            that contains the arc.
+         * @param y
+         *            the y coordinate of the upper left corner of the rectangle
+         *            that contains the arc.
+         * @param width
+         *            the width of the rectangle that contains the arc.
+         * @param height
+         *            the height of the rectangle that contains the arc.
+         * @param start
+         *            the start angle of the arc in degrees.
+         * @param extent
+         *            the width angle of the arc in degrees.
+         * @param type
+         *            the type of the new Arc2D, either {@link Arc2D#OPEN},
+         *            {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+         */
+        public Float(float x, float y, float width, float height, float start, float extent,
+                int type) {
+            super(type);
+            this.x = x;
+            this.y = y;
+            this.width = width;
+            this.height = height;
+            this.start = start;
+            this.extent = extent;
+        }
+
+        /**
+         * Instantiates a new Angle2D with the specified float-valued data and
+         * the bounding rectangle given by the parameter bounds.
+         * 
+         * @param bounds
+         *            the bounding rectangle of the Angle2D.
+         * @param start
+         *            the start angle of the arc in degrees.
+         * @param extent
+         *            the width angle of the arc in degrees.
+         * @param type
+         *            the type of the new Arc2D, either {@link Arc2D#OPEN},
+         *            {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+         */
+        public Float(Rectangle2D bounds, float start, float extent, int type) {
+            super(type);
+            this.x = (float)bounds.getX();
+            this.y = (float)bounds.getY();
+            this.width = (float)bounds.getWidth();
+            this.height = (float)bounds.getHeight();
+            this.start = start;
+            this.extent = extent;
+        }
+
+        @Override
+        public double getX() {
+            return x;
+        }
+
+        @Override
+        public double getY() {
+            return y;
+        }
+
+        @Override
+        public double getWidth() {
+            return width;
+        }
+
+        @Override
+        public double getHeight() {
+            return height;
+        }
+
+        @Override
+        public double getAngleStart() {
+            return start;
+        }
+
+        @Override
+        public double getAngleExtent() {
+            return extent;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return width <= 0.0f || height <= 0.0f;
+        }
+
+        @Override
+        public void setArc(double x, double y, double width, double height, double start,
+                double extent, int type) {
+            this.setArcType(type);
+            this.x = (float)x;
+            this.y = (float)y;
+            this.width = (float)width;
+            this.height = (float)height;
+            this.start = (float)start;
+            this.extent = (float)extent;
+        }
+
+        @Override
+        public void setAngleStart(double start) {
+            this.start = (float)start;
+        }
+
+        @Override
+        public void setAngleExtent(double extent) {
+            this.extent = (float)extent;
+        }
+
+        @Override
+        protected Rectangle2D makeBounds(double x, double y, double width, double height) {
+            return new Rectangle2D.Float((float)x, (float)y, (float)width, (float)height);
+        }
+
+    }
+
+    /**
+     * The Class Double is a subclass of Arc2D in which all of the data values
+     * are given as doubles.
+     * 
+     * @see Arc2D.Float
+     * @since Android 1.0
+     */
+    public static class Double extends Arc2D {
+
+        /**
+         * The x coordinate of the upper left corner of the rectangle that
+         * contains the arc.
+         */
+        public double x;
+
+        /**
+         * The y coordinate of the upper left corner of the rectangle that
+         * contains the arc.
+         */
+        public double y;
+
+        /**
+         * The width of the rectangle that contains the arc.
+         */
+        public double width;
+
+        /**
+         * The height of the rectangle that contains the arc.
+         */
+        public double height;
+
+        /**
+         * The start angle of the arc in degrees.
+         */
+        public double start;
+
+        /**
+         * The width angle of the arc in degrees.
+         */
+        public double extent;
+
+        /**
+         * Instantiates a new Arc2D of type OPEN with double values.
+         */
+        public Double() {
+            super(OPEN);
+        }
+
+        /**
+         * Instantiates a new Arc2D of the specified type with double values.
+         * 
+         * @param type
+         *            the type of the new Arc2D, either {@link Arc2D#OPEN},
+         *            {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+         */
+        public Double(int type) {
+            super(type);
+        }
+
+        /**
+         * Instantiates a Arc2D with the specified double-valued data.
+         * 
+         * @param x
+         *            the x coordinate of the upper left corner of the rectangle
+         *            that contains the arc.
+         * @param y
+         *            the y coordinate of the upper left corner of the rectangle
+         *            that contains the arc.
+         * @param width
+         *            the width of the rectangle that contains the arc.
+         * @param height
+         *            the height of the rectangle that contains the arc.
+         * @param start
+         *            the start angle of the arc in degrees.
+         * @param extent
+         *            the width angle of the arc in degrees.
+         * @param type
+         *            the type of the new Arc2D, either {@link Arc2D#OPEN},
+         *            {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+         */
+        public Double(double x, double y, double width, double height, double start, double extent,
+                int type) {
+            super(type);
+            this.x = x;
+            this.y = y;
+            this.width = width;
+            this.height = height;
+            this.start = start;
+            this.extent = extent;
+        }
+
+        /**
+         * Instantiates a new Angle2D with the specified float-valued data and
+         * the bounding rectangle given by the parameter bounds.
+         * 
+         * @param bounds
+         *            the bounding rectangle of the Angle2D.
+         * @param start
+         *            the start angle of the arc in degrees.
+         * @param extent
+         *            the width angle of the arc in degrees.
+         * @param type
+         *            the type of the new Arc2D, either {@link Arc2D#OPEN},
+         *            {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+         */
+        public Double(Rectangle2D bounds, double start, double extent, int type) {
+            super(type);
+            this.x = bounds.getX();
+            this.y = bounds.getY();
+            this.width = bounds.getWidth();
+            this.height = bounds.getHeight();
+            this.start = start;
+            this.extent = extent;
+        }
+
+        @Override
+        public double getX() {
+            return x;
+        }
+
+        @Override
+        public double getY() {
+            return y;
+        }
+
+        @Override
+        public double getWidth() {
+            return width;
+        }
+
+        @Override
+        public double getHeight() {
+            return height;
+        }
+
+        @Override
+        public double getAngleStart() {
+            return start;
+        }
+
+        @Override
+        public double getAngleExtent() {
+            return extent;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return width <= 0.0 || height <= 0.0;
+        }
+
+        @Override
+        public void setArc(double x, double y, double width, double height, double start,
+                double extent, int type) {
+            this.setArcType(type);
+            this.x = x;
+            this.y = y;
+            this.width = width;
+            this.height = height;
+            this.start = start;
+            this.extent = extent;
+        }
+
+        @Override
+        public void setAngleStart(double start) {
+            this.start = start;
+        }
+
+        @Override
+        public void setAngleExtent(double extent) {
+            this.extent = extent;
+        }
+
+        @Override
+        protected Rectangle2D makeBounds(double x, double y, double width, double height) {
+            return new Rectangle2D.Double(x, y, width, height);
+        }
+
+    }
+
+    /**
+     * The Class Iterator is the subclass of PathIterator that is used to
+     * traverse the boundary of a shape of type Arc2D.
+     */
+    class Iterator implements PathIterator {
+
+        /**
+         * The x coordinate of the center of the arc's bounding rectangle.
+         */
+        double x;
+
+        /**
+         * The y coordinate of the center of the arc's bounding rectangle.
+         */
+        double y;
+
+        /**
+         * Half of the width of the arc's bounding rectangle (the radius in the
+         * case of a circular arc).
+         */
+        double width;
+
+        /**
+         * Half of the height of the arc's bounding rectangle (the radius in the
+         * case of a circular arc).
+         */
+        double height;
+
+        /**
+         * The start angle of the arc in degrees.
+         */
+        double angle;
+
+        /**
+         * The angle extent in degrees.
+         */
+        double extent;
+
+        /**
+         * The closure type of the arc.
+         */
+        int type;
+
+        /**
+         * The path iterator transformation.
+         */
+        AffineTransform t;
+
+        /**
+         * The current segment index.
+         */
+        int index;
+
+        /**
+         * The number of arc segments the source arc subdivided to be
+         * approximated by Bezier curves. Depends on extent value.
+         */
+        int arcCount;
+
+        /**
+         * The number of line segments. Depends on closure type.
+         */
+        int lineCount;
+
+        /**
+         * The step to calculate next arc subdivision point.
+         */
+        double step;
+
+        /**
+         * The temporary value of cosinus of the current angle.
+         */
+        double cos;
+
+        /**
+         * The temporary value of sinus of the current angle.
+         */
+        double sin;
+
+        /** The coefficient to calculate control points of Bezier curves. */
+        double k;
+
+        /**
+         * The temporary value of x coordinate of the Bezier curve control
+         * vector.
+         */
+        double kx;
+
+        /**
+         * The temporary value of y coordinate of the Bezier curve control
+         * vector.
+         */
+        double ky;
+
+        /**
+         * The x coordinate of the first path point (MOVE_TO).
+         */
+        double mx;
+
+        /**
+         * The y coordinate of the first path point (MOVE_TO).
+         */
+        double my;
+
+        /**
+         * Constructs a new Arc2D.Iterator for given line and transformation
+         * 
+         * @param a
+         *            the source Arc2D object.
+         * @param t
+         *            the AffineTransformation.
+         */
+        Iterator(Arc2D a, AffineTransform t) {
+            if (width < 0 || height < 0) {
+                arcCount = 0;
+                lineCount = 0;
+                index = 1;
+                return;
+            }
+
+            this.width = a.getWidth() / 2.0;
+            this.height = a.getHeight() / 2.0;
+            this.x = a.getX() + width;
+            this.y = a.getY() + height;
+            this.angle = -Math.toRadians(a.getAngleStart());
+            this.extent = -a.getAngleExtent();
+            this.type = a.getArcType();
+            this.t = t;
+
+            if (Math.abs(extent) >= 360.0) {
+                arcCount = 4;
+                k = 4.0 / 3.0 * (Math.sqrt(2.0) - 1.0);
+                step = Math.PI / 2.0;
+                if (extent < 0.0) {
+                    step = -step;
+                    k = -k;
+                }
+            } else {
+                arcCount = (int)Math.rint(Math.abs(extent) / 90.0);
+                step = Math.toRadians(extent / arcCount);
+                k = 4.0 / 3.0 * (1.0 - Math.cos(step / 2.0)) / Math.sin(step / 2.0);
+            }
+
+            lineCount = 0;
+            if (type == Arc2D.CHORD) {
+                lineCount++;
+            } else if (type == Arc2D.PIE) {
+                lineCount += 2;
+            }
+        }
+
+        public int getWindingRule() {
+            return WIND_NON_ZERO;
+        }
+
+        public boolean isDone() {
+            return index > arcCount + lineCount;
+        }
+
+        public void next() {
+            index++;
+        }
+
+        public int currentSegment(double[] coords) {
+            if (isDone()) {
+                // awt.4B=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            int type;
+            int count;
+            if (index == 0) {
+                type = SEG_MOVETO;
+                count = 1;
+                cos = Math.cos(angle);
+                sin = Math.sin(angle);
+                kx = k * width * sin;
+                ky = k * height * cos;
+                coords[0] = mx = x + cos * width;
+                coords[1] = my = y + sin * height;
+            } else if (index <= arcCount) {
+                type = SEG_CUBICTO;
+                count = 3;
+                coords[0] = mx - kx;
+                coords[1] = my + ky;
+                angle += step;
+                cos = Math.cos(angle);
+                sin = Math.sin(angle);
+                kx = k * width * sin;
+                ky = k * height * cos;
+                coords[4] = mx = x + cos * width;
+                coords[5] = my = y + sin * height;
+                coords[2] = mx + kx;
+                coords[3] = my - ky;
+            } else if (index == arcCount + lineCount) {
+                type = SEG_CLOSE;
+                count = 0;
+            } else {
+                type = SEG_LINETO;
+                count = 1;
+                coords[0] = x;
+                coords[1] = y;
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, count);
+            }
+            return type;
+        }
+
+        public int currentSegment(float[] coords) {
+            if (isDone()) {
+                // awt.4B=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            int type;
+            int count;
+            if (index == 0) {
+                type = SEG_MOVETO;
+                count = 1;
+                cos = Math.cos(angle);
+                sin = Math.sin(angle);
+                kx = k * width * sin;
+                ky = k * height * cos;
+                coords[0] = (float)(mx = x + cos * width);
+                coords[1] = (float)(my = y + sin * height);
+            } else if (index <= arcCount) {
+                type = SEG_CUBICTO;
+                count = 3;
+                coords[0] = (float)(mx - kx);
+                coords[1] = (float)(my + ky);
+                angle += step;
+                cos = Math.cos(angle);
+                sin = Math.sin(angle);
+                kx = k * width * sin;
+                ky = k * height * cos;
+                coords[4] = (float)(mx = x + cos * width);
+                coords[5] = (float)(my = y + sin * height);
+                coords[2] = (float)(mx + kx);
+                coords[3] = (float)(my - ky);
+            } else if (index == arcCount + lineCount) {
+                type = SEG_CLOSE;
+                count = 0;
+            } else {
+                type = SEG_LINETO;
+                count = 1;
+                coords[0] = (float)x;
+                coords[1] = (float)y;
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, count);
+            }
+            return type;
+        }
+
+    }
+
+    /**
+     * The closure type of the arc.
+     */
+    private int type;
+
+    /**
+     * Instantiates a new arc2D.
+     * 
+     * @param type
+     *            the closure type.
+     */
+    protected Arc2D(int type) {
+        setArcType(type);
+    }
+
+    /**
+     * Takes the double-valued data and creates the corresponding Rectangle2D
+     * object with values either of type float or of type double depending on
+     * whether this Arc2D instance is of type Float or Double.
+     * 
+     * @param x
+     *            the x coordinate of the upper left corner of the bounding
+     *            rectangle.
+     * @param y
+     *            the y coordinate of the upper left corner of the bounding
+     *            rectangle.
+     * @param width
+     *            the width of the bounding rectangle.
+     * @param height
+     *            the height of the bounding rectangle.
+     * @return the corresponding Rectangle2D object.
+     */
+    protected abstract Rectangle2D makeBounds(double x, double y, double width, double height);
+
+    /**
+     * Gets the start angle.
+     * 
+     * @return the start angle.
+     */
+    public abstract double getAngleStart();
+
+    /**
+     * Gets the width angle.
+     * 
+     * @return the width angle.
+     */
+    public abstract double getAngleExtent();
+
+    /**
+     * Sets the start angle.
+     * 
+     * @param start
+     *            the new start angle.
+     */
+    public abstract void setAngleStart(double start);
+
+    /**
+     * Sets the width angle.
+     * 
+     * @param extent
+     *            the new width angle.
+     */
+    public abstract void setAngleExtent(double extent);
+
+    /**
+     * Sets the data values that define the arc.
+     * 
+     * @param x
+     *            the x coordinate of the upper left corner of the rectangle
+     *            that contains the arc.
+     * @param y
+     *            the y coordinate of the upper left corner of the rectangle
+     *            that contains the arc.
+     * @param width
+     *            the width of the rectangle that contains the arc.
+     * @param height
+     *            the height of the rectangle that contains the arc.
+     * @param start
+     *            the start angle of the arc in degrees.
+     * @param extent
+     *            the width angle of the arc in degrees.
+     * @param type
+     *            the type of the new Arc2D, either {@link Arc2D#OPEN},
+     *            {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+     */
+    public abstract void setArc(double x, double y, double width, double height, double start,
+            double extent, int type);
+
+    /**
+     * Gets the arc type, either {@link Arc2D#OPEN}, {@link Arc2D#CHORD}, or
+     * {@link Arc2D#PIE}.
+     * 
+     * @return the arc type.
+     */
+    public int getArcType() {
+        return type;
+    }
+
+    /**
+     * Sets the arc type, either {@link Arc2D#OPEN}, {@link Arc2D#CHORD}, or
+     * {@link Arc2D#PIE}.
+     * 
+     * @param type
+     *            the new arc type.
+     */
+    public void setArcType(int type) {
+        if (type != OPEN && type != CHORD && type != PIE) {
+            // awt.205=Invalid type of Arc: {0}
+            throw new IllegalArgumentException(Messages.getString("awt.205", type)); //$NON-NLS-1$
+        }
+        this.type = type;
+    }
+
+    /**
+     * Gets the start point of the arc as a Point2D.
+     * 
+     * @return the start point of the curved arc segment.
+     */
+    public Point2D getStartPoint() {
+        double a = Math.toRadians(getAngleStart());
+        return new Point2D.Double(getX() + (1.0 + Math.cos(a)) * getWidth() / 2.0, getY()
+                + (1.0 - Math.sin(a)) * getHeight() / 2.0);
+    }
+
+    /**
+     * Gets the end point of the arc as a Point2D.
+     * 
+     * @return the end point of the curved arc segment.
+     */
+    public Point2D getEndPoint() {
+        double a = Math.toRadians(getAngleStart() + getAngleExtent());
+        return new Point2D.Double(getX() + (1.0 + Math.cos(a)) * getWidth() / 2.0, getY()
+                + (1.0 - Math.sin(a)) * getHeight() / 2.0);
+    }
+
+    public Rectangle2D getBounds2D() {
+        if (isEmpty()) {
+            return makeBounds(getX(), getY(), getWidth(), getHeight());
+        }
+        double rx1 = getX();
+        double ry1 = getY();
+        double rx2 = rx1 + getWidth();
+        double ry2 = ry1 + getHeight();
+
+        Point2D p1 = getStartPoint();
+        Point2D p2 = getEndPoint();
+
+        double bx1 = containsAngle(180.0) ? rx1 : Math.min(p1.getX(), p2.getX());
+        double by1 = containsAngle(90.0) ? ry1 : Math.min(p1.getY(), p2.getY());
+        double bx2 = containsAngle(0.0) ? rx2 : Math.max(p1.getX(), p2.getX());
+        double by2 = containsAngle(270.0) ? ry2 : Math.max(p1.getY(), p2.getY());
+
+        if (type == PIE) {
+            double cx = getCenterX();
+            double cy = getCenterY();
+            bx1 = Math.min(bx1, cx);
+            by1 = Math.min(by1, cy);
+            bx2 = Math.max(bx2, cx);
+            by2 = Math.max(by2, cy);
+        }
+        return makeBounds(bx1, by1, bx2 - bx1, by2 - by1);
+    }
+
+    @Override
+    public void setFrame(double x, double y, double width, double height) {
+        setArc(x, y, width, height, getAngleStart(), getAngleExtent(), type);
+    }
+
+    /**
+     * Sets the data that defines the arc.
+     * 
+     * @param point
+     *            the upper left corner of the bounding rectangle.
+     * @param size
+     *            the size of the bounding rectangle.
+     * @param start
+     *            the start angle of the arc in degrees.
+     * @param extent
+     *            the angle width of the arc in degrees.
+     * @param type
+     *            the closure type, either {@link Arc2D#OPEN},
+     *            {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+     */
+    public void setArc(Point2D point, Dimension2D size, double start, double extent, int type) {
+        setArc(point.getX(), point.getY(), size.getWidth(), size.getHeight(), start, extent, type);
+    }
+
+    /**
+     * Sets the data that defines the arc.
+     * 
+     * @param rect
+     *            the arc's bounding rectangle.
+     * @param start
+     *            the start angle of the arc in degrees.
+     * @param extent
+     *            the angle width of the arc in degrees.
+     * @param type
+     *            the closure type, either {@link Arc2D#OPEN},
+     *            {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+     */
+    public void setArc(Rectangle2D rect, double start, double extent, int type) {
+        setArc(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), start, extent, type);
+    }
+
+    /**
+     * Sets the data that defines the arc by copying it from another Arc2D.
+     * 
+     * @param arc
+     *            the arc whose data is copied into this arc.
+     */
+    public void setArc(Arc2D arc) {
+        setArc(arc.getX(), arc.getY(), arc.getWidth(), arc.getHeight(), arc.getAngleStart(), arc
+                .getAngleExtent(), arc.getArcType());
+    }
+
+    /**
+     * Sets the data for a circular arc by giving its center and radius.
+     * 
+     * @param x
+     *            the x coordinate of the center of the circle.
+     * @param y
+     *            the y coordinate of the center of the circle.
+     * @param radius
+     *            the radius of the circle.
+     * @param start
+     *            the start angle of the arc in degrees.
+     * @param extent
+     *            the angle width of the arc in degrees.
+     * @param type
+     *            the closure type, either {@link Arc2D#OPEN},
+     *            {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+     */
+    public void setArcByCenter(double x, double y, double radius, double start, double extent,
+            int type) {
+        setArc(x - radius, y - radius, radius * 2.0, radius * 2.0, start, extent, type);
+    }
+
+    /**
+     * Sets the arc data for a circular arc based on two tangent lines and the
+     * radius. The two tangent lines are the lines from p1 to p2 and from p2 to
+     * p3, which determine a unique circle with the given radius. The start and
+     * end points of the arc are the points where the circle touches the two
+     * lines, and the arc itself is the shorter of the two circle segments
+     * determined by the two points (in other words, it is the piece of the
+     * circle that is closer to the lines' intersection point p2 and forms a
+     * concave shape with the segments from p1 to p2 and from p2 to p3).
+     * 
+     * @param p1
+     *            a point which determines one of the two tangent lines (with
+     *            p2).
+     * @param p2
+     *            the point of intersection of the two tangent lines.
+     * @param p3
+     *            a point which determines one of the two tangent lines (with
+     *            p2).
+     * @param radius
+     *            the radius of the circular arc.
+     */
+    public void setArcByTangent(Point2D p1, Point2D p2, Point2D p3, double radius) {
+        // Used simple geometric calculations of arc center, radius and angles
+        // by tangents
+        double a1 = -Math.atan2(p1.getY() - p2.getY(), p1.getX() - p2.getX());
+        double a2 = -Math.atan2(p3.getY() - p2.getY(), p3.getX() - p2.getX());
+        double am = (a1 + a2) / 2.0;
+        double ah = a1 - am;
+        double d = radius / Math.abs(Math.sin(ah));
+        double x = p2.getX() + d * Math.cos(am);
+        double y = p2.getY() - d * Math.sin(am);
+        ah = ah >= 0.0 ? Math.PI * 1.5 - ah : Math.PI * 0.5 - ah;
+        a1 = getNormAngle(Math.toDegrees(am - ah));
+        a2 = getNormAngle(Math.toDegrees(am + ah));
+        double delta = a2 - a1;
+        if (delta <= 0.0) {
+            delta += 360.0;
+        }
+        setArcByCenter(x, y, radius, a1, delta, type);
+    }
+
+    /**
+     * Sets a new start angle to be the angle given by the the vector from the
+     * current center point to the specified point.
+     * 
+     * @param point
+     *            the point that determines the new start angle.
+     */
+    public void setAngleStart(Point2D point) {
+        double angle = Math.atan2(point.getY() - getCenterY(), point.getX() - getCenterX());
+        setAngleStart(getNormAngle(-Math.toDegrees(angle)));
+    }
+
+    /**
+     * Sets the angles in terms of vectors from the current arc center to the
+     * points (x1, y1) and (x2, y2). The start angle is given by the vector from
+     * the current center to the point (x1, y1) and the end angle is given by
+     * the vector from the center to the point (x2, y2).
+     * 
+     * @param x1
+     *            the x coordinate of the point whose vector from the center
+     *            point determines the new start angle of the arc.
+     * @param y1
+     *            the y coordinate of the point whose vector from the center
+     *            point determines the new start angle of the arc.
+     * @param x2
+     *            the x coordinate of the point whose vector from the center
+     *            point determines the new end angle of the arc.
+     * @param y2
+     *            the y coordinate of the point whose vector from the center
+     *            point determines the new end angle of the arc.
+     */
+    public void setAngles(double x1, double y1, double x2, double y2) {
+        double cx = getCenterX();
+        double cy = getCenterY();
+        double a1 = getNormAngle(-Math.toDegrees(Math.atan2(y1 - cy, x1 - cx)));
+        double a2 = getNormAngle(-Math.toDegrees(Math.atan2(y2 - cy, x2 - cx)));
+        a2 -= a1;
+        if (a2 <= 0.0) {
+            a2 += 360.0;
+        }
+        setAngleStart(a1);
+        setAngleExtent(a2);
+    }
+
+    /**
+     * Sets the angles in terms of vectors from the current arc center to the
+     * points p1 and p2. The start angle is given by the vector from the current
+     * center to the point p1 and the end angle is given by the vector from the
+     * center to the point p2.
+     * 
+     * @param p1
+     *            the point whose vector from the center point determines the
+     *            new start angle of the arc.
+     * @param p2
+     *            the point whose vector from the center point determines the
+     *            new end angle of the arc.
+     */
+    public void setAngles(Point2D p1, Point2D p2) {
+        setAngles(p1.getX(), p1.getY(), p2.getX(), p2.getY());
+    }
+
+    /**
+     * Normalizes the angle by removing extra winding (past 360 degrees) and
+     * placing it in the positive degree range.
+     * 
+     * @param angle
+     *            the source angle in degrees.
+     * @return an angle between 0 and 360 degrees which corresponds to the same
+     *         direction vector as the source angle.
+     */
+    double getNormAngle(double angle) {
+        double n = Math.floor(angle / 360.0);
+        return angle - n * 360.0;
+    }
+
+    /**
+     * Determines whether the given angle is contained in the span of the arc.
+     * 
+     * @param angle
+     *            the angle to test in degrees.
+     * @return true, if the given angle is between the start angle and the end
+     *         angle of the arc.
+     */
+    public boolean containsAngle(double angle) {
+        double extent = getAngleExtent();
+        if (extent >= 360.0) {
+            return true;
+        }
+        angle = getNormAngle(angle);
+        double a1 = getNormAngle(getAngleStart());
+        double a2 = a1 + extent;
+        if (a2 > 360.0) {
+            return angle >= a1 || angle <= a2 - 360.0;
+        }
+        if (a2 < 0.0) {
+            return angle >= a2 + 360.0 || angle <= a1;
+        }
+        return extent > 0.0 ? a1 <= angle && angle <= a2 : a2 <= angle && angle <= a1;
+    }
+
+    public boolean contains(double px, double py) {
+        // Normalize point
+        double nx = (px - getX()) / getWidth() - 0.5;
+        double ny = (py - getY()) / getHeight() - 0.5;
+
+        if ((nx * nx + ny * ny) > 0.25) {
+            return false;
+        }
+
+        double extent = getAngleExtent();
+        double absExtent = Math.abs(extent);
+        if (absExtent >= 360.0) {
+            return true;
+        }
+
+        boolean containsAngle = containsAngle(Math.toDegrees(-Math.atan2(ny, nx)));
+        if (type == PIE) {
+            return containsAngle;
+        }
+        if (absExtent <= 180.0 && !containsAngle) {
+            return false;
+        }
+
+        Line2D l = new Line2D.Double(getStartPoint(), getEndPoint());
+        int ccw1 = l.relativeCCW(px, py);
+        int ccw2 = l.relativeCCW(getCenterX(), getCenterY());
+        return ccw1 == 0 || ccw2 == 0 || ((ccw1 + ccw2) == 0 ^ absExtent > 180.0);
+    }
+
+    public boolean contains(double rx, double ry, double rw, double rh) {
+
+        if (!(contains(rx, ry) && contains(rx + rw, ry) && contains(rx + rw, ry + rh) && contains(
+                rx, ry + rh))) {
+            return false;
+        }
+
+        double absExtent = Math.abs(getAngleExtent());
+        if (type != PIE || absExtent <= 180.0 || absExtent >= 360.0) {
+            return true;
+        }
+
+        Rectangle2D r = new Rectangle2D.Double(rx, ry, rw, rh);
+
+        double cx = getCenterX();
+        double cy = getCenterY();
+        if (r.contains(cx, cy)) {
+            return false;
+        }
+
+        Point2D p1 = getStartPoint();
+        Point2D p2 = getEndPoint();
+
+        return !r.intersectsLine(cx, cy, p1.getX(), p1.getY())
+                && !r.intersectsLine(cx, cy, p2.getX(), p2.getY());
+    }
+
+    @Override
+    public boolean contains(Rectangle2D rect) {
+        return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+    }
+
+    public boolean intersects(double rx, double ry, double rw, double rh) {
+
+        if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+            return false;
+        }
+
+        // Check: Does arc contain rectangle's points
+        if (contains(rx, ry) || contains(rx + rw, ry) || contains(rx, ry + rh)
+                || contains(rx + rw, ry + rh)) {
+            return true;
+        }
+
+        double cx = getCenterX();
+        double cy = getCenterY();
+        Point2D p1 = getStartPoint();
+        Point2D p2 = getEndPoint();
+        Rectangle2D r = new Rectangle2D.Double(rx, ry, rw, rh);
+
+        // Check: Does rectangle contain arc's points
+        if (r.contains(p1) || r.contains(p2) || (type == PIE && r.contains(cx, cy))) {
+            return true;
+        }
+
+        if (type == PIE) {
+            if (r.intersectsLine(p1.getX(), p1.getY(), cx, cy)
+                    || r.intersectsLine(p2.getX(), p2.getY(), cx, cy)) {
+                return true;
+            }
+        } else {
+            if (r.intersectsLine(p1.getX(), p1.getY(), p2.getX(), p2.getY())) {
+                return true;
+            }
+        }
+
+        // Nearest rectangle point
+        double nx = cx < rx ? rx : (cx > rx + rw ? rx + rw : cx);
+        double ny = cy < ry ? ry : (cy > ry + rh ? ry + rh : cy);
+        return contains(nx, ny);
+    }
+
+    public PathIterator getPathIterator(AffineTransform at) {
+        return new Iterator(this, at);
+    }
+
+}
diff --git a/awt/java/awt/geom/Area.java b/awt/java/awt/geom/Area.java
new file mode 100644
index 0000000..e6619e3
--- /dev/null
+++ b/awt/java/awt/geom/Area.java
@@ -0,0 +1,330 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Rectangle2D;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.luni.util.NotImplementedException;
+
+/**
+ * The Class Area provides a minimal implementation for a generic shape.
+ * 
+ * @since Android 1.0
+ */
+public class Area implements Shape, Cloneable {
+
+    /**
+     * The source Shape object.
+     */
+    Shape s;
+
+    /**
+     * The Class NullIterator.
+     */
+    private static class NullIterator implements PathIterator {
+
+        /**
+         * Instantiates a new null iterator.
+         */
+        NullIterator() {
+        }
+
+        public int getWindingRule() {
+            return WIND_NON_ZERO;
+        }
+
+        public boolean isDone() {
+            return true;
+        }
+
+        public void next() {
+            // nothing
+        }
+
+        public int currentSegment(double[] coords) {
+            // awt.4B=Iterator out of bounds
+            throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+        }
+
+        public int currentSegment(float[] coords) {
+            // awt.4B=Iterator out of bounds
+            throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+        }
+
+    }
+
+    /**
+     * Instantiates a new area with no data.
+     */
+    public Area() {
+    }
+
+    /**
+     * Instantiates a new area with data given by the specified shape.
+     * 
+     * @param s
+     *            the shape that gives the data for this Area.
+     */
+    public Area(Shape s) {
+        if (s == null) {
+            throw new NullPointerException();
+        }
+        this.s = s;
+    }
+
+    public boolean contains(double x, double y) {
+        return s == null ? false : s.contains(x, y);
+    }
+
+    public boolean contains(double x, double y, double width, double height) {
+        return s == null ? false : s.contains(x, y, width, height);
+    }
+
+    public boolean contains(Point2D p) {
+        if (p == null) {
+            throw new NullPointerException();
+        }
+        return s == null ? false : s.contains(p);
+    }
+
+    public boolean contains(Rectangle2D r) {
+        if (r == null) {
+            throw new NullPointerException();
+        }
+        return s == null ? false : s.contains(r);
+    }
+
+    /**
+     * Tests whether the object is equal to this Area.
+     * 
+     * @param obj
+     *            the object to compare.
+     * @return true, if successful.
+     * @throws NotImplementedException
+     *             if this method is not implemented.
+     */
+    public boolean equals(Area obj) throws org.apache.harmony.luni.util.NotImplementedException {
+        throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+    }
+
+    public boolean intersects(double x, double y, double width, double height) {
+        return s == null ? false : s.intersects(x, y, width, height);
+    }
+
+    public boolean intersects(Rectangle2D r) {
+        if (r == null) {
+            throw new NullPointerException();
+        }
+        return s == null ? false : s.intersects(r);
+    }
+
+    public Rectangle getBounds() {
+        return s == null ? new Rectangle() : s.getBounds();
+    }
+
+    public Rectangle2D getBounds2D() {
+        return s == null ? new Rectangle2D.Double() : s.getBounds2D();
+    }
+
+    public PathIterator getPathIterator(AffineTransform t) {
+        return s == null ? new NullIterator() : s.getPathIterator(t);
+    }
+
+    public PathIterator getPathIterator(AffineTransform t, double flatness) {
+        return s == null ? new NullIterator() : s.getPathIterator(t, flatness);
+    }
+
+    /**
+     * Adds the specified area to this area.
+     * 
+     * @param area
+     *            the area to add to this area.
+     * @throws NotImplementedException
+     *             if this method is not implemented.
+     */
+    public void add(Area area) throws org.apache.harmony.luni.util.NotImplementedException {
+        throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+    }
+
+    /**
+     * Performs an exclusive or operation between this shape and the specified
+     * shape.
+     * 
+     * @param area
+     *            the area to XOR against this area.
+     * @throws NotImplementedException
+     *             if this method is not implemented.
+     */
+    public void exclusiveOr(Area area) throws org.apache.harmony.luni.util.NotImplementedException {
+        throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+    }
+
+    /**
+     * Extracts a Rectangle2D from the source shape if the underlying shape data
+     * describes a rectangle.
+     * 
+     * @return a Rectangle2D object if the source shape is rectangle, or null if
+     *         shape is empty or not rectangle.
+     */
+    Rectangle2D extractRectangle() {
+        if (s == null) {
+            return null;
+        }
+        float[] points = new float[12];
+        int count = 0;
+        PathIterator p = s.getPathIterator(null);
+        float[] coords = new float[6];
+        while (!p.isDone()) {
+            int type = p.currentSegment(coords);
+            if (count > 12 || type == PathIterator.SEG_QUADTO || type == PathIterator.SEG_CUBICTO) {
+                return null;
+            }
+            points[count++] = coords[0];
+            points[count++] = coords[1];
+            p.next();
+        }
+        if (points[0] == points[6] && points[6] == points[8] && points[2] == points[4]
+                && points[1] == points[3] && points[3] == points[9] && points[5] == points[7]) {
+            return new Rectangle2D.Float(points[0], points[1], points[2] - points[0], points[7]
+                    - points[1]);
+        }
+        return null;
+    }
+
+    /**
+     * Reduces the size of this Area by intersecting it with the specified Area
+     * if they are both rectangles.
+     * 
+     * @see java.awt.geom.Rectangle2D#intersect(Rectangle2D, Rectangle2D,
+     *      Rectangle2D)
+     * @param area
+     *            the area.
+     */
+    public void intersect(Area area) {
+        Rectangle2D src1 = extractRectangle();
+        Rectangle2D src2 = area.extractRectangle();
+        if (src1 != null && src2 != null) {
+            Rectangle2D.intersect(src1, src2, (Rectangle2D)s);
+        }
+    }
+
+    /**
+     * Subtract the specified area from this area.
+     * 
+     * @param area
+     *            the area to subtract.
+     * @throws NotImplementedException
+     *             if this method is not implemented.
+     */
+    public void subtract(Area area) throws org.apache.harmony.luni.util.NotImplementedException {
+        throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+    }
+
+    /**
+     * Checks if this Area is empty.
+     * 
+     * @return true, if this Area is empty.
+     * @throws NotImplementedException
+     *             if this method is not implemented.
+     */
+    public boolean isEmpty() throws org.apache.harmony.luni.util.NotImplementedException {
+        throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+    }
+
+    /**
+     * Checks if this Area is polygonal.
+     * 
+     * @return true, if this Area is polygonal.
+     * @throws NotImplementedException
+     *             if this method is not implemented.
+     */
+    public boolean isPolygonal() throws org.apache.harmony.luni.util.NotImplementedException {
+        throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+    }
+
+    /**
+     * Checks if this Area is rectangular.
+     * 
+     * @return true, if this Area is rectangular.
+     * @throws NotImplementedException
+     *             if this method is not implemented.
+     */
+    public boolean isRectangular() throws org.apache.harmony.luni.util.NotImplementedException {
+        throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+    }
+
+    /**
+     * Checks if this Area is singular.
+     * 
+     * @return true, if this Area is singular.
+     * @throws NotImplementedException
+     *             if this method is not implemented.
+     */
+    public boolean isSingular() throws org.apache.harmony.luni.util.NotImplementedException {
+        throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+    }
+
+    /**
+     * Resets the data of this Area.
+     * 
+     * @throws NotImplementedException
+     *             if this method is not implemented.
+     */
+    public void reset() throws org.apache.harmony.luni.util.NotImplementedException {
+        throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+    }
+
+    /**
+     * Transforms the data of this Area according to the specified
+     * AffineTransform.
+     * 
+     * @param t
+     *            the transform to use to transform the data.
+     */
+    public void transform(AffineTransform t) {
+        s = t.createTransformedShape(s);
+    }
+
+    /**
+     * Creates a new Area that is the result of transforming the data of this
+     * Area according to the specified AffineTransform.
+     * 
+     * @param t
+     *            the transform to use to transform the data.
+     * @return the new Area that is the result of transforming the data of this
+     *         Area according to the specified AffineTransform.
+     */
+    public Area createTransformedArea(AffineTransform t) {
+        return s == null ? new Area() : new Area(t.createTransformedShape(s));
+    }
+
+    @Override
+    public Object clone() {
+        return new Area(this);
+    }
+
+}
diff --git a/awt/java/awt/geom/CubicCurve2D.java b/awt/java/awt/geom/CubicCurve2D.java
new file mode 100644
index 0000000..1ddedf3
--- /dev/null
+++ b/awt/java/awt/geom/CubicCurve2D.java
@@ -0,0 +1,1047 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.gl.Crossing;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class CubicCurve2D is a Shape that represents a segment of a quadratic
+ * (Bezier) curve. The curved segment is determined by four points: a start
+ * point, an end point, and two control points. The control points give
+ * information about the tangent and next derivative at the endpoints according
+ * to the standard theory of Bezier curves. For more information on Bezier
+ * curves, see <a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve">this
+ * article</a>.
+ * 
+ * @since Android 1.0
+ */
+public abstract class CubicCurve2D implements Shape, Cloneable {
+
+    /**
+     * The Class Float is the subclass of CubicCurve2D that has all of its data
+     * values stored with float-level precision.
+     * 
+     * @since Android 1.0
+     */
+    public static class Float extends CubicCurve2D {
+
+        /**
+         * The x coordinate of the starting point.
+         */
+        public float x1;
+
+        /**
+         * The y coordinate of the starting point.
+         */
+        public float y1;
+
+        /**
+         * The x coordinate of the first control point.
+         */
+        public float ctrlx1;
+
+        /**
+         * The y coordinate of the first control point.
+         */
+        public float ctrly1;
+
+        /**
+         * The x coordinate of the second control point.
+         */
+        public float ctrlx2;
+
+        /**
+         * The y coordinate of the second control point.
+         */
+        public float ctrly2;
+
+        /**
+         * The x coordinate of the end point.
+         */
+        public float x2;
+
+        /**
+         * The y coordinate of the end point.
+         */
+        public float y2;
+
+        /**
+         * Instantiates a new float-valued CubicCurve2D with all coordinate
+         * values set to zero.
+         */
+        public Float() {
+        }
+
+        /**
+         * Instantiates a new float-valued CubicCurve2D with the specified
+         * coordinate values.
+         * 
+         * @param x1
+         *            the x coordinate of the starting point.
+         * @param y1
+         *            the y coordinate of the starting point.
+         * @param ctrlx1
+         *            the x coordinate of the first control point.
+         * @param ctrly1
+         *            the y coordinate of the first control point.
+         * @param ctrlx2
+         *            the x coordinate of the second control point.
+         * @param ctrly2
+         *            the y coordinate of the second control point.
+         * @param x2
+         *            the x coordinate of the end point.
+         * @param y2
+         *            the y coordinate of the end point.
+         */
+        public Float(float x1, float y1, float ctrlx1, float ctrly1, float ctrlx2, float ctrly2,
+                float x2, float y2) {
+            setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
+        }
+
+        @Override
+        public double getX1() {
+            return x1;
+        }
+
+        @Override
+        public double getY1() {
+            return y1;
+        }
+
+        @Override
+        public double getCtrlX1() {
+            return ctrlx1;
+        }
+
+        @Override
+        public double getCtrlY1() {
+            return ctrly1;
+        }
+
+        @Override
+        public double getCtrlX2() {
+            return ctrlx2;
+        }
+
+        @Override
+        public double getCtrlY2() {
+            return ctrly2;
+        }
+
+        @Override
+        public double getX2() {
+            return x2;
+        }
+
+        @Override
+        public double getY2() {
+            return y2;
+        }
+
+        @Override
+        public Point2D getP1() {
+            return new Point2D.Float(x1, y1);
+        }
+
+        @Override
+        public Point2D getCtrlP1() {
+            return new Point2D.Float(ctrlx1, ctrly1);
+        }
+
+        @Override
+        public Point2D getCtrlP2() {
+            return new Point2D.Float(ctrlx2, ctrly2);
+        }
+
+        @Override
+        public Point2D getP2() {
+            return new Point2D.Float(x2, y2);
+        }
+
+        @Override
+        public void setCurve(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2,
+                double ctrly2, double x2, double y2) {
+            this.x1 = (float)x1;
+            this.y1 = (float)y1;
+            this.ctrlx1 = (float)ctrlx1;
+            this.ctrly1 = (float)ctrly1;
+            this.ctrlx2 = (float)ctrlx2;
+            this.ctrly2 = (float)ctrly2;
+            this.x2 = (float)x2;
+            this.y2 = (float)y2;
+        }
+
+        /**
+         * Sets the data values of the curve.
+         * 
+         * @param x1
+         *            the x coordinate of the starting point.
+         * @param y1
+         *            the y coordinate of the starting point.
+         * @param ctrlx1
+         *            the x coordinate of the first control point.
+         * @param ctrly1
+         *            the y coordinate of the first control point.
+         * @param ctrlx2
+         *            the x coordinate of the second control point.
+         * @param ctrly2
+         *            the y coordinate of the second control point.
+         * @param x2
+         *            the x coordinate of the end point.
+         * @param y2
+         *            the y coordinate of the end point.
+         */
+        public void setCurve(float x1, float y1, float ctrlx1, float ctrly1, float ctrlx2,
+                float ctrly2, float x2, float y2) {
+            this.x1 = x1;
+            this.y1 = y1;
+            this.ctrlx1 = ctrlx1;
+            this.ctrly1 = ctrly1;
+            this.ctrlx2 = ctrlx2;
+            this.ctrly2 = ctrly2;
+            this.x2 = x2;
+            this.y2 = y2;
+        }
+
+        public Rectangle2D getBounds2D() {
+            float rx1 = Math.min(Math.min(x1, x2), Math.min(ctrlx1, ctrlx2));
+            float ry1 = Math.min(Math.min(y1, y2), Math.min(ctrly1, ctrly2));
+            float rx2 = Math.max(Math.max(x1, x2), Math.max(ctrlx1, ctrlx2));
+            float ry2 = Math.max(Math.max(y1, y2), Math.max(ctrly1, ctrly2));
+            return new Rectangle2D.Float(rx1, ry1, rx2 - rx1, ry2 - ry1);
+        }
+    }
+
+    /**
+     * The Class Double is the subclass of CubicCurve2D that has all of its data
+     * values stored with double-level precision.
+     * 
+     * @since Android 1.0
+     */
+    public static class Double extends CubicCurve2D {
+
+        /**
+         * The x coordinate of the starting point.
+         */
+        public double x1;
+
+        /**
+         * The y coordinate of the starting point.
+         */
+        public double y1;
+
+        /**
+         * The x coordinate of the first control point.
+         */
+        public double ctrlx1;
+
+        /**
+         * The y coordinate of the first control point.
+         */
+        public double ctrly1;
+
+        /**
+         * The x coordinate of the second control point.
+         */
+        public double ctrlx2;
+
+        /**
+         * The y coordinate of the second control point.
+         */
+        public double ctrly2;
+
+        /**
+         * The x coordinate of the end point.
+         */
+        public double x2;
+
+        /**
+         * The y coordinate of the end point.
+         */
+        public double y2;
+
+        /**
+         * Instantiates a new double-valued CubicCurve2D with all coordinate
+         * values set to zero.
+         */
+        public Double() {
+        }
+
+        /**
+         * Instantiates a new double-valued CubicCurve2D with the specified
+         * coordinate values.
+         * 
+         * @param x1
+         *            the x coordinate of the starting point.
+         * @param y1
+         *            the y coordinate of the starting point.
+         * @param ctrlx1
+         *            the x coordinate of the first control point.
+         * @param ctrly1
+         *            the y coordinate of the first control point.
+         * @param ctrlx2
+         *            the x coordinate of the second control point.
+         * @param ctrly2
+         *            the y coordinate of the second control point.
+         * @param x2
+         *            the x coordinate of the end point.
+         * @param y2
+         *            the y coordinate of the end point.
+         */
+        public Double(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2,
+                double ctrly2, double x2, double y2) {
+            setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
+        }
+
+        @Override
+        public double getX1() {
+            return x1;
+        }
+
+        @Override
+        public double getY1() {
+            return y1;
+        }
+
+        @Override
+        public double getCtrlX1() {
+            return ctrlx1;
+        }
+
+        @Override
+        public double getCtrlY1() {
+            return ctrly1;
+        }
+
+        @Override
+        public double getCtrlX2() {
+            return ctrlx2;
+        }
+
+        @Override
+        public double getCtrlY2() {
+            return ctrly2;
+        }
+
+        @Override
+        public double getX2() {
+            return x2;
+        }
+
+        @Override
+        public double getY2() {
+            return y2;
+        }
+
+        @Override
+        public Point2D getP1() {
+            return new Point2D.Double(x1, y1);
+        }
+
+        @Override
+        public Point2D getCtrlP1() {
+            return new Point2D.Double(ctrlx1, ctrly1);
+        }
+
+        @Override
+        public Point2D getCtrlP2() {
+            return new Point2D.Double(ctrlx2, ctrly2);
+        }
+
+        @Override
+        public Point2D getP2() {
+            return new Point2D.Double(x2, y2);
+        }
+
+        @Override
+        public void setCurve(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2,
+                double ctrly2, double x2, double y2) {
+            this.x1 = x1;
+            this.y1 = y1;
+            this.ctrlx1 = ctrlx1;
+            this.ctrly1 = ctrly1;
+            this.ctrlx2 = ctrlx2;
+            this.ctrly2 = ctrly2;
+            this.x2 = x2;
+            this.y2 = y2;
+        }
+
+        public Rectangle2D getBounds2D() {
+            double rx1 = Math.min(Math.min(x1, x2), Math.min(ctrlx1, ctrlx2));
+            double ry1 = Math.min(Math.min(y1, y2), Math.min(ctrly1, ctrly2));
+            double rx2 = Math.max(Math.max(x1, x2), Math.max(ctrlx1, ctrlx2));
+            double ry2 = Math.max(Math.max(y1, y2), Math.max(ctrly1, ctrly2));
+            return new Rectangle2D.Double(rx1, ry1, rx2 - rx1, ry2 - ry1);
+        }
+    }
+
+    /*
+     * CubicCurve2D path iterator
+     */
+    /**
+     * The Iterator class for the Shape CubicCurve2D.
+     */
+    class Iterator implements PathIterator {
+
+        /**
+         * The source CubicCurve2D object.
+         */
+        CubicCurve2D c;
+
+        /**
+         * The path iterator transformation.
+         */
+        AffineTransform t;
+
+        /**
+         * The current segment index.
+         */
+        int index;
+
+        /**
+         * Constructs a new CubicCurve2D.Iterator for given line and
+         * transformation
+         * 
+         * @param c
+         *            the source CubicCurve2D object.
+         * @param t
+         *            the affine transformation object.
+         */
+        Iterator(CubicCurve2D c, AffineTransform t) {
+            this.c = c;
+            this.t = t;
+        }
+
+        public int getWindingRule() {
+            return WIND_NON_ZERO;
+        }
+
+        public boolean isDone() {
+            return index > 1;
+        }
+
+        public void next() {
+            index++;
+        }
+
+        public int currentSegment(double[] coords) {
+            if (isDone()) {
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            int type;
+            int count;
+            if (index == 0) {
+                type = SEG_MOVETO;
+                coords[0] = c.getX1();
+                coords[1] = c.getY1();
+                count = 1;
+            } else {
+                type = SEG_CUBICTO;
+                coords[0] = c.getCtrlX1();
+                coords[1] = c.getCtrlY1();
+                coords[2] = c.getCtrlX2();
+                coords[3] = c.getCtrlY2();
+                coords[4] = c.getX2();
+                coords[5] = c.getY2();
+                count = 3;
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, count);
+            }
+            return type;
+        }
+
+        public int currentSegment(float[] coords) {
+            if (isDone()) {
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            int type;
+            int count;
+            if (index == 0) {
+                type = SEG_MOVETO;
+                coords[0] = (float)c.getX1();
+                coords[1] = (float)c.getY1();
+                count = 1;
+            } else {
+                type = SEG_CUBICTO;
+                coords[0] = (float)c.getCtrlX1();
+                coords[1] = (float)c.getCtrlY1();
+                coords[2] = (float)c.getCtrlX2();
+                coords[3] = (float)c.getCtrlY2();
+                coords[4] = (float)c.getX2();
+                coords[5] = (float)c.getY2();
+                count = 3;
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, count);
+            }
+            return type;
+        }
+
+    }
+
+    /**
+     * Instantiates a new 2-D cubic curve.
+     */
+    protected CubicCurve2D() {
+    }
+
+    /**
+     * Gets the x coordinate of the starting point.
+     * 
+     * @return the x coordinate of the starting point.
+     */
+    public abstract double getX1();
+
+    /**
+     * Gets the y coordinate of the starting point.
+     * 
+     * @return the y coordinate of the starting point.
+     */
+    public abstract double getY1();
+
+    /**
+     * Gets the starting point.
+     * 
+     * @return the starting point.
+     */
+    public abstract Point2D getP1();
+
+    /**
+     * Gets the x coordinate of the first control point.
+     * 
+     * @return the x coordinate of the first control point.
+     */
+    public abstract double getCtrlX1();
+
+    /**
+     * Gets the y coordinate of the first control point.
+     * 
+     * @return the y coordinate of the first control point.
+     */
+    public abstract double getCtrlY1();
+
+    /**
+     * Gets the second control point.
+     * 
+     * @return the second control point.
+     */
+    public abstract Point2D getCtrlP1();
+
+    /**
+     * Gets the x coordinate of the second control point.
+     * 
+     * @return the x coordinate of the second control point
+     */
+    public abstract double getCtrlX2();
+
+    /**
+     * Gets the y coordinate of the second control point.
+     * 
+     * @return the y coordinate of the second control point
+     */
+    public abstract double getCtrlY2();
+
+    /**
+     * Gets the second control point.
+     * 
+     * @return the second control point.
+     */
+    public abstract Point2D getCtrlP2();
+
+    /**
+     * Gets the x coordinate of the end point.
+     * 
+     * @return the x coordinate of the end point.
+     */
+    public abstract double getX2();
+
+    /**
+     * Gets the y coordinate of the end point.
+     * 
+     * @return the y coordinate of the end point.
+     */
+    public abstract double getY2();
+
+    /**
+     * Gets the end point.
+     * 
+     * @return the end point.
+     */
+    public abstract Point2D getP2();
+
+    /**
+     * Sets the data of the curve.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point.
+     * @param y1
+     *            the y coordinate of the starting point.
+     * @param ctrlx1
+     *            the x coordinate of the first control point.
+     * @param ctrly1
+     *            the y coordinate of the first control point.
+     * @param ctrlx2
+     *            the x coordinate of the second control point.
+     * @param ctrly2
+     *            the y coordinate of the second control point.
+     * @param x2
+     *            the x coordinate of the end point.
+     * @param y2
+     *            the y coordinate of the end point.
+     */
+    public abstract void setCurve(double x1, double y1, double ctrlx1, double ctrly1,
+            double ctrlx2, double ctrly2, double x2, double y2);
+
+    /**
+     * Sets the data of the curve as point objects.
+     * 
+     * @param p1
+     *            the starting point.
+     * @param cp1
+     *            the first control point.
+     * @param cp2
+     *            the second control point.
+     * @param p2
+     *            the end point.
+     * @throws NullPointerException
+     *             if any of the points is null.
+     */
+    public void setCurve(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2) {
+        setCurve(p1.getX(), p1.getY(), cp1.getX(), cp1.getY(), cp2.getX(), cp2.getY(), p2.getX(),
+                p2.getY());
+    }
+
+    /**
+     * Sets the data of the curve by reading the data from an array of values.
+     * The values are read in the same order as the arguments of the method
+     * {@link CubicCurve2D#setCurve(double, double, double, double, double, double, double, double)}
+     * .
+     * 
+     * @param coords
+     *            the array of values containing the new coordinates.
+     * @param offset
+     *            the offset of the data to read within the array.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if {@code coords.length} < offset + 8.
+     * @throws NullPointerException
+     *             if the coordinate array is null.
+     */
+    public void setCurve(double[] coords, int offset) {
+        setCurve(coords[offset + 0], coords[offset + 1], coords[offset + 2], coords[offset + 3],
+                coords[offset + 4], coords[offset + 5], coords[offset + 6], coords[offset + 7]);
+    }
+
+    /**
+     * Sets the data of the curve by reading the data from an array of points.
+     * The values are read in the same order as the arguments of the method
+     * {@link CubicCurve2D#setCurve(Point2D, Point2D, Point2D, Point2D)}
+     * 
+     * @param points
+     *            the array of points containing the new coordinates.
+     * @param offset
+     *            the offset of the data to read within the array.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if {@code points.length} < offset + .
+     * @throws NullPointerException
+     *             if the point array is null.
+     */
+    public void setCurve(Point2D[] points, int offset) {
+        setCurve(points[offset + 0].getX(), points[offset + 0].getY(), points[offset + 1].getX(),
+                points[offset + 1].getY(), points[offset + 2].getX(), points[offset + 2].getY(),
+                points[offset + 3].getX(), points[offset + 3].getY());
+    }
+
+    /**
+     * Sets the data of the curve by copying it from another CubicCurve2D.
+     * 
+     * @param curve
+     *            the curve to copy the data points from.
+     * @throws NullPointerException
+     *             if the curve is null.
+     */
+    public void setCurve(CubicCurve2D curve) {
+        setCurve(curve.getX1(), curve.getY1(), curve.getCtrlX1(), curve.getCtrlY1(), curve
+                .getCtrlX2(), curve.getCtrlY2(), curve.getX2(), curve.getY2());
+    }
+
+    /**
+     * Gets the square of the flatness of this curve, where the flatness is the
+     * maximum distance from the curves control points to the line segment
+     * connecting the two points.
+     * 
+     * @return the square of the flatness.
+     */
+    public double getFlatnessSq() {
+        return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(), getCtrlX2(), getCtrlY2(),
+                getX2(), getY2());
+    }
+
+    /**
+     * Gets the square of the flatness of the cubic curve segment defined by the
+     * specified values.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point.
+     * @param y1
+     *            the y coordinate of the starting point.
+     * @param ctrlx1
+     *            the x coordinate of the first control point.
+     * @param ctrly1
+     *            the y coordinate of the first control point.
+     * @param ctrlx2
+     *            the x coordinate of the second control point.
+     * @param ctrly2
+     *            the y coordinate of the second control point.
+     * @param x2
+     *            the x coordinate of the end point.
+     * @param y2
+     *            the y coordinate of the end point.
+     * @return the square of the flatness.
+     */
+    public static double getFlatnessSq(double x1, double y1, double ctrlx1, double ctrly1,
+            double ctrlx2, double ctrly2, double x2, double y2) {
+        return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx1, ctrly1), Line2D.ptSegDistSq(x1,
+                y1, x2, y2, ctrlx2, ctrly2));
+    }
+
+    /**
+     * Gets the square of the flatness of the cubic curve segment defined by the
+     * specified values. The values are read in the same order as the arguments
+     * of the method
+     * {@link CubicCurve2D#getFlatnessSq(double, double, double, double, double, double, double, double)}
+     * .
+     * 
+     * @param coords
+     *            the array of points containing the new coordinates.
+     * @param offset
+     *            the offset of the data to read within the array.
+     * @return the square of the flatness.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if points.length < offset + .
+     * @throws NullPointerException
+     *             if the point array is null.
+     */
+    public static double getFlatnessSq(double coords[], int offset) {
+        return getFlatnessSq(coords[offset + 0], coords[offset + 1], coords[offset + 2],
+                coords[offset + 3], coords[offset + 4], coords[offset + 5], coords[offset + 6],
+                coords[offset + 7]);
+    }
+
+    /**
+     * Gets the flatness of this curve, where the flatness is the maximum
+     * distance from the curves control points to the line segment connecting
+     * the two points.
+     * 
+     * @return the flatness of this curve.
+     */
+    public double getFlatness() {
+        return getFlatness(getX1(), getY1(), getCtrlX1(), getCtrlY1(), getCtrlX2(), getCtrlY2(),
+                getX2(), getY2());
+    }
+
+    /**
+     * Gets the flatness of the cubic curve segment defined by the specified
+     * values.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point.
+     * @param y1
+     *            the y coordinate of the starting point.
+     * @param ctrlx1
+     *            the x coordinate of the first control point.
+     * @param ctrly1
+     *            the y coordinate of the first control point.
+     * @param ctrlx2
+     *            the x coordinate of the second control point.
+     * @param ctrly2
+     *            the y coordinate of the second control point.
+     * @param x2
+     *            the x coordinate of the end point.
+     * @param y2
+     *            the y coordinate of the end point.
+     * @return the flatness.
+     */
+    public static double getFlatness(double x1, double y1, double ctrlx1, double ctrly1,
+            double ctrlx2, double ctrly2, double x2, double y2) {
+        return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2));
+    }
+
+    /**
+     * Gets the flatness of the cubic curve segment defined by the specified
+     * values. The values are read in the same order as the arguments of the
+     * method
+     * {@link CubicCurve2D#getFlatness(double, double, double, double, double, double, double, double)}
+     * .
+     * 
+     * @param coords
+     *            the array of points containing the new coordinates.
+     * @param offset
+     *            the offset of the data to read within the array.
+     * @return the flatness.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if points.length < offset + .
+     * @throws NullPointerException
+     *             if the point array is null.
+     */
+    public static double getFlatness(double coords[], int offset) {
+        return getFlatness(coords[offset + 0], coords[offset + 1], coords[offset + 2],
+                coords[offset + 3], coords[offset + 4], coords[offset + 5], coords[offset + 6],
+                coords[offset + 7]);
+    }
+
+    /**
+     * Creates the data for two cubic curves by dividing this curve in two. The
+     * division point is the point on the curve that is closest to the average
+     * of curve's two control points. The two new control points (nearest the
+     * new endpoint) are computed by averaging the original control points with
+     * the new endpoint. The data of this curve is left unchanged.
+     * 
+     * @param left
+     *            the CubicCurve2D where the left (start) segment's data is
+     *            written.
+     * @param right
+     *            the CubicCurve2D where the right (end) segment's data is
+     *            written.
+     * @throws NullPointerException
+     *             if either curve is null.
+     */
+    public void subdivide(CubicCurve2D left, CubicCurve2D right) {
+        subdivide(this, left, right);
+    }
+
+    /**
+     * Creates the data for two cubic curves by dividing the specified curve in
+     * two. The division point is the point on the curve that is closest to the
+     * average of curve's two control points. The two new control points
+     * (nearest the new endpoint) are computed by averaging the original control
+     * points with the new endpoint. The data of the source curve is left
+     * unchanged.
+     * 
+     * @param src
+     *            the original curve to be divided in two.
+     * @param left
+     *            the CubicCurve2D where the left (start) segment's data is
+     *            written.
+     * @param right
+     *            the CubicCurve2D where the right (end) segment's data is
+     *            written.
+     * @throws NullPointerException
+     *             if either curve is null.
+     */
+    public static void subdivide(CubicCurve2D src, CubicCurve2D left, CubicCurve2D right) {
+        double x1 = src.getX1();
+        double y1 = src.getY1();
+        double cx1 = src.getCtrlX1();
+        double cy1 = src.getCtrlY1();
+        double cx2 = src.getCtrlX2();
+        double cy2 = src.getCtrlY2();
+        double x2 = src.getX2();
+        double y2 = src.getY2();
+        double cx = (cx1 + cx2) / 2.0;
+        double cy = (cy1 + cy2) / 2.0;
+        cx1 = (x1 + cx1) / 2.0;
+        cy1 = (y1 + cy1) / 2.0;
+        cx2 = (x2 + cx2) / 2.0;
+        cy2 = (y2 + cy2) / 2.0;
+        double ax = (cx1 + cx) / 2.0;
+        double ay = (cy1 + cy) / 2.0;
+        double bx = (cx2 + cx) / 2.0;
+        double by = (cy2 + cy) / 2.0;
+        cx = (ax + bx) / 2.0;
+        cy = (ay + by) / 2.0;
+        if (left != null) {
+            left.setCurve(x1, y1, cx1, cy1, ax, ay, cx, cy);
+        }
+        if (right != null) {
+            right.setCurve(cx, cy, bx, by, cx2, cy2, x2, y2);
+        }
+    }
+
+    /**
+     * Creates the data for two cubic curves by dividing the specified curve in
+     * two. The division point is the point on the curve that is closest to the
+     * average of curve's two control points. The two new control points
+     * (nearest the new endpoint) are computed by averaging the original control
+     * points with the new endpoint. The data of the source curve is left
+     * unchanged. The data for the three curves is read/written in the usual
+     * order: { x1, y1, ctrlx1, ctrly1, ctrlx2, crtry2, x2, y3 }
+     * 
+     * @param src
+     *            the array that gives the data values for the source curve.
+     * @param srcOff
+     *            the offset in the src array to read the values from.
+     * @param left
+     *            the array where the coordinates of the start curve should be
+     *            written.
+     * @param leftOff
+     *            the offset in the left array to start writing the values.
+     * @param right
+     *            the array where the coordinates of the end curve should be
+     *            written.
+     * @param rightOff
+     *            the offset in the right array to start writing the values.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if src.length < srcoff + 8 or if left.length < leftOff + 8 or
+     *             if right.length < rightOff + 8.
+     * @throws NullPointerException
+     *             if one of the arrays is null.
+     */
+    public static void subdivide(double src[], int srcOff, double left[], int leftOff,
+            double right[], int rightOff) {
+        double x1 = src[srcOff + 0];
+        double y1 = src[srcOff + 1];
+        double cx1 = src[srcOff + 2];
+        double cy1 = src[srcOff + 3];
+        double cx2 = src[srcOff + 4];
+        double cy2 = src[srcOff + 5];
+        double x2 = src[srcOff + 6];
+        double y2 = src[srcOff + 7];
+        double cx = (cx1 + cx2) / 2.0;
+        double cy = (cy1 + cy2) / 2.0;
+        cx1 = (x1 + cx1) / 2.0;
+        cy1 = (y1 + cy1) / 2.0;
+        cx2 = (x2 + cx2) / 2.0;
+        cy2 = (y2 + cy2) / 2.0;
+        double ax = (cx1 + cx) / 2.0;
+        double ay = (cy1 + cy) / 2.0;
+        double bx = (cx2 + cx) / 2.0;
+        double by = (cy2 + cy) / 2.0;
+        cx = (ax + bx) / 2.0;
+        cy = (ay + by) / 2.0;
+        if (left != null) {
+            left[leftOff + 0] = x1;
+            left[leftOff + 1] = y1;
+            left[leftOff + 2] = cx1;
+            left[leftOff + 3] = cy1;
+            left[leftOff + 4] = ax;
+            left[leftOff + 5] = ay;
+            left[leftOff + 6] = cx;
+            left[leftOff + 7] = cy;
+        }
+        if (right != null) {
+            right[rightOff + 0] = cx;
+            right[rightOff + 1] = cy;
+            right[rightOff + 2] = bx;
+            right[rightOff + 3] = by;
+            right[rightOff + 4] = cx2;
+            right[rightOff + 5] = cy2;
+            right[rightOff + 6] = x2;
+            right[rightOff + 7] = y2;
+        }
+    }
+
+    /**
+     * Finds the roots of the cubic polynomial. This is accomplished by finding
+     * the (real) values of x that solve the following equation: eqn[3]*x*x*x +
+     * eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. The solutions are written back into
+     * the array eqn starting from the index 0 in the array. The return value
+     * tells how many array elements have been changed by this method call.
+     * 
+     * @param eqn
+     *            an array containing the coefficients of the cubic polynomial
+     *            to solve.
+     * @return the number of roots of the cubic polynomial.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if eqn.length < 4.
+     * @throws NullPointerException
+     *             if the array is null.
+     */
+    public static int solveCubic(double eqn[]) {
+        return solveCubic(eqn, eqn);
+    }
+
+    /**
+     * Finds the roots of the cubic polynomial. This is accomplished by finding
+     * the (real) values of x that solve the following equation: eqn[3]*x*x*x +
+     * eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. The solutions are written into the
+     * array res starting from the index 0 in the array. The return value tells
+     * how many array elements have been changed by this method call.
+     * 
+     * @param eqn
+     *            an array containing the coefficients of the cubic polynomial
+     *            to solve.
+     * @param res
+     *            the array that this method writes the results into.
+     * @return the number of roots of the cubic polynomial.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if eqn.length < 4 or if res.length is less than the number of
+     *             roots.
+     * @throws NullPointerException
+     *             if either array is null.
+     */
+    public static int solveCubic(double eqn[], double res[]) {
+        return Crossing.solveCubic(eqn, res);
+    }
+
+    public boolean contains(double px, double py) {
+        return Crossing.isInsideEvenOdd(Crossing.crossShape(this, px, py));
+    }
+
+    public boolean contains(double rx, double ry, double rw, double rh) {
+        int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+        return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross);
+    }
+
+    public boolean intersects(double rx, double ry, double rw, double rh) {
+        int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+        return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross);
+    }
+
+    public boolean contains(Point2D p) {
+        return contains(p.getX(), p.getY());
+    }
+
+    public boolean intersects(Rectangle2D r) {
+        return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+    }
+
+    public boolean contains(Rectangle2D r) {
+        return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+    }
+
+    public Rectangle getBounds() {
+        return getBounds2D().getBounds();
+    }
+
+    public PathIterator getPathIterator(AffineTransform t) {
+        return new Iterator(this, t);
+    }
+
+    public PathIterator getPathIterator(AffineTransform at, double flatness) {
+        return new FlatteningPathIterator(getPathIterator(at), flatness);
+    }
+
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+}
\ No newline at end of file
diff --git a/awt/java/awt/geom/Dimension2D.java b/awt/java/awt/geom/Dimension2D.java
new file mode 100644
index 0000000..ea081c5
--- /dev/null
+++ b/awt/java/awt/geom/Dimension2D.java
@@ -0,0 +1,83 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+/**
+ * The Class Dimension2D represents a size (width and height) of a geometric
+ * object. It stores double-valued data in order to be compatible with
+ * high-precision geometric operations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class Dimension2D implements Cloneable {
+
+    /**
+     * Instantiates a new dimension 2d with no data.
+     */
+    protected Dimension2D() {
+    }
+
+    /**
+     * Gets the width.
+     * 
+     * @return the width.
+     */
+    public abstract double getWidth();
+
+    /**
+     * Gets the height.
+     * 
+     * @return the height.
+     */
+    public abstract double getHeight();
+
+    /**
+     * Sets the width and height.
+     * 
+     * @param width
+     *            the width.
+     * @param height
+     *            the height.
+     */
+    public abstract void setSize(double width, double height);
+
+    /**
+     * Sets the width and height based on the data of another Dimension2D
+     * object.
+     * 
+     * @param d
+     *            the Dimension2D object providing the data to copy into this
+     *            Dimension2D object.
+     */
+    public void setSize(Dimension2D d) {
+        setSize(d.getWidth(), d.getHeight());
+    }
+
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+}
diff --git a/awt/java/awt/geom/Ellipse2D.java b/awt/java/awt/geom/Ellipse2D.java
new file mode 100644
index 0000000..89fd0d0
--- /dev/null
+++ b/awt/java/awt/geom/Ellipse2D.java
@@ -0,0 +1,458 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class Ellipse2D describes an ellipse defined by a rectangular area in
+ * which it is inscribed.
+ * 
+ * @since Android 1.0
+ */
+public abstract class Ellipse2D extends RectangularShape {
+
+    /**
+     * The Class Float is the subclass of Ellipse2D that has all of its data
+     * values stored with float-level precision.
+     * 
+     * @since Android 1.0
+     */
+    public static class Float extends Ellipse2D {
+
+        /**
+         * The x coordinate of the upper left corner of the ellipse's bounding
+         * rectangle.
+         */
+        public float x;
+
+        /**
+         * The y coordinate of the upper left corner of the ellipse's bounding
+         * rectangle.
+         */
+        public float y;
+
+        /**
+         * The width of the ellipse's bounding rectangle.
+         */
+        public float width;
+
+        /**
+         * The height of the ellipse's bounding rectangle.
+         */
+        public float height;
+
+        /**
+         * Instantiates a new float-valued Ellipse2D.
+         */
+        public Float() {
+        }
+
+        /**
+         * Instantiates a new float-valued Ellipse2D with the specified data.
+         * 
+         * @param x
+         *            the x coordinate of the upper left corner of the ellipse's
+         *            bounding rectangle.
+         * @param y
+         *            the y coordinate of the upper left corner of the ellipse's
+         *            bounding rectangle.
+         * @param width
+         *            the width of the ellipse's bounding rectangle.
+         * @param height
+         *            the height of the ellipse's bounding rectangle.
+         */
+        public Float(float x, float y, float width, float height) {
+            setFrame(x, y, width, height);
+        }
+
+        @Override
+        public double getX() {
+            return x;
+        }
+
+        @Override
+        public double getY() {
+            return y;
+        }
+
+        @Override
+        public double getWidth() {
+            return width;
+        }
+
+        @Override
+        public double getHeight() {
+            return height;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return width <= 0.0 || height <= 0.0;
+        }
+
+        /**
+         * Sets the data of the ellipse's bounding rectangle.
+         * 
+         * @param x
+         *            the x coordinate of the upper left corner of the ellipse's
+         *            bounding rectangle.
+         * @param y
+         *            the y coordinate of the upper left corner of the ellipse's
+         *            bounding rectangle.
+         * @param width
+         *            the width of the ellipse's bounding rectangle.
+         * @param height
+         *            the height of the ellipse's bounding rectangle.
+         */
+        public void setFrame(float x, float y, float width, float height) {
+            this.x = x;
+            this.y = y;
+            this.width = width;
+            this.height = height;
+        }
+
+        @Override
+        public void setFrame(double x, double y, double width, double height) {
+            this.x = (float)x;
+            this.y = (float)y;
+            this.width = (float)width;
+            this.height = (float)height;
+        }
+
+        public Rectangle2D getBounds2D() {
+            return new Rectangle2D.Float(x, y, width, height);
+        }
+    }
+
+    /**
+     * The Class Double is the subclass of Ellipse2D that has all of its data
+     * values stored with double-level precision.
+     * 
+     * @since Android 1.0
+     */
+    public static class Double extends Ellipse2D {
+
+        /**
+         * The x coordinate of the upper left corner of the ellipse's bounding
+         * rectangle.
+         */
+        public double x;
+
+        /**
+         * The y coordinate of the upper left corner of the ellipse's bounding
+         * rectangle.
+         */
+        public double y;
+
+        /**
+         * The width of the ellipse's bounding rectangle.
+         */
+        public double width;
+
+        /**
+         * The height of the ellipse's bounding rectangle.
+         */
+        public double height;
+
+        /**
+         * Instantiates a new double-valued Ellipse2D.
+         */
+        public Double() {
+        }
+
+        /**
+         * Instantiates a new double-valued Ellipse2D with the specified data.
+         * 
+         * @param x
+         *            the x coordinate of the upper left corner of the ellipse's
+         *            bounding rectangle.
+         * @param y
+         *            the y coordinate of the upper left corner of the ellipse's
+         *            bounding rectangle.
+         * @param width
+         *            the width of the ellipse's bounding rectangle.
+         * @param height
+         *            the height of the ellipse's bounding rectangle.
+         */
+        public Double(double x, double y, double width, double height) {
+            setFrame(x, y, width, height);
+        }
+
+        @Override
+        public double getX() {
+            return x;
+        }
+
+        @Override
+        public double getY() {
+            return y;
+        }
+
+        @Override
+        public double getWidth() {
+            return width;
+        }
+
+        @Override
+        public double getHeight() {
+            return height;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return width <= 0.0 || height <= 0.0;
+        }
+
+        @Override
+        public void setFrame(double x, double y, double width, double height) {
+            this.x = x;
+            this.y = y;
+            this.width = width;
+            this.height = height;
+        }
+
+        public Rectangle2D getBounds2D() {
+            return new Rectangle2D.Double(x, y, width, height);
+        }
+    }
+
+    /*
+     * Ellipse2D path iterator
+     */
+    /**
+     * The subclass of PathIterator to traverse an Ellipse2D.
+     */
+    class Iterator implements PathIterator {
+
+        /*
+         * Ellipse is subdivided into four quarters by x and y axis. Each part
+         * approximated by cubic Bezier curve. Arc in first quarter is started
+         * in (a, 0) and finished in (0, b) points. Control points for cubic
+         * curve wiil be (a, 0), (a, m), (n, b) and (0, b) where n and m are
+         * calculated based on requirement Bezier curve in point 0.5 should lay
+         * on the arc.
+         */
+
+        /**
+         * The coefficient to calculate control points of Bezier curves.
+         */
+        final double u = 2.0 / 3.0 * (Math.sqrt(2.0) - 1.0);
+
+        /**
+         * The points coordinates calculation table.
+         */
+        final double points[][] = {
+                {
+                        1.0, 0.5 + u, 0.5 + u, 1.0, 0.5, 1.0
+                }, {
+                        0.5 - u, 1.0, 0.0, 0.5 + u, 0.0, 0.5
+                }, {
+                        0.0, 0.5 - u, 0.5 - u, 0.0, 0.5, 0.0
+                }, {
+                        0.5 + u, 0.0, 1.0, 0.5 - u, 1.0, 0.5
+                }
+        };
+
+        /**
+         * The x coordinate of left-upper corner of the ellipse bounds.
+         */
+        double x;
+
+        /**
+         * The y coordinate of left-upper corner of the ellipse bounds.
+         */
+        double y;
+
+        /**
+         * The width of the ellipse bounds.
+         */
+        double width;
+
+        /**
+         * The height of the ellipse bounds.
+         */
+        double height;
+
+        /**
+         * The path iterator transformation.
+         */
+        AffineTransform t;
+
+        /**
+         * The current segment index.
+         */
+        int index;
+
+        /**
+         * Constructs a new Ellipse2D.Iterator for given ellipse and
+         * transformation
+         * 
+         * @param e
+         *            the source Ellipse2D object.
+         * @param t
+         *            the affine transformation object.
+         */
+        Iterator(Ellipse2D e, AffineTransform t) {
+            this.x = e.getX();
+            this.y = e.getY();
+            this.width = e.getWidth();
+            this.height = e.getHeight();
+            this.t = t;
+            if (width < 0.0 || height < 0.0) {
+                index = 6;
+            }
+        }
+
+        public int getWindingRule() {
+            return WIND_NON_ZERO;
+        }
+
+        public boolean isDone() {
+            return index > 5;
+        }
+
+        public void next() {
+            index++;
+        }
+
+        public int currentSegment(double[] coords) {
+            if (isDone()) {
+                // awt.4B=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            if (index == 5) {
+                return SEG_CLOSE;
+            }
+            int type;
+            int count;
+            if (index == 0) {
+                type = SEG_MOVETO;
+                count = 1;
+                double p[] = points[3];
+                coords[0] = x + p[4] * width;
+                coords[1] = y + p[5] * height;
+            } else {
+                type = SEG_CUBICTO;
+                count = 3;
+                double p[] = points[index - 1];
+                int j = 0;
+                for (int i = 0; i < 3; i++) {
+                    coords[j] = x + p[j++] * width;
+                    coords[j] = y + p[j++] * height;
+                }
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, count);
+            }
+            return type;
+        }
+
+        public int currentSegment(float[] coords) {
+            if (isDone()) {
+                // awt.4B=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            if (index == 5) {
+                return SEG_CLOSE;
+            }
+            int type;
+            int count;
+            if (index == 0) {
+                type = SEG_MOVETO;
+                count = 1;
+                double p[] = points[3];
+                coords[0] = (float)(x + p[4] * width);
+                coords[1] = (float)(y + p[5] * height);
+            } else {
+                type = SEG_CUBICTO;
+                count = 3;
+                int j = 0;
+                double p[] = points[index - 1];
+                for (int i = 0; i < 3; i++) {
+                    coords[j] = (float)(x + p[j++] * width);
+                    coords[j] = (float)(y + p[j++] * height);
+                }
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, count);
+            }
+            return type;
+        }
+
+    }
+
+    /**
+     * Instantiates a new Ellipse2D.
+     */
+    protected Ellipse2D() {
+    }
+
+    public boolean contains(double px, double py) {
+        if (isEmpty()) {
+            return false;
+        }
+
+        double a = (px - getX()) / getWidth() - 0.5;
+        double b = (py - getY()) / getHeight() - 0.5;
+
+        return a * a + b * b < 0.25;
+    }
+
+    public boolean intersects(double rx, double ry, double rw, double rh) {
+        if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+            return false;
+        }
+
+        double cx = getX() + getWidth() / 2.0;
+        double cy = getY() + getHeight() / 2.0;
+
+        double rx1 = rx;
+        double ry1 = ry;
+        double rx2 = rx + rw;
+        double ry2 = ry + rh;
+
+        double nx = cx < rx1 ? rx1 : (cx > rx2 ? rx2 : cx);
+        double ny = cy < ry1 ? ry1 : (cy > ry2 ? ry2 : cy);
+
+        return contains(nx, ny);
+    }
+
+    public boolean contains(double rx, double ry, double rw, double rh) {
+        if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+            return false;
+        }
+
+        double rx1 = rx;
+        double ry1 = ry;
+        double rx2 = rx + rw;
+        double ry2 = ry + rh;
+
+        return contains(rx1, ry1) && contains(rx2, ry1) && contains(rx2, ry2) && contains(rx1, ry2);
+    }
+
+    public PathIterator getPathIterator(AffineTransform at) {
+        return new Iterator(this, at);
+    }
+}
diff --git a/awt/java/awt/geom/FlatteningPathIterator.java b/awt/java/awt/geom/FlatteningPathIterator.java
new file mode 100644
index 0000000..8208f39
--- /dev/null
+++ b/awt/java/awt/geom/FlatteningPathIterator.java
@@ -0,0 +1,358 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class FlatteningPathIterator takes a PathIterator for traversing a curved
+ * shape and flattens it by estimating the curve as a series of line segments.
+ * The flattening factor indicates how far the estimating line segments are
+ * allowed to be from the actual curve: the FlatteningPathIterator will keep
+ * dividing each curved segment into smaller and smaller flat segments until
+ * either the segments are within the flattening factor of the curve or until
+ * the buffer limit is reached.
+ * 
+ * @since Android 1.0
+ */
+public class FlatteningPathIterator implements PathIterator {
+
+    /**
+     * The default points buffer size.
+     */
+    private static final int BUFFER_SIZE = 16;
+
+    /**
+     * The default curve subdivision limit.
+     */
+    private static final int BUFFER_LIMIT = 16;
+
+    /**
+     * The points buffer capacity.
+     */
+    private static final int BUFFER_CAPACITY = 16;
+
+    /**
+     * The type of current segment to be flat.
+     */
+    int bufType;
+
+    /**
+     * The curve subdivision limit.
+     */
+    int bufLimit;
+
+    /**
+     * The current points buffer size.
+     */
+    int bufSize;
+
+    /**
+     * The inner cursor position in points buffer.
+     */
+    int bufIndex;
+
+    /**
+     * The current subdivision count.
+     */
+    int bufSubdiv;
+
+    /**
+     * The points buffer.
+     */
+    double buf[];
+
+    /**
+     * The indicator of empty points buffer.
+     */
+    boolean bufEmpty = true;
+
+    /**
+     * The source PathIterator.
+     */
+    PathIterator p;
+
+    /**
+     * The flatness of new path.
+     */
+    double flatness;
+
+    /**
+     * The square of flatness.
+     */
+    double flatness2;
+
+    /**
+     * The x coordinate of previous path segment.
+     */
+    double px;
+
+    /**
+     * The y coordinate of previous path segment.
+     */
+    double py;
+
+    /**
+     * The temporary buffer for getting points from PathIterator.
+     */
+    double coords[] = new double[6];
+
+    /**
+     * Instantiates a new flattening path iterator given the path iterator for a
+     * (possibly) curved path and a flattening factor which indicates how close
+     * together the points on the curve should be chosen. The buffer limit
+     * defaults to 16 which means that each curve will be divided into no more
+     * than 16 segments regardless of the flattening factor.
+     * 
+     * @param path
+     *            the path iterator of the original curve.
+     * @param flatness
+     *            the flattening factor that indicates how far the flat path is
+     *            allowed to be from the actual curve in order to decide when to
+     *            stop dividing the path into smaller and smaller segments.
+     * @throws IllegalArgumentException
+     *             if the flatness is less than zero.
+     * @throws NullPointerException
+     *             if the path is null.
+     */
+    public FlatteningPathIterator(PathIterator path, double flatness) {
+        this(path, flatness, BUFFER_LIMIT);
+    }
+
+    /**
+     * Instantiates a new flattening path iterator given the path iterator for a
+     * (possibly) curved path and a flattening factor and a buffer limit. The
+     * FlatteningPathIterator will keep dividing each curved segment into
+     * smaller and smaller flat segments until either the segments are within
+     * the flattening factor of the curve or until the buffer limit is reached.
+     * 
+     * @param path
+     *            the path iterator of the original curve.
+     * @param flatness
+     *            the flattening factor that indicates how far the flat path is
+     *            allowed to be from the actual curve in order to decide when to
+     *            stop dividing the path into smaller and smaller segments.
+     * @param limit
+     *            the maximum number of flat segments to divide each curve into.
+     * @throws IllegalArgumentException
+     *             if the flatness or limit is less than zero.
+     * @throws NullPointerException
+     *             if the path is null.
+     */
+    public FlatteningPathIterator(PathIterator path, double flatness, int limit) {
+        if (flatness < 0.0) {
+            // awt.206=Flatness is less then zero
+            throw new IllegalArgumentException(Messages.getString("awt.206")); //$NON-NLS-1$
+        }
+        if (limit < 0) {
+            // awt.207=Limit is less then zero
+            throw new IllegalArgumentException(Messages.getString("awt.207")); //$NON-NLS-1$
+        }
+        if (path == null) {
+            // awt.208=Path is null
+            throw new NullPointerException(Messages.getString("awt.208")); //$NON-NLS-1$
+        }
+        this.p = path;
+        this.flatness = flatness;
+        this.flatness2 = flatness * flatness;
+        this.bufLimit = limit;
+        this.bufSize = Math.min(bufLimit, BUFFER_SIZE);
+        this.buf = new double[bufSize];
+        this.bufIndex = bufSize;
+    }
+
+    /**
+     * Gets the flattening factor.
+     * 
+     * @return the flattening factor.
+     */
+    public double getFlatness() {
+        return flatness;
+    }
+
+    /**
+     * Gets the maximum number of subdivisions per curved segment.
+     * 
+     * @return the maximum number of subdivisions per curved segment.
+     */
+    public int getRecursionLimit() {
+        return bufLimit;
+    }
+
+    public int getWindingRule() {
+        return p.getWindingRule();
+    }
+
+    public boolean isDone() {
+        return bufEmpty && p.isDone();
+    }
+
+    /**
+     * Calculates flat path points for current segment of the source shape. Line
+     * segment is flat by itself. Flatness of quad and cubic curves evaluated by
+     * getFlatnessSq() method. Curves subdivided until current flatness is
+     * bigger than user defined and subdivision limit isn't exhausted. Single
+     * source segment translated to series of buffer points. The less flatness
+     * the bigger series. Every currentSegment() call extract one point from the
+     * buffer. When series completed evaluate() takes next source shape segment.
+     */
+    void evaluate() {
+        if (bufEmpty) {
+            bufType = p.currentSegment(coords);
+        }
+
+        switch (bufType) {
+            case SEG_MOVETO:
+            case SEG_LINETO:
+                px = coords[0];
+                py = coords[1];
+                break;
+            case SEG_QUADTO:
+                if (bufEmpty) {
+                    bufIndex -= 6;
+                    buf[bufIndex + 0] = px;
+                    buf[bufIndex + 1] = py;
+                    System.arraycopy(coords, 0, buf, bufIndex + 2, 4);
+                    bufSubdiv = 0;
+                }
+
+                while (bufSubdiv < bufLimit) {
+                    if (QuadCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) {
+                        break;
+                    }
+
+                    // Realloc buffer
+                    if (bufIndex <= 4) {
+                        double tmp[] = new double[bufSize + BUFFER_CAPACITY];
+                        System.arraycopy(buf, bufIndex, tmp, bufIndex + BUFFER_CAPACITY, bufSize
+                                - bufIndex);
+                        buf = tmp;
+                        bufSize += BUFFER_CAPACITY;
+                        bufIndex += BUFFER_CAPACITY;
+                    }
+
+                    QuadCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 4, buf, bufIndex);
+
+                    bufIndex -= 4;
+                    bufSubdiv++;
+                }
+
+                bufIndex += 4;
+                px = buf[bufIndex];
+                py = buf[bufIndex + 1];
+
+                bufEmpty = (bufIndex == bufSize - 2);
+                if (bufEmpty) {
+                    bufIndex = bufSize;
+                    bufType = SEG_LINETO;
+                } else {
+                    bufSubdiv--;
+                }
+                break;
+            case SEG_CUBICTO:
+                if (bufEmpty) {
+                    bufIndex -= 8;
+                    buf[bufIndex + 0] = px;
+                    buf[bufIndex + 1] = py;
+                    System.arraycopy(coords, 0, buf, bufIndex + 2, 6);
+                    bufSubdiv = 0;
+                }
+
+                while (bufSubdiv < bufLimit) {
+                    if (CubicCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) {
+                        break;
+                    }
+
+                    // Realloc buffer
+                    if (bufIndex <= 6) {
+                        double tmp[] = new double[bufSize + BUFFER_CAPACITY];
+                        System.arraycopy(buf, bufIndex, tmp, bufIndex + BUFFER_CAPACITY, bufSize
+                                - bufIndex);
+                        buf = tmp;
+                        bufSize += BUFFER_CAPACITY;
+                        bufIndex += BUFFER_CAPACITY;
+                    }
+
+                    CubicCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 6, buf, bufIndex);
+
+                    bufIndex -= 6;
+                    bufSubdiv++;
+                }
+
+                bufIndex += 6;
+                px = buf[bufIndex];
+                py = buf[bufIndex + 1];
+
+                bufEmpty = (bufIndex == bufSize - 2);
+                if (bufEmpty) {
+                    bufIndex = bufSize;
+                    bufType = SEG_LINETO;
+                } else {
+                    bufSubdiv--;
+                }
+                break;
+        }
+
+    }
+
+    public void next() {
+        if (bufEmpty) {
+            p.next();
+        }
+    }
+
+    public int currentSegment(float[] coords) {
+        if (isDone()) {
+            // awt.4B=Iterator out of bounds
+            throw new NoSuchElementException(Messages.getString("awt.4Bx")); //$NON-NLS-1$
+        }
+        evaluate();
+        int type = bufType;
+        if (type != SEG_CLOSE) {
+            coords[0] = (float)px;
+            coords[1] = (float)py;
+            if (type != SEG_MOVETO) {
+                type = SEG_LINETO;
+            }
+        }
+        return type;
+    }
+
+    public int currentSegment(double[] coords) {
+        if (isDone()) {
+            // awt.4B=Iterator out of bounds
+            throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+        }
+        evaluate();
+        int type = bufType;
+        if (type != SEG_CLOSE) {
+            coords[0] = px;
+            coords[1] = py;
+            if (type != SEG_MOVETO) {
+                type = SEG_LINETO;
+            }
+        }
+        return type;
+    }
+}
diff --git a/awt/java/awt/geom/GeneralPath.java b/awt/java/awt/geom/GeneralPath.java
new file mode 100644
index 0000000..0669bc7
--- /dev/null
+++ b/awt/java/awt/geom/GeneralPath.java
@@ -0,0 +1,624 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.gl.Crossing;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The class GeneralPath represents a shape whose outline is given by different
+ * types of curved and straight segments.
+ * 
+ * @since Android 1.0
+ */
+public final class GeneralPath implements Shape, Cloneable {
+
+    /**
+     * The Constant WIND_EVEN_ODD see {@link PathIterator#WIND_EVEN_ODD}.
+     */
+    public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
+
+    /**
+     * The Constant WIND_NON_ZERO see {@link PathIterator#WIND_NON_ZERO}.
+     */
+    public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
+
+    /**
+     * The buffers size.
+     */
+    private static final int BUFFER_SIZE = 10;
+
+    /**
+     * The buffers capacity.
+     */
+    private static final int BUFFER_CAPACITY = 10;
+
+    /**
+     * The point's types buffer.
+     */
+    byte[] types;
+
+    /**
+     * The points buffer.
+     */
+    float[] points;
+
+    /**
+     * The point's type buffer size.
+     */
+    int typeSize;
+
+    /**
+     * The points buffer size.
+     */
+    int pointSize;
+
+    /**
+     * The path rule.
+     */
+    int rule;
+
+    /**
+     * The space amount in points buffer for different segmenet's types.
+     */
+    static int pointShift[] = {
+            2, // MOVETO
+            2, // LINETO
+            4, // QUADTO
+            6, // CUBICTO
+            0
+    }; // CLOSE
+
+    /*
+     * GeneralPath path iterator
+     */
+    /**
+     * The Class Iterator is the subclass of Iterator for traversing the outline
+     * of a GeneralPath.
+     */
+    class Iterator implements PathIterator {
+
+        /**
+         * The current cursor position in types buffer.
+         */
+        int typeIndex;
+
+        /**
+         * The current cursor position in points buffer.
+         */
+        int pointIndex;
+
+        /**
+         * The source GeneralPath object.
+         */
+        GeneralPath p;
+
+        /**
+         * The path iterator transformation.
+         */
+        AffineTransform t;
+
+        /**
+         * Constructs a new GeneralPath.Iterator for given general path.
+         * 
+         * @param path
+         *            the source GeneralPath object.
+         */
+        Iterator(GeneralPath path) {
+            this(path, null);
+        }
+
+        /**
+         * Constructs a new GeneralPath.Iterator for given general path and
+         * transformation.
+         * 
+         * @param path
+         *            the source GeneralPath object.
+         * @param at
+         *            the AffineTransform object to apply rectangle path.
+         */
+        Iterator(GeneralPath path, AffineTransform at) {
+            this.p = path;
+            this.t = at;
+        }
+
+        public int getWindingRule() {
+            return p.getWindingRule();
+        }
+
+        public boolean isDone() {
+            return typeIndex >= p.typeSize;
+        }
+
+        public void next() {
+            typeIndex++;
+        }
+
+        public int currentSegment(double[] coords) {
+            if (isDone()) {
+                // awt.4B=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            int type = p.types[typeIndex];
+            int count = GeneralPath.pointShift[type];
+            for (int i = 0; i < count; i++) {
+                coords[i] = p.points[pointIndex + i];
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, count / 2);
+            }
+            pointIndex += count;
+            return type;
+        }
+
+        public int currentSegment(float[] coords) {
+            if (isDone()) {
+                // awt.4B=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            int type = p.types[typeIndex];
+            int count = GeneralPath.pointShift[type];
+            System.arraycopy(p.points, pointIndex, coords, 0, count);
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, count / 2);
+            }
+            pointIndex += count;
+            return type;
+        }
+
+    }
+
+    /**
+     * Instantiates a new general path with the winding rule set to
+     * {@link PathIterator#WIND_NON_ZERO} and the initial capacity (number of
+     * segments) set to the default value 10.
+     */
+    public GeneralPath() {
+        this(WIND_NON_ZERO, BUFFER_SIZE);
+    }
+
+    /**
+     * Instantiates a new general path with the given winding rule and the
+     * initial capacity (number of segments) set to the default value 10.
+     * 
+     * @param rule
+     *            the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or
+     *            {@link PathIterator#WIND_NON_ZERO}.
+     */
+    public GeneralPath(int rule) {
+        this(rule, BUFFER_SIZE);
+    }
+
+    /**
+     * Instantiates a new general path with the given winding rule and initial
+     * capacity (number of segments).
+     * 
+     * @param rule
+     *            the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or
+     *            {@link PathIterator#WIND_NON_ZERO}.
+     * @param initialCapacity
+     *            the number of segments the path is set to hold.
+     */
+    public GeneralPath(int rule, int initialCapacity) {
+        setWindingRule(rule);
+        types = new byte[initialCapacity];
+        points = new float[initialCapacity * 2];
+    }
+
+    /**
+     * Creates a new GeneralPath from the outline of the given shape.
+     * 
+     * @param shape
+     *            the shape.
+     */
+    public GeneralPath(Shape shape) {
+        this(WIND_NON_ZERO, BUFFER_SIZE);
+        PathIterator p = shape.getPathIterator(null);
+        setWindingRule(p.getWindingRule());
+        append(p, false);
+    }
+
+    /**
+     * Sets the winding rule, which determines how to decide whether a point
+     * that isn't on the path itself is inside or outside of the shape.
+     * 
+     * @param rule
+     *            the new winding rule.
+     * @throws IllegalArgumentException
+     *             if the winding rule is neither
+     *             {@link PathIterator#WIND_EVEN_ODD} nor
+     *             {@link PathIterator#WIND_NON_ZERO}.
+     */
+    public void setWindingRule(int rule) {
+        if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
+            // awt.209=Invalid winding rule value
+            throw new java.lang.IllegalArgumentException(Messages.getString("awt.209")); //$NON-NLS-1$
+        }
+        this.rule = rule;
+    }
+
+    /**
+     * Gets the winding rule.
+     * 
+     * @return the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or
+     *         {@link PathIterator#WIND_NON_ZERO}.
+     */
+    public int getWindingRule() {
+        return rule;
+    }
+
+    /**
+     * Checks the point data buffer sizes to see whether pointCount additional
+     * point-data elements can fit. (Note that the number of point data elements
+     * to add is more than one per point -- it depends on the type of point
+     * being added.) Reallocates the buffers to enlarge the size if necessary.
+     * 
+     * @param pointCount
+     *            the number of point data elements to be added.
+     * @param checkMove
+     *            whether to check for existing points.
+     * @throws IllegalPathStateException
+     *             checkMove is true and the path is currently empty.
+     */
+    void checkBuf(int pointCount, boolean checkMove) {
+        if (checkMove && typeSize == 0) {
+            // awt.20A=First segment should be SEG_MOVETO type
+            throw new IllegalPathStateException(Messages.getString("awt.20A")); //$NON-NLS-1$
+        }
+        if (typeSize == types.length) {
+            byte tmp[] = new byte[typeSize + BUFFER_CAPACITY];
+            System.arraycopy(types, 0, tmp, 0, typeSize);
+            types = tmp;
+        }
+        if (pointSize + pointCount > points.length) {
+            float tmp[] = new float[pointSize + Math.max(BUFFER_CAPACITY * 2, pointCount)];
+            System.arraycopy(points, 0, tmp, 0, pointSize);
+            points = tmp;
+        }
+    }
+
+    /**
+     * Appends a new point to the end of this general path, disconnected from
+     * the existing path.
+     * 
+     * @param x
+     *            the x coordinate of the next point to append.
+     * @param y
+     *            the y coordinate of the next point to append.
+     */
+    public void moveTo(float x, float y) {
+        if (typeSize > 0 && types[typeSize - 1] == PathIterator.SEG_MOVETO) {
+            points[pointSize - 2] = x;
+            points[pointSize - 1] = y;
+        } else {
+            checkBuf(2, false);
+            types[typeSize++] = PathIterator.SEG_MOVETO;
+            points[pointSize++] = x;
+            points[pointSize++] = y;
+        }
+    }
+
+    /**
+     * Appends a new segment to the end of this general path by making a
+     * straight line segment from the current endpoint to the given new point.
+     * 
+     * @param x
+     *            the x coordinate of the next point to append.
+     * @param y
+     *            the y coordinate of the next point to append.
+     */
+    public void lineTo(float x, float y) {
+        checkBuf(2, true);
+        types[typeSize++] = PathIterator.SEG_LINETO;
+        points[pointSize++] = x;
+        points[pointSize++] = y;
+    }
+
+    /**
+     * Appends a new segment to the end of this general path by making a
+     * quadratic curve from the current endpoint to the point (x2, y2) using the
+     * point (x1, y1) as the quadratic curve's control point.
+     * 
+     * @param x1
+     *            the x coordinate of the quadratic curve's control point.
+     * @param y1
+     *            the y coordinate of the quadratic curve's control point.
+     * @param x2
+     *            the x coordinate of the quadratic curve's end point.
+     * @param y2
+     *            the y coordinate of the quadratic curve's end point.
+     */
+    public void quadTo(float x1, float y1, float x2, float y2) {
+        checkBuf(4, true);
+        types[typeSize++] = PathIterator.SEG_QUADTO;
+        points[pointSize++] = x1;
+        points[pointSize++] = y1;
+        points[pointSize++] = x2;
+        points[pointSize++] = y2;
+    }
+
+    /**
+     * Appends a new segment to the end of this general path by making a cubic
+     * curve from the current endpoint to the point (x3, y3) using (x1, y1) and
+     * (x2, y2) as control points.
+     * 
+     * @see java.awt.geom.CubicCurve2D
+     * @param x1
+     *            the x coordinate of the new cubic segment's first control
+     *            point.
+     * @param y1
+     *            the y coordinate of the new cubic segment's first control
+     *            point.
+     * @param x2
+     *            the x coordinate of the new cubic segment's second control
+     *            point.
+     * @param y2
+     *            the y coordinate of the new cubic segment's second control
+     *            point.
+     * @param x3
+     *            the x coordinate of the new cubic segment's end point.
+     * @param y3
+     *            the y coordinate of the new cubic segment's end point.
+     */
+    public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) {
+        checkBuf(6, true);
+        types[typeSize++] = PathIterator.SEG_CUBICTO;
+        points[pointSize++] = x1;
+        points[pointSize++] = y1;
+        points[pointSize++] = x2;
+        points[pointSize++] = y2;
+        points[pointSize++] = x3;
+        points[pointSize++] = y3;
+    }
+
+    /**
+     * Appends the type information to declare that the current endpoint closes
+     * the curve.
+     */
+    public void closePath() {
+        if (typeSize == 0 || types[typeSize - 1] != PathIterator.SEG_CLOSE) {
+            checkBuf(0, true);
+            types[typeSize++] = PathIterator.SEG_CLOSE;
+        }
+    }
+
+    /**
+     * Appends the outline of the specified shape onto the end of this
+     * GeneralPath.
+     * 
+     * @param shape
+     *            the shape whose outline is to be appended.
+     * @param connect
+     *            true to connect this path's current endpoint to the first
+     *            point of the shape's outline or false to append the shape's
+     *            outline without connecting it.
+     * @throws NullPointerException
+     *             if the shape parameter is null.
+     */
+    public void append(Shape shape, boolean connect) {
+        PathIterator p = shape.getPathIterator(null);
+        append(p, connect);
+    }
+
+    /**
+     * Appends the path defined by the specified PathIterator onto the end of
+     * this GeneralPath.
+     * 
+     * @param path
+     *            the PathIterator that defines the new path to append.
+     * @param connect
+     *            true to connect this path's current endpoint to the first
+     *            point of the shape's outline or false to append the shape's
+     *            outline without connecting it.
+     */
+    public void append(PathIterator path, boolean connect) {
+        while (!path.isDone()) {
+            float coords[] = new float[6];
+            switch (path.currentSegment(coords)) {
+                case PathIterator.SEG_MOVETO:
+                    if (!connect || typeSize == 0) {
+                        moveTo(coords[0], coords[1]);
+                        break;
+                    }
+                    if (types[typeSize - 1] != PathIterator.SEG_CLOSE
+                            && points[pointSize - 2] == coords[0]
+                            && points[pointSize - 1] == coords[1]) {
+                        break;
+                    }
+                    // NO BREAK;
+                case PathIterator.SEG_LINETO:
+                    lineTo(coords[0], coords[1]);
+                    break;
+                case PathIterator.SEG_QUADTO:
+                    quadTo(coords[0], coords[1], coords[2], coords[3]);
+                    break;
+                case PathIterator.SEG_CUBICTO:
+                    curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
+                    break;
+                case PathIterator.SEG_CLOSE:
+                    closePath();
+                    break;
+            }
+            path.next();
+            connect = false;
+        }
+    }
+
+    /**
+     * Gets the current end point of the path.
+     * 
+     * @return the current end point of the path.
+     */
+    public Point2D getCurrentPoint() {
+        if (typeSize == 0) {
+            return null;
+        }
+        int j = pointSize - 2;
+        if (types[typeSize - 1] == PathIterator.SEG_CLOSE) {
+
+            for (int i = typeSize - 2; i > 0; i--) {
+                int type = types[i];
+                if (type == PathIterator.SEG_MOVETO) {
+                    break;
+                }
+                j -= pointShift[type];
+            }
+        }
+        return new Point2D.Float(points[j], points[j + 1]);
+    }
+
+    /**
+     * Resets the GeneralPath to being an empty path. The underlying point and
+     * segment data is not deleted but rather the end indices of the data arrays
+     * are set to zero.
+     */
+    public void reset() {
+        typeSize = 0;
+        pointSize = 0;
+    }
+
+    /**
+     * Transform all of the coordinates of this path according to the specified
+     * AffineTransform.
+     * 
+     * @param t
+     *            the AffineTransform.
+     */
+    public void transform(AffineTransform t) {
+        t.transform(points, 0, points, 0, pointSize / 2);
+    }
+
+    /**
+     * Creates a new GeneralPath whose data is given by this path's data
+     * transformed according to the specified AffineTransform.
+     * 
+     * @param t
+     *            the AffineTransform.
+     * @return the new GeneralPath whose data is given by this path's data
+     *         transformed according to the specified AffineTransform.
+     */
+    public Shape createTransformedShape(AffineTransform t) {
+        GeneralPath p = (GeneralPath)clone();
+        if (t != null) {
+            p.transform(t);
+        }
+        return p;
+    }
+
+    public Rectangle2D getBounds2D() {
+        float rx1, ry1, rx2, ry2;
+        if (pointSize == 0) {
+            rx1 = ry1 = rx2 = ry2 = 0.0f;
+        } else {
+            int i = pointSize - 1;
+            ry1 = ry2 = points[i--];
+            rx1 = rx2 = points[i--];
+            while (i > 0) {
+                float y = points[i--];
+                float x = points[i--];
+                if (x < rx1) {
+                    rx1 = x;
+                } else if (x > rx2) {
+                    rx2 = x;
+                }
+                if (y < ry1) {
+                    ry1 = y;
+                } else if (y > ry2) {
+                    ry2 = y;
+                }
+            }
+        }
+        return new Rectangle2D.Float(rx1, ry1, rx2 - rx1, ry2 - ry1);
+    }
+
+    public Rectangle getBounds() {
+        return getBounds2D().getBounds();
+    }
+
+    /**
+     * Checks the cross count (number of times a ray from the point crosses the
+     * shape's boundary) to determine whether the number of crossings
+     * corresponds to a point inside the shape or not (according to the shape's
+     * path rule).
+     * 
+     * @param cross
+     *            the point's cross count.
+     * @return true if the point is inside the path, or false otherwise.
+     */
+    boolean isInside(int cross) {
+        if (rule == WIND_NON_ZERO) {
+            return Crossing.isInsideNonZero(cross);
+        }
+        return Crossing.isInsideEvenOdd(cross);
+    }
+
+    public boolean contains(double px, double py) {
+        return isInside(Crossing.crossShape(this, px, py));
+    }
+
+    public boolean contains(double rx, double ry, double rw, double rh) {
+        int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+        return cross != Crossing.CROSSING && isInside(cross);
+    }
+
+    public boolean intersects(double rx, double ry, double rw, double rh) {
+        int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+        return cross == Crossing.CROSSING || isInside(cross);
+    }
+
+    public boolean contains(Point2D p) {
+        return contains(p.getX(), p.getY());
+    }
+
+    public boolean contains(Rectangle2D r) {
+        return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+    }
+
+    public boolean intersects(Rectangle2D r) {
+        return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+    }
+
+    public PathIterator getPathIterator(AffineTransform t) {
+        return new Iterator(this, t);
+    }
+
+    public PathIterator getPathIterator(AffineTransform t, double flatness) {
+        return new FlatteningPathIterator(getPathIterator(t), flatness);
+    }
+
+    @Override
+    public Object clone() {
+        try {
+            GeneralPath p = (GeneralPath)super.clone();
+            p.types = types.clone();
+            p.points = points.clone();
+            return p;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+}
diff --git a/awt/java/awt/geom/IllegalPathStateException.java b/awt/java/awt/geom/IllegalPathStateException.java
new file mode 100644
index 0000000..750ba29
--- /dev/null
+++ b/awt/java/awt/geom/IllegalPathStateException.java
@@ -0,0 +1,55 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+/**
+ * The Class IllegalPathStateException indicates errors where the current state
+ * of a path object is incompatible with the desired action, such as performing
+ * non-trivial actions on an empty path.
+ * 
+ * @since Android 1.0
+ */
+public class IllegalPathStateException extends RuntimeException {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -5158084205220481094L;
+
+    /**
+     * Instantiates a new illegal path state exception.
+     */
+    public IllegalPathStateException() {
+    }
+
+    /**
+     * Instantiates a new illegal path state exception with the specified detail
+     * message.
+     * 
+     * @param s
+     *            the details of the error.
+     */
+    public IllegalPathStateException(String s) {
+        super(s);
+    }
+
+}
diff --git a/awt/java/awt/geom/Line2D.java b/awt/java/awt/geom/Line2D.java
new file mode 100644
index 0000000..fcd51b6
--- /dev/null
+++ b/awt/java/awt/geom/Line2D.java
@@ -0,0 +1,948 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class Line2D represents a line whose data is given in high-precision
+ * values appropriate for graphical operations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class Line2D implements Shape, Cloneable {
+
+    /**
+     * The Class Float is the subclass of Line2D that has all of its data values
+     * stored with float-level precision.
+     * 
+     * @since Android 1.0
+     */
+    public static class Float extends Line2D {
+
+        /**
+         * The x coordinate of the starting point.
+         */
+        public float x1;
+
+        /**
+         * The y coordinate of the starting point.
+         */
+        public float y1;
+
+        /**
+         * The x coordinate of the end point.
+         */
+        public float x2;
+
+        /**
+         * The y coordinate of the end point.
+         */
+        public float y2;
+
+        /**
+         * Instantiates a new float-valued Line2D with its data values set to
+         * zero.
+         */
+        public Float() {
+        }
+
+        /**
+         * Instantiates a new float-valued Line2D with the specified endpoints.
+         * 
+         * @param x1
+         *            the x coordinate of the starting point.
+         * @param y1
+         *            the y coordinate of the starting point.
+         * @param x2
+         *            the x coordinate of the end point.
+         * @param y2
+         *            the y coordinate of the end point.
+         */
+        public Float(float x1, float y1, float x2, float y2) {
+            setLine(x1, y1, x2, y2);
+        }
+
+        /**
+         * Instantiates a new float-valued Line2D with the specified endpoints.
+         * 
+         * @param p1
+         *            the starting point.
+         * @param p2
+         *            the end point.
+         */
+        public Float(Point2D p1, Point2D p2) {
+            setLine(p1, p2);
+        }
+
+        @Override
+        public double getX1() {
+            return x1;
+        }
+
+        @Override
+        public double getY1() {
+            return y1;
+        }
+
+        @Override
+        public double getX2() {
+            return x2;
+        }
+
+        @Override
+        public double getY2() {
+            return y2;
+        }
+
+        @Override
+        public Point2D getP1() {
+            return new Point2D.Float(x1, y1);
+        }
+
+        @Override
+        public Point2D getP2() {
+            return new Point2D.Float(x2, y2);
+        }
+
+        @Override
+        public void setLine(double x1, double y1, double x2, double y2) {
+            this.x1 = (float)x1;
+            this.y1 = (float)y1;
+            this.x2 = (float)x2;
+            this.y2 = (float)y2;
+        }
+
+        /**
+         * Sets the data values that define the line.
+         * 
+         * @param x1
+         *            the x coordinate of the starting point.
+         * @param y1
+         *            the y coordinate of the starting point.
+         * @param x2
+         *            the x coordinate of the end point.
+         * @param y2
+         *            the y coordinate of the end point.
+         */
+        public void setLine(float x1, float y1, float x2, float y2) {
+            this.x1 = x1;
+            this.y1 = y1;
+            this.x2 = x2;
+            this.y2 = y2;
+        }
+
+        public Rectangle2D getBounds2D() {
+            float rx, ry, rw, rh;
+            if (x1 < x2) {
+                rx = x1;
+                rw = x2 - x1;
+            } else {
+                rx = x2;
+                rw = x1 - x2;
+            }
+            if (y1 < y2) {
+                ry = y1;
+                rh = y2 - y1;
+            } else {
+                ry = y2;
+                rh = y1 - y2;
+            }
+            return new Rectangle2D.Float(rx, ry, rw, rh);
+        }
+    }
+
+    /**
+     * The Class Double is the subclass of Line2D that has all of its data
+     * values stored with double-level precision.
+     * 
+     * @since Android 1.0
+     */
+    public static class Double extends Line2D {
+
+        /**
+         * The x coordinate of the starting point.
+         */
+        public double x1;
+
+        /**
+         * The y coordinate of the starting point.
+         */
+        public double y1;
+
+        /**
+         * The x coordinate of the end point.
+         */
+        public double x2;
+
+        /**
+         * The y coordinate of the end point.
+         */
+        public double y2;
+
+        /**
+         * Instantiates a new double-valued Line2D with its data values set to
+         * zero.
+         */
+        public Double() {
+        }
+
+        /**
+         * Instantiates a new double-valued Line2D with the specified endpoints.
+         * 
+         * @param x1
+         *            the x coordinate of the starting point.
+         * @param y1
+         *            the y coordinate of the starting point.
+         * @param x2
+         *            the x coordinate of the end point.
+         * @param y2
+         *            the y coordinate of the end point.
+         */
+        public Double(double x1, double y1, double x2, double y2) {
+            setLine(x1, y1, x2, y2);
+        }
+
+        /**
+         * Instantiates a new double-valued Line2D with the specified endpoints.
+         * 
+         * @param p1
+         *            the starting point.
+         * @param p2
+         *            the end point.
+         */
+        public Double(Point2D p1, Point2D p2) {
+            setLine(p1, p2);
+        }
+
+        @Override
+        public double getX1() {
+            return x1;
+        }
+
+        @Override
+        public double getY1() {
+            return y1;
+        }
+
+        @Override
+        public double getX2() {
+            return x2;
+        }
+
+        @Override
+        public double getY2() {
+            return y2;
+        }
+
+        @Override
+        public Point2D getP1() {
+            return new Point2D.Double(x1, y1);
+        }
+
+        @Override
+        public Point2D getP2() {
+            return new Point2D.Double(x2, y2);
+        }
+
+        @Override
+        public void setLine(double x1, double y1, double x2, double y2) {
+            this.x1 = x1;
+            this.y1 = y1;
+            this.x2 = x2;
+            this.y2 = y2;
+        }
+
+        public Rectangle2D getBounds2D() {
+            double rx, ry, rw, rh;
+            if (x1 < x2) {
+                rx = x1;
+                rw = x2 - x1;
+            } else {
+                rx = x2;
+                rw = x1 - x2;
+            }
+            if (y1 < y2) {
+                ry = y1;
+                rh = y2 - y1;
+            } else {
+                ry = y2;
+                rh = y1 - y2;
+            }
+            return new Rectangle2D.Double(rx, ry, rw, rh);
+        }
+    }
+
+    /*
+     * Line2D path iterator
+     */
+    /**
+     * The subclass of PathIterator to traverse a Line2D.
+     */
+    class Iterator implements PathIterator {
+
+        /**
+         * The x coordinate of the start line point.
+         */
+        double x1;
+
+        /**
+         * The y coordinate of the start line point.
+         */
+        double y1;
+
+        /**
+         * The x coordinate of the end line point.
+         */
+        double x2;
+
+        /**
+         * The y coordinate of the end line point.
+         */
+        double y2;
+
+        /**
+         * The path iterator transformation.
+         */
+        AffineTransform t;
+
+        /**
+         * The current segment index.
+         */
+        int index;
+
+        /**
+         * Constructs a new Line2D.Iterator for given line and transformation.
+         * 
+         * @param l
+         *            the source Line2D object.
+         * @param at
+         *            the AffineTransform object to apply rectangle path.
+         */
+        Iterator(Line2D l, AffineTransform at) {
+            this.x1 = l.getX1();
+            this.y1 = l.getY1();
+            this.x2 = l.getX2();
+            this.y2 = l.getY2();
+            this.t = at;
+        }
+
+        public int getWindingRule() {
+            return WIND_NON_ZERO;
+        }
+
+        public boolean isDone() {
+            return index > 1;
+        }
+
+        public void next() {
+            index++;
+        }
+
+        public int currentSegment(double[] coords) {
+            if (isDone()) {
+                // awt.4B=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            int type;
+            if (index == 0) {
+                type = SEG_MOVETO;
+                coords[0] = x1;
+                coords[1] = y1;
+            } else {
+                type = SEG_LINETO;
+                coords[0] = x2;
+                coords[1] = y2;
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, 1);
+            }
+            return type;
+        }
+
+        public int currentSegment(float[] coords) {
+            if (isDone()) {
+                // awt.4B=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            int type;
+            if (index == 0) {
+                type = SEG_MOVETO;
+                coords[0] = (float)x1;
+                coords[1] = (float)y1;
+            } else {
+                type = SEG_LINETO;
+                coords[0] = (float)x2;
+                coords[1] = (float)y2;
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, 1);
+            }
+            return type;
+        }
+
+    }
+
+    /**
+     * Instantiates a new Line2D.
+     */
+    protected Line2D() {
+    }
+
+    /**
+     * Gets the x coordinate of the starting point.
+     * 
+     * @return the x coordinate of the starting point.
+     */
+    public abstract double getX1();
+
+    /**
+     * Gets the y coordinate of the starting point.
+     * 
+     * @return the y coordinate of the starting point.
+     */
+    public abstract double getY1();
+
+    /**
+     * Gets the x coordinate of the end point.
+     * 
+     * @return the x2.
+     */
+    public abstract double getX2();
+
+    /**
+     * Gets the y coordinate of the end point.
+     * 
+     * @return the y coordinate of the end point.
+     */
+    public abstract double getY2();
+
+    /**
+     * Gets the p the starting point.
+     * 
+     * @return the p the starting point.
+     */
+    public abstract Point2D getP1();
+
+    /**
+     * Gets the p end point.
+     * 
+     * @return the p end point.
+     */
+    public abstract Point2D getP2();
+
+    /**
+     * Sets the line's endpoints.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point.
+     * @param y1
+     *            the y coordinate of the starting point.
+     * @param x2
+     *            the x coordinate of the end point.
+     * @param y2
+     *            the y coordinate of the end point.
+     */
+    public abstract void setLine(double x1, double y1, double x2, double y2);
+
+    /**
+     * Sets the line's endpoints.
+     * 
+     * @param p1
+     *            the starting point.
+     * @param p2
+     *            the end point.
+     */
+    public void setLine(Point2D p1, Point2D p2) {
+        setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY());
+    }
+
+    /**
+     * Sets the line's endpoints by copying the data from another Line2D.
+     * 
+     * @param line
+     *            the Line2D to copy the endpoint data from.
+     */
+    public void setLine(Line2D line) {
+        setLine(line.getX1(), line.getY1(), line.getX2(), line.getY2());
+    }
+
+    public Rectangle getBounds() {
+        return getBounds2D().getBounds();
+    }
+
+    /**
+     * Tells where the point is with respect to the line segment, given the
+     * orientation of the line segment. If the ray found by extending the line
+     * segment from its starting point is rotated, this method tells whether the
+     * ray should rotate in a clockwise direction or a counter-clockwise
+     * direction to hit the point first. The return value is 0 if the point is
+     * on the line segment, it's 1 if the point is on the ray or if the ray
+     * should rotate in a counter-clockwise direction to get to the point, and
+     * it's -1 if the ray should rotate in a clockwise direction to get to the
+     * point or if the point is on the line determined by the line segment but
+     * not on the ray from the segment's starting point and through its end
+     * point.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point of the line segment.
+     * @param y1
+     *            the y coordinate of the starting point of the line segment.
+     * @param x2
+     *            the x coordinate of the end point of the line segment.
+     * @param y2
+     *            the y coordinate of the end point of the line segment.
+     * @param px
+     *            the x coordinate of the test point.
+     * @param py
+     *            the p coordinate of the test point.
+     * @return the value that describes where the point is with respect to the
+     *         line segment, given the orientation of the line segment.
+     */
+    public static int relativeCCW(double x1, double y1, double x2, double y2, double px, double py) {
+        /*
+         * A = (x2-x1, y2-y1) P = (px-x1, py-y1)
+         */
+        x2 -= x1;
+        y2 -= y1;
+        px -= x1;
+        py -= y1;
+        double t = px * y2 - py * x2; // PxA
+        if (t == 0.0) {
+            t = px * x2 + py * y2; // P*A
+            if (t > 0.0) {
+                px -= x2; // B-A
+                py -= y2;
+                t = px * x2 + py * y2; // (P-A)*A
+                if (t < 0.0) {
+                    t = 0.0;
+                }
+            }
+        }
+
+        return t < 0.0 ? -1 : (t > 0.0 ? 1 : 0);
+    }
+
+    /**
+     * Tells where the point is with respect to this line segment, given the
+     * orientation of this line segment. If the ray found by extending the line
+     * segment from its starting point is rotated, this method tells whether the
+     * ray should rotate in a clockwise direction or a counter-clockwise
+     * direction to hit the point first. The return value is 0 if the point is
+     * on the line segment, it's 1 if the point is on the ray or if the ray
+     * should rotate in a counter-clockwise direction to get to the point, and
+     * it's -1 if the ray should rotate in a clockwise direction to get to the
+     * point or if the point is on the line determined by the line segment but
+     * not on the ray from the segment's starting point and through its end
+     * point.
+     * 
+     * @param px
+     *            the x coordinate of the test point.
+     * @param py
+     *            the p coordinate of the test point.
+     * @return the value that describes where the point is with respect to this
+     *         line segment, given the orientation of this line segment.
+     */
+    public int relativeCCW(double px, double py) {
+        return relativeCCW(getX1(), getY1(), getX2(), getY2(), px, py);
+    }
+
+    /**
+     * Tells where the point is with respect to this line segment, given the
+     * orientation of this line segment. If the ray found by extending the line
+     * segment from its starting point is rotated, this method tells whether the
+     * ray should rotate in a clockwise direction or a counter-clockwise
+     * direction to hit the point first. The return value is 0 if the point is
+     * on the line segment, it's 1 if the point is on the ray or if the ray
+     * should rotate in a counter-clockwise direction to get to the point, and
+     * it's -1 if the ray should rotate in a clockwise direction to get to the
+     * point or if the point is on the line determined by the line segment but
+     * not on the ray from the segment's starting point and through its end
+     * point.
+     * 
+     * @param p
+     *            the test point.
+     * @return the value that describes where the point is with respect to this
+     *         line segment, given the orientation of this line segment.
+     */
+    public int relativeCCW(Point2D p) {
+        return relativeCCW(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+    }
+
+    /**
+     * Tells whether the two line segments cross.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point of the first segment.
+     * @param y1
+     *            the y coordinate of the starting point of the first segment.
+     * @param x2
+     *            the x coordinate of the end point of the first segment.
+     * @param y2
+     *            the y coordinate of the end point of the first segment.
+     * @param x3
+     *            the x coordinate of the starting point of the second segment.
+     * @param y3
+     *            the y coordinate of the starting point of the second segment.
+     * @param x4
+     *            the x coordinate of the end point of the second segment.
+     * @param y4
+     *            the y coordinate of the end point of the second segment.
+     * @return true, if the two line segments cross.
+     */
+    public static boolean linesIntersect(double x1, double y1, double x2, double y2, double x3,
+            double y3, double x4, double y4) {
+        /*
+         * A = (x2-x1, y2-y1) B = (x3-x1, y3-y1) C = (x4-x1, y4-y1) D = (x4-x3,
+         * y4-y3) = C-B E = (x1-x3, y1-y3) = -B F = (x2-x3, y2-y3) = A-B Result
+         * is ((AxB) (AxC) <=0) and ((DxE) (DxF) <= 0) DxE = (C-B)x(-B) =
+         * BxB-CxB = BxC DxF = (C-B)x(A-B) = CxA-CxB-BxA+BxB = AxB+BxC-AxC
+         */
+
+        x2 -= x1; // A
+        y2 -= y1;
+        x3 -= x1; // B
+        y3 -= y1;
+        x4 -= x1; // C
+        y4 -= y1;
+
+        double AvB = x2 * y3 - x3 * y2;
+        double AvC = x2 * y4 - x4 * y2;
+
+        // Online
+        if (AvB == 0.0 && AvC == 0.0) {
+            if (x2 != 0.0) {
+                return (x4 * x3 <= 0.0)
+                        || ((x3 * x2 >= 0.0) && (x2 > 0.0 ? x3 <= x2 || x4 <= x2 : x3 >= x2
+                                || x4 >= x2));
+            }
+            if (y2 != 0.0) {
+                return (y4 * y3 <= 0.0)
+                        || ((y3 * y2 >= 0.0) && (y2 > 0.0 ? y3 <= y2 || y4 <= y2 : y3 >= y2
+                                || y4 >= y2));
+            }
+            return false;
+        }
+
+        double BvC = x3 * y4 - x4 * y3;
+
+        return (AvB * AvC <= 0.0) && (BvC * (AvB + BvC - AvC) <= 0.0);
+    }
+
+    /**
+     * Tells whether the specified line segments crosses this line segment.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point of the test segment.
+     * @param y1
+     *            the y coordinate of the starting point of the test segment.
+     * @param x2
+     *            the x coordinate of the end point of the test segment.
+     * @param y2
+     *            the y coordinate of the end point of the test segment.
+     * @return true, if the specified line segments crosses this line segment.
+     */
+    public boolean intersectsLine(double x1, double y1, double x2, double y2) {
+        return linesIntersect(x1, y1, x2, y2, getX1(), getY1(), getX2(), getY2());
+    }
+
+    /**
+     * Tells whether the specified line segments crosses this line segment.
+     * 
+     * @param l
+     *            the test segment.
+     * @return true, if the specified line segments crosses this line segment.
+     * @throws NullPointerException
+     *             if l is null.
+     */
+    public boolean intersectsLine(Line2D l) {
+        return linesIntersect(l.getX1(), l.getY1(), l.getX2(), l.getY2(), getX1(), getY1(),
+                getX2(), getY2());
+    }
+
+    /**
+     * Gives the square of the distance between the point and the line segment.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point of the line segment.
+     * @param y1
+     *            the y coordinate of the starting point of the line segment.
+     * @param x2
+     *            the x coordinate of the end point of the line segment.
+     * @param y2
+     *            the y coordinate of the end point of the line segment.
+     * @param px
+     *            the x coordinate of the test point.
+     * @param py
+     *            the y coordinate of the test point.
+     * @return the the square of the distance between the point and the line
+     *         segment.
+     */
+    public static double ptSegDistSq(double x1, double y1, double x2, double y2, double px,
+            double py) {
+        /*
+         * A = (x2 - x1, y2 - y1) P = (px - x1, py - y1)
+         */
+        x2 -= x1; // A = (x2, y2)
+        y2 -= y1;
+        px -= x1; // P = (px, py)
+        py -= y1;
+        double dist;
+        if (px * x2 + py * y2 <= 0.0) { // P*A
+            dist = px * px + py * py;
+        } else {
+            px = x2 - px; // P = A - P = (x2 - px, y2 - py)
+            py = y2 - py;
+            if (px * x2 + py * y2 <= 0.0) { // P*A
+                dist = px * px + py * py;
+            } else {
+                dist = px * y2 - py * x2;
+                dist = dist * dist / (x2 * x2 + y2 * y2); // pxA/|A|
+            }
+        }
+        if (dist < 0) {
+            dist = 0;
+        }
+        return dist;
+    }
+
+    /**
+     * Gives the distance between the point and the line segment.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point of the line segment.
+     * @param y1
+     *            the y coordinate of the starting point of the line segment.
+     * @param x2
+     *            the x coordinate of the end point of the line segment.
+     * @param y2
+     *            the y coordinate of the end point of the line segment.
+     * @param px
+     *            the x coordinate of the test point.
+     * @param py
+     *            the y coordinate of the test point.
+     * @return the the distance between the point and the line segment.
+     */
+    public static double ptSegDist(double x1, double y1, double x2, double y2, double px, double py) {
+        return Math.sqrt(ptSegDistSq(x1, y1, x2, y2, px, py));
+    }
+
+    /**
+     * Gives the square of the distance between the point and this line segment.
+     * 
+     * @param px
+     *            the x coordinate of the test point.
+     * @param py
+     *            the y coordinate of the test point.
+     * @return the the square of the distance between the point and this line
+     *         segment.
+     */
+    public double ptSegDistSq(double px, double py) {
+        return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), px, py);
+    }
+
+    /**
+     * Gives the square of the distance between the point and this line segment.
+     * 
+     * @param p
+     *            the test point.
+     * @return the square of the distance between the point and this line
+     *         segment.
+     */
+    public double ptSegDistSq(Point2D p) {
+        return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+    }
+
+    /**
+     * Gives the distance between the point and this line segment.
+     * 
+     * @param px
+     *            the x coordinate of the test point.
+     * @param py
+     *            the y coordinate of the test point.
+     * @return the distance between the point and this line segment.
+     */
+    public double ptSegDist(double px, double py) {
+        return ptSegDist(getX1(), getY1(), getX2(), getY2(), px, py);
+    }
+
+    /**
+     * Gives the distance between the point and this line segment.
+     * 
+     * @param p
+     *            the test point.
+     * @return the distance between the point and this line segment.
+     */
+    public double ptSegDist(Point2D p) {
+        return ptSegDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+    }
+
+    /**
+     * Gives the square of the distance between the point and the line.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point of the line segment.
+     * @param y1
+     *            the y coordinate of the starting point of the line segment.
+     * @param x2
+     *            the x coordinate of the end point of the line segment.
+     * @param y2
+     *            the y coordinate of the end point of the line segment.
+     * @param px
+     *            the x coordinate of the test point.
+     * @param py
+     *            the y coordinate of the test point.
+     * @return the square of the distance between the point and the line.
+     */
+    public static double ptLineDistSq(double x1, double y1, double x2, double y2, double px,
+            double py) {
+        x2 -= x1;
+        y2 -= y1;
+        px -= x1;
+        py -= y1;
+        double s = px * y2 - py * x2;
+        return s * s / (x2 * x2 + y2 * y2);
+    }
+
+    /**
+     * Gives the square of the distance between the point and the line.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point of the line segment.
+     * @param y1
+     *            the y coordinate of the starting point of the line segment.
+     * @param x2
+     *            the x coordinate of the end point of the line segment.
+     * @param y2
+     *            the y coordinate of the end point of the line segment.
+     * @param px
+     *            the x coordinate of the test point.
+     * @param py
+     *            the y coordinate of the test point.
+     * @return the square of the distance between the point and the line.
+     */
+    public static double ptLineDist(double x1, double y1, double x2, double y2, double px, double py) {
+        return Math.sqrt(ptLineDistSq(x1, y1, x2, y2, px, py));
+    }
+
+    /**
+     * Gives the square of the distance between the point and the line
+     * determined by this Line2D.
+     * 
+     * @param px
+     *            the x coordinate of the test point.
+     * @param py
+     *            the y coordinate of the test point.
+     * @return the square of the distance between the point and the line
+     *         determined by this Line2D.
+     */
+    public double ptLineDistSq(double px, double py) {
+        return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), px, py);
+    }
+
+    /**
+     * Gives the square of the distance between the point and the line
+     * determined by this Line2D.
+     * 
+     * @param p
+     *            the test point.
+     * @return the square of the distance between the point and the line
+     *         determined by this Line2D.
+     */
+    public double ptLineDistSq(Point2D p) {
+        return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+    }
+
+    /**
+     * Gives the distance between the point and the line determined by this
+     * Line2D.
+     * 
+     * @param px
+     *            the x coordinate of the test point.
+     * @param py
+     *            the y coordinate of the test point.
+     * @return the distance between the point and the line determined by this
+     *         Line2D.
+     */
+    public double ptLineDist(double px, double py) {
+        return ptLineDist(getX1(), getY1(), getX2(), getY2(), px, py);
+    }
+
+    /**
+     * Gives the distance between the point and the line determined by this
+     * Line2D.
+     * 
+     * @param p
+     *            the test point.
+     * @return the distance between the point and the line determined by this
+     *         Line2D.
+     */
+    public double ptLineDist(Point2D p) {
+        return ptLineDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+    }
+
+    public boolean contains(double px, double py) {
+        return false;
+    }
+
+    public boolean contains(Point2D p) {
+        return false;
+    }
+
+    public boolean contains(Rectangle2D r) {
+        return false;
+    }
+
+    public boolean contains(double rx, double ry, double rw, double rh) {
+        return false;
+    }
+
+    public boolean intersects(double rx, double ry, double rw, double rh) {
+        return intersects(new Rectangle2D.Double(rx, ry, rw, rh));
+    }
+
+    public boolean intersects(Rectangle2D r) {
+        return r.intersectsLine(getX1(), getY1(), getX2(), getY2());
+    }
+
+    public PathIterator getPathIterator(AffineTransform at) {
+        return new Iterator(this, at);
+    }
+
+    public PathIterator getPathIterator(AffineTransform at, double flatness) {
+        return new Iterator(this, at);
+    }
+
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+}
diff --git a/awt/java/awt/geom/NoninvertibleTransformException.java b/awt/java/awt/geom/NoninvertibleTransformException.java
new file mode 100644
index 0000000..a4e6f0f
--- /dev/null
+++ b/awt/java/awt/geom/NoninvertibleTransformException.java
@@ -0,0 +1,48 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+/**
+ * The Class NoninvertibleTransformException is the exception that is thrown
+ * when an action requires inverting an {@link AffineTransform} that is not
+ * invertible (has determinant 0).
+ * 
+ * @since Android 1.0
+ */
+public class NoninvertibleTransformException extends java.lang.Exception {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 6137225240503990466L;
+
+    /**
+     * Instantiates a new non-invertible transform exception.
+     * 
+     * @param s
+     *            the error message.
+     */
+    public NoninvertibleTransformException(String s) {
+        super(s);
+    }
+
+}
diff --git a/awt/java/awt/geom/PathIterator.java b/awt/java/awt/geom/PathIterator.java
new file mode 100644
index 0000000..2d1c0ff
--- /dev/null
+++ b/awt/java/awt/geom/PathIterator.java
@@ -0,0 +1,146 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+/**
+ * The Interface PathIterator represents an iterator object that can be used to
+ * traverse the outline of a {@link java.awt.Shape}. It returns points along the
+ * boundary of the Shape which may be actual vertices (in the case of a shape
+ * made of line segments) or may be points on a curved segment with the distance
+ * between the points determined by a chosen flattening factor.
+ * <p>
+ * If the shape is closed, the outline is traversed in the counter-clockwise
+ * direction. That means that moving forward along the boundary is to travel in
+ * such a way that the interior of the shape is to the left of the outline path
+ * and the exterior of the shape is to the right of the outline path. The
+ * interior and exterior of the shape are determined by a winding rule.
+ * </p>
+ * 
+ * @since Android 1.0
+ */
+public interface PathIterator {
+
+    /**
+     * The Constant WIND_EVEN_ODD indicates the winding rule that says that a
+     * point is outside the shape if any infinite ray from the point crosses the
+     * outline of the shape an even number of times, otherwise it is inside.
+     */
+    public static final int WIND_EVEN_ODD = 0;
+
+    /**
+     * The Constant WIND_NON_ZERO indicates the winding rule that says that a
+     * point is inside the shape if every infinite ray starting from that point
+     * crosses the outline of the shape a non-zero number of times.
+     */
+    public static final int WIND_NON_ZERO = 1;
+
+    /**
+     * The Constant SEG_MOVETO indicates that to follow the shape's outline from
+     * the previous point to the current point, the cursor (traversal point)
+     * should be placed directly on the current point.
+     */
+    public static final int SEG_MOVETO = 0;
+
+    /**
+     * The Constant SEG_LINETO indicates that to follow the shape's outline from
+     * the previous point to the current point, the cursor (traversal point)
+     * should follow a straight line.
+     */
+    public static final int SEG_LINETO = 1;
+
+    /**
+     * The Constant SEG_QUADTO indicates that to follow the shape's outline from
+     * the previous point to the current point, the cursor (traversal point)
+     * should follow a quadratic curve.
+     */
+    public static final int SEG_QUADTO = 2;
+
+    /**
+     * The Constant SEG_CUBICTO indicates that to follow the shape's outline
+     * from the previous point to the current point, the cursor (traversal
+     * point) should follow a cubic curve.
+     */
+    public static final int SEG_CUBICTO = 3;
+
+    /**
+     * The Constant SEG_CLOSE indicates that the previous point was the end of
+     * the shape's outline.
+     */
+    public static final int SEG_CLOSE = 4;
+
+    /**
+     * Gets the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or
+     * {@link PathIterator#WIND_NON_ZERO}.
+     * 
+     * @return the winding rule.
+     */
+    public int getWindingRule();
+
+    /**
+     * Checks if this PathIterator has been completely traversed.
+     * 
+     * @return true, if this PathIterator has been completely traversed.
+     */
+    public boolean isDone();
+
+    /**
+     * Tells this PathIterator to skip to the next segment.
+     */
+    public void next();
+
+    /**
+     * Gets the coordinates of the next vertex point along the shape's outline
+     * and a flag that indicates what kind of segment to use in order to connect
+     * the previous vertex point to the current vertex point to form the current
+     * segment.
+     * 
+     * @param coords
+     *            the array that the coordinates of the end point of the current
+     *            segment are written into.
+     * @return the flag that indicates how to follow the shape's outline from
+     *         the previous point to the current one, chosen from the following
+     *         constants: {@link PathIterator#SEG_MOVETO},
+     *         {@link PathIterator#SEG_LINETO}, {@link PathIterator#SEG_QUADTO},
+     *         {@link PathIterator#SEG_CUBICTO}, or
+     *         {@link PathIterator#SEG_CLOSE}.
+     */
+    public int currentSegment(float[] coords);
+
+    /**
+     * Gets the coordinates of the next vertex point along the shape's outline
+     * and a flag that indicates what kind of segment to use in order to connect
+     * the previous vertex point to the current vertex point to form the current
+     * segment.
+     * 
+     * @param coords
+     *            the array that the coordinates of the end point of the current
+     *            segment are written into.
+     * @return the flag that indicates how to follow the shape's outline from
+     *         the previous point to the current one, chosen from the following
+     *         constants: {@link PathIterator#SEG_MOVETO},
+     *         {@link PathIterator#SEG_LINETO}, {@link PathIterator#SEG_QUADTO},
+     *         {@link PathIterator#SEG_CUBICTO}, or
+     *         {@link PathIterator#SEG_CLOSE}.
+     */
+    public int currentSegment(double[] coords);
+
+}
diff --git a/awt/java/awt/geom/Point2D.java b/awt/java/awt/geom/Point2D.java
new file mode 100644
index 0000000..f7026c8
--- /dev/null
+++ b/awt/java/awt/geom/Point2D.java
@@ -0,0 +1,323 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Class Point2D represents a point whose data is given in high-precision
+ * values appropriate for graphical operations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class Point2D implements Cloneable {
+
+    /**
+     * The Class Float is the subclass of Point2D that has all of its data
+     * values stored with float-level precision.
+     * 
+     * @since Android 1.0
+     */
+    public static class Float extends Point2D {
+
+        /**
+         * The x coordinate.
+         */
+        public float x;
+
+        /**
+         * The y coordinate.
+         */
+        public float y;
+
+        /**
+         * Instantiates a new float-valued Point2D with its data set to zero.
+         */
+        public Float() {
+        }
+
+        /**
+         * Instantiates a new float-valued Point2D with the specified
+         * coordinates.
+         * 
+         * @param x
+         *            the x coordinate.
+         * @param y
+         *            the y coordinate.
+         */
+        public Float(float x, float y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public double getX() {
+            return x;
+        }
+
+        @Override
+        public double getY() {
+            return y;
+        }
+
+        /**
+         * Sets the point's coordinates.
+         * 
+         * @param x
+         *            the x coordinate.
+         * @param y
+         *            the y coordinate.
+         */
+        public void setLocation(float x, float y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void setLocation(double x, double y) {
+            this.x = (float)x;
+            this.y = (float)y;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getName() + "[x=" + x + ",y=" + y + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+    }
+
+    /**
+     * The Class Double is the subclass of Point2D that has all of its data
+     * values stored with double-level precision.
+     * 
+     * @since Android 1.0
+     */
+    public static class Double extends Point2D {
+
+        /**
+         * The x coordinate.
+         */
+        public double x;
+
+        /**
+         * The y coordinate.
+         */
+        public double y;
+
+        /**
+         * Instantiates a new double-valued Point2D with its data set to zero.
+         */
+        public Double() {
+        }
+
+        /**
+         * Instantiates a new double-valued Point2D with the specified
+         * coordinates.
+         * 
+         * @param x
+         *            the x coordinate.
+         * @param y
+         *            the y coordinate.
+         */
+        public Double(double x, double y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public double getX() {
+            return x;
+        }
+
+        @Override
+        public double getY() {
+            return y;
+        }
+
+        @Override
+        public void setLocation(double x, double y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getName() + "[x=" + x + ",y=" + y + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+    }
+
+    /**
+     * Instantiates a new Point2D.
+     */
+    protected Point2D() {
+    }
+
+    /**
+     * Gets the x coordinate.
+     * 
+     * @return the x coordinate.
+     */
+    public abstract double getX();
+
+    /**
+     * Gets the y coordinate.
+     * 
+     * @return the y coordinate.
+     */
+    public abstract double getY();
+
+    /**
+     * Sets the point's coordinates.
+     * 
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     */
+    public abstract void setLocation(double x, double y);
+
+    /**
+     * Sets the point's coordinates by copying them from another point.
+     * 
+     * @param p
+     *            the point to copy the data from.
+     */
+    public void setLocation(Point2D p) {
+        setLocation(p.getX(), p.getY());
+    }
+
+    /**
+     * Finds the square of the distance between the two specified points.
+     * 
+     * @param x1
+     *            the x coordinate of the first point.
+     * @param y1
+     *            the y coordinate of the first point.
+     * @param x2
+     *            the x coordinate of the second point.
+     * @param y2
+     *            the y coordinate of the second point.
+     * @return the square of the distance between the two specified points.
+     */
+    public static double distanceSq(double x1, double y1, double x2, double y2) {
+        x2 -= x1;
+        y2 -= y1;
+        return x2 * x2 + y2 * y2;
+    }
+
+    /**
+     * Finds the square of the distance between this point and the specified
+     * point.
+     * 
+     * @param px
+     *            the x coordinate of the point.
+     * @param py
+     *            the y coordinate of the point.
+     * @return the square of the distance between this point and the specified
+     *         point.
+     */
+    public double distanceSq(double px, double py) {
+        return Point2D.distanceSq(getX(), getY(), px, py);
+    }
+
+    /**
+     * Finds the square of the distance between this point and the specified
+     * point.
+     * 
+     * @param p
+     *            the other point.
+     * @return the square of the distance between this point and the specified
+     *         point.
+     */
+    public double distanceSq(Point2D p) {
+        return Point2D.distanceSq(getX(), getY(), p.getX(), p.getY());
+    }
+
+    /**
+     * Finds the distance between the two specified points.
+     * 
+     * @param x1
+     *            the x coordinate of the first point.
+     * @param y1
+     *            the y coordinate of the first point.
+     * @param x2
+     *            the x coordinate of the second point.
+     * @param y2
+     *            the y coordinate of the second point.
+     * @return the distance between the two specified points.
+     */
+    public static double distance(double x1, double y1, double x2, double y2) {
+        return Math.sqrt(distanceSq(x1, y1, x2, y2));
+    }
+
+    /**
+     * Finds the distance between this point and the specified point.
+     * 
+     * @param px
+     *            the x coordinate of the point.
+     * @param py
+     *            the y coordinate of the point.
+     * @return the distance between this point and the specified point.
+     */
+    public double distance(double px, double py) {
+        return Math.sqrt(distanceSq(px, py));
+    }
+
+    /**
+     * Finds the distance between this point and the specified point.
+     * 
+     * @param p
+     *            the other point.
+     * @return the distance between this point and the specified point.
+     */
+    public double distance(Point2D p) {
+        return Math.sqrt(distanceSq(p));
+    }
+
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        HashCode hash = new HashCode();
+        hash.append(getX());
+        hash.append(getY());
+        return hash.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof Point2D) {
+            Point2D p = (Point2D)obj;
+            return getX() == p.getX() && getY() == p.getY();
+        }
+        return false;
+    }
+}
diff --git a/awt/java/awt/geom/QuadCurve2D.java b/awt/java/awt/geom/QuadCurve2D.java
new file mode 100644
index 0000000..7a86a48
--- /dev/null
+++ b/awt/java/awt/geom/QuadCurve2D.java
@@ -0,0 +1,918 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.gl.Crossing;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class QuadCurve2D is a Shape that represents a segment of a quadratic
+ * (Bezier) curve. The curved segment is determined by three points: a start
+ * point, an end point, and a control point. The line from the control point to
+ * the starting point gives the tangent to the curve at the starting point, and
+ * the line from the control point to the end point gives the tangent to the
+ * curve at the end point.
+ * 
+ * @since Android 1.0
+ */
+public abstract class QuadCurve2D implements Shape, Cloneable {
+
+    /**
+     * The Class Float is the subclass of QuadCurve2D that has all of its data
+     * values stored with float-level precision.
+     * 
+     * @since Android 1.0
+     */
+    public static class Float extends QuadCurve2D {
+
+        /**
+         * The x coordinate of the starting point of the curved segment.
+         */
+        public float x1;
+
+        /**
+         * The y coordinate of the starting point of the curved segment.
+         */
+        public float y1;
+
+        /**
+         * The x coordinate of the control point.
+         */
+        public float ctrlx;
+
+        /**
+         * The y coordinate of the control point.
+         */
+        public float ctrly;
+
+        /**
+         * The x coordinate of the end point of the curved segment.
+         */
+        public float x2;
+
+        /**
+         * The y coordinate of the end point of the curved segment.
+         */
+        public float y2;
+
+        /**
+         * Instantiates a new float-valued QuadCurve2D with all coordinate
+         * values set to zero.
+         */
+        public Float() {
+        }
+
+        /**
+         * Instantiates a new float-valued QuadCurve2D with the specified
+         * coordinate values.
+         * 
+         * @param x1
+         *            the x coordinate of the starting point of the curved
+         *            segment.
+         * @param y1
+         *            the y coordinate of the starting point of the curved
+         *            segment.
+         * @param ctrlx
+         *            the x coordinate of the control point.
+         * @param ctrly
+         *            the y coordinate of the control point.
+         * @param x2
+         *            the x coordinate of the end point of the curved segment.
+         * @param y2
+         *            the y coordinate of the end point of the curved segment.
+         */
+        public Float(float x1, float y1, float ctrlx, float ctrly, float x2, float y2) {
+            setCurve(x1, y1, ctrlx, ctrly, x2, y2);
+        }
+
+        @Override
+        public double getX1() {
+            return x1;
+        }
+
+        @Override
+        public double getY1() {
+            return y1;
+        }
+
+        @Override
+        public double getCtrlX() {
+            return ctrlx;
+        }
+
+        @Override
+        public double getCtrlY() {
+            return ctrly;
+        }
+
+        @Override
+        public double getX2() {
+            return x2;
+        }
+
+        @Override
+        public double getY2() {
+            return y2;
+        }
+
+        @Override
+        public Point2D getP1() {
+            return new Point2D.Float(x1, y1);
+        }
+
+        @Override
+        public Point2D getCtrlPt() {
+            return new Point2D.Float(ctrlx, ctrly);
+        }
+
+        @Override
+        public Point2D getP2() {
+            return new Point2D.Float(x2, y2);
+        }
+
+        @Override
+        public void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) {
+            this.x1 = (float)x1;
+            this.y1 = (float)y1;
+            this.ctrlx = (float)ctrlx;
+            this.ctrly = (float)ctrly;
+            this.x2 = (float)x2;
+            this.y2 = (float)y2;
+        }
+
+        /**
+         * Sets the data values of the curve.
+         * 
+         * @param x1
+         *            the x coordinate of the starting point of the curved
+         *            segment.
+         * @param y1
+         *            the y coordinate of the starting point of the curved
+         *            segment.
+         * @param ctrlx
+         *            the x coordinate of the control point.
+         * @param ctrly
+         *            the y coordinate of the control point.
+         * @param x2
+         *            the x coordinate of the end point of the curved segment.
+         * @param y2
+         *            the y coordinate of the end point of the curved segment.
+         */
+        public void setCurve(float x1, float y1, float ctrlx, float ctrly, float x2, float y2) {
+            this.x1 = x1;
+            this.y1 = y1;
+            this.ctrlx = ctrlx;
+            this.ctrly = ctrly;
+            this.x2 = x2;
+            this.y2 = y2;
+        }
+
+        public Rectangle2D getBounds2D() {
+            float rx0 = Math.min(Math.min(x1, x2), ctrlx);
+            float ry0 = Math.min(Math.min(y1, y2), ctrly);
+            float rx1 = Math.max(Math.max(x1, x2), ctrlx);
+            float ry1 = Math.max(Math.max(y1, y2), ctrly);
+            return new Rectangle2D.Float(rx0, ry0, rx1 - rx0, ry1 - ry0);
+        }
+    }
+
+    /**
+     * The Class Double is the subclass of QuadCurve2D that has all of its data
+     * values stored with double-level precision.
+     * 
+     * @since Android 1.0
+     */
+    public static class Double extends QuadCurve2D {
+
+        /**
+         * The x coordinate of the starting point of the curved segment.
+         */
+        public double x1;
+
+        /**
+         * The y coordinate of the starting point of the curved segment.
+         */
+        public double y1;
+
+        /**
+         * The x coordinate of the control point.
+         */
+        public double ctrlx;
+
+        /**
+         * The y coordinate of the control point.
+         */
+        public double ctrly;
+
+        /**
+         * The x coordinate of the end point of the curved segment.
+         */
+        public double x2;
+
+        /**
+         * The y coordinate of the end point of the curved segment.
+         */
+        public double y2;
+
+        /**
+         * Instantiates a new double-valued QuadCurve2D with all coordinate
+         * values set to zero.
+         */
+        public Double() {
+        }
+
+        /**
+         * Instantiates a new double-valued QuadCurve2D with the specified
+         * coordinate values.
+         * 
+         * @param x1
+         *            the x coordinate of the starting point of the curved
+         *            segment.
+         * @param y1
+         *            the y coordinate of the starting point of the curved
+         *            segment.
+         * @param ctrlx
+         *            the x coordinate of the control point.
+         * @param ctrly
+         *            the y coordinate of the control point.
+         * @param x2
+         *            the x coordinate of the end point of the curved segment.
+         * @param y2
+         *            the y coordinate of the end point of the curved segment.
+         */
+        public Double(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) {
+            setCurve(x1, y1, ctrlx, ctrly, x2, y2);
+        }
+
+        @Override
+        public double getX1() {
+            return x1;
+        }
+
+        @Override
+        public double getY1() {
+            return y1;
+        }
+
+        @Override
+        public double getCtrlX() {
+            return ctrlx;
+        }
+
+        @Override
+        public double getCtrlY() {
+            return ctrly;
+        }
+
+        @Override
+        public double getX2() {
+            return x2;
+        }
+
+        @Override
+        public double getY2() {
+            return y2;
+        }
+
+        @Override
+        public Point2D getP1() {
+            return new Point2D.Double(x1, y1);
+        }
+
+        @Override
+        public Point2D getCtrlPt() {
+            return new Point2D.Double(ctrlx, ctrly);
+        }
+
+        @Override
+        public Point2D getP2() {
+            return new Point2D.Double(x2, y2);
+        }
+
+        @Override
+        public void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) {
+            this.x1 = x1;
+            this.y1 = y1;
+            this.ctrlx = ctrlx;
+            this.ctrly = ctrly;
+            this.x2 = x2;
+            this.y2 = y2;
+        }
+
+        public Rectangle2D getBounds2D() {
+            double rx0 = Math.min(Math.min(x1, x2), ctrlx);
+            double ry0 = Math.min(Math.min(y1, y2), ctrly);
+            double rx1 = Math.max(Math.max(x1, x2), ctrlx);
+            double ry1 = Math.max(Math.max(y1, y2), ctrly);
+            return new Rectangle2D.Double(rx0, ry0, rx1 - rx0, ry1 - ry0);
+        }
+    }
+
+    /*
+     * QuadCurve2D path iterator
+     */
+    /**
+     * The PathIterator for a Quad2D curve.
+     */
+    class Iterator implements PathIterator {
+
+        /**
+         * The source QuadCurve2D object.
+         */
+        QuadCurve2D c;
+
+        /**
+         * The path iterator transformation.
+         */
+        AffineTransform t;
+
+        /**
+         * The current segment index.
+         */
+        int index;
+
+        /**
+         * Constructs a new QuadCurve2D.Iterator for given curve and
+         * transformation
+         * 
+         * @param q
+         *            the source QuadCurve2D object.
+         * @param t
+         *            the AffineTransform that acts on the coordinates before
+         *            returning them (or null).
+         */
+        Iterator(QuadCurve2D q, AffineTransform t) {
+            this.c = q;
+            this.t = t;
+        }
+
+        public int getWindingRule() {
+            return WIND_NON_ZERO;
+        }
+
+        public boolean isDone() {
+            return (index > 1);
+        }
+
+        public void next() {
+            index++;
+        }
+
+        public int currentSegment(double[] coords) {
+            if (isDone()) {
+                // awt.4B=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            int type;
+            int count;
+            if (index == 0) {
+                type = SEG_MOVETO;
+                coords[0] = c.getX1();
+                coords[1] = c.getY1();
+                count = 1;
+            } else {
+                type = SEG_QUADTO;
+                coords[0] = c.getCtrlX();
+                coords[1] = c.getCtrlY();
+                coords[2] = c.getX2();
+                coords[3] = c.getY2();
+                count = 2;
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, count);
+            }
+            return type;
+        }
+
+        public int currentSegment(float[] coords) {
+            if (isDone()) {
+                // awt.4B=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            int type;
+            int count;
+            if (index == 0) {
+                type = SEG_MOVETO;
+                coords[0] = (float)c.getX1();
+                coords[1] = (float)c.getY1();
+                count = 1;
+            } else {
+                type = SEG_QUADTO;
+                coords[0] = (float)c.getCtrlX();
+                coords[1] = (float)c.getCtrlY();
+                coords[2] = (float)c.getX2();
+                coords[3] = (float)c.getY2();
+                count = 2;
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, count);
+            }
+            return type;
+        }
+
+    }
+
+    /**
+     * Instantiates a new quadratic curve.
+     */
+    protected QuadCurve2D() {
+    }
+
+    /**
+     * Gets the x coordinate of the starting point.
+     * 
+     * @return the x coordinate of the starting point.
+     */
+    public abstract double getX1();
+
+    /**
+     * Gets the y coordinate of the starting point.
+     * 
+     * @return the y coordinate of the starting point.
+     */
+    public abstract double getY1();
+
+    /**
+     * Gets the starting point.
+     * 
+     * @return the starting point.
+     */
+    public abstract Point2D getP1();
+
+    /**
+     * Gets the x coordinate of the control point.
+     * 
+     * @return the x coordinate of the control point.
+     */
+    public abstract double getCtrlX();
+
+    /**
+     * Gets the y coordinate of the control point.
+     * 
+     * @return y coordinate of the control point.
+     */
+    public abstract double getCtrlY();
+
+    /**
+     * Gets the control point.
+     * 
+     * @return the control point.
+     */
+    public abstract Point2D getCtrlPt();
+
+    /**
+     * Gets the x coordinate of the end point.
+     * 
+     * @return the x coordinate of the end point.
+     */
+    public abstract double getX2();
+
+    /**
+     * Gets the y coordinate of the end point.
+     * 
+     * @return the y coordinate of the end point.
+     */
+    public abstract double getY2();
+
+    /**
+     * Gets the end point.
+     * 
+     * @return the end point.
+     */
+    public abstract Point2D getP2();
+
+    /**
+     * Sets the data of the curve.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point of the curved segment.
+     * @param y1
+     *            the y coordinate of the starting point of the curved segment.
+     * @param ctrlx
+     *            the x coordinate of the control point.
+     * @param ctrly
+     *            the y coordinate of the control point.
+     * @param x2
+     *            the x coordinate of the end point of the curved segment.
+     * @param y2
+     *            the y coordinate of the end point of the curved segment.
+     */
+    public abstract void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2,
+            double y2);
+
+    /**
+     * Sets the data of the curve.
+     * 
+     * @param p1
+     *            the starting point of the curved segment.
+     * @param cp
+     *            the control point.
+     * @param p2
+     *            the end point of the curved segment.
+     * @throws NullPointerException
+     *             if any of the three points is null.
+     */
+    public void setCurve(Point2D p1, Point2D cp, Point2D p2) {
+        setCurve(p1.getX(), p1.getY(), cp.getX(), cp.getY(), p2.getX(), p2.getY());
+    }
+
+    /**
+     * Sets the data of the curve by reading the data from an array of values.
+     * The values are read in the same order as the arguments of the method
+     * {@link QuadCurve2D#setCurve(double, double, double, double, double, double)}
+     * .
+     * 
+     * @param coords
+     *            the array of values containing the new coordinates.
+     * @param offset
+     *            the offset of the data to read within the array.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if {@code coords.length} < offset + 6.
+     * @throws NullPointerException
+     *             if the coordinate array is null.
+     */
+    public void setCurve(double[] coords, int offset) {
+        setCurve(coords[offset + 0], coords[offset + 1], coords[offset + 2], coords[offset + 3],
+                coords[offset + 4], coords[offset + 5]);
+    }
+
+    /**
+     * Sets the data of the curve by reading the data from an array of points.
+     * The values are read in the same order as the arguments of the method
+     * {@link QuadCurve2D#setCurve(Point2D, Point2D, Point2D)}.
+     * 
+     * @param points
+     *            the array of points containing the new coordinates.
+     * @param offset
+     *            the offset of the data to read within the array.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if points.length < offset + 3.
+     * @throws NullPointerException
+     *             if the point array is null.
+     */
+    public void setCurve(Point2D[] points, int offset) {
+        setCurve(points[offset + 0].getX(), points[offset + 0].getY(), points[offset + 1].getX(),
+                points[offset + 1].getY(), points[offset + 2].getX(), points[offset + 2].getY());
+    }
+
+    /**
+     * Sets the data of the curve by copying it from another QuadCurve2D.
+     * 
+     * @param curve
+     *            the curve to copy the data points from.
+     * @throws NullPointerException
+     *             if the curve is null.
+     */
+    public void setCurve(QuadCurve2D curve) {
+        setCurve(curve.getX1(), curve.getY1(), curve.getCtrlX(), curve.getCtrlY(), curve.getX2(),
+                curve.getY2());
+    }
+
+    /**
+     * Gets the square of the distance from the control point to the straight
+     * line segment connecting the start point and the end point for this curve.
+     * 
+     * @return the square of the distance from the control point to the straight
+     *         line segment connecting the start point and the end point.
+     */
+    public double getFlatnessSq() {
+        return Line2D.ptSegDistSq(getX1(), getY1(), getX2(), getY2(), getCtrlX(), getCtrlY());
+    }
+
+    /**
+     * Gets the square of the distance from the control point to the straight
+     * line segment connecting the start point and the end point.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point of the curved segment.
+     * @param y1
+     *            the y coordinate of the starting point of the curved segment.
+     * @param ctrlx
+     *            the x coordinate of the control point.
+     * @param ctrly
+     *            the y coordinate of the control point.
+     * @param x2
+     *            the x coordinate of the end point of the curved segment.
+     * @param y2
+     *            the y coordinate of the end point of the curved segment.
+     * @return the square of the distance from the control point to the straight
+     *         line segment connecting the start point and the end point.
+     */
+    public static double getFlatnessSq(double x1, double y1, double ctrlx, double ctrly, double x2,
+            double y2) {
+        return Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx, ctrly);
+    }
+
+    /**
+     * Gets the square of the distance from the control point to the straight
+     * line segment connecting the start point and the end point by reading the
+     * coordinates of the points from an array of values. The values are read in
+     * the same order as the arguments of the method
+     * {@link QuadCurve2D#getFlatnessSq(double, double, double, double, double, double)}
+     * .
+     * 
+     * @param coords
+     *            the array of points containing the coordinates to use for the
+     *            calculation
+     * @param offset
+     *            the offset of the data to read within the array
+     * @return the square of the distance from the control point to the straight
+     *         line segment connecting the start point and the end point.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if {@code coords.length} < offset + 6.
+     * @throws NullPointerException
+     *             if the coordinate array is null.
+     */
+    public static double getFlatnessSq(double coords[], int offset) {
+        return Line2D.ptSegDistSq(coords[offset + 0], coords[offset + 1], coords[offset + 4],
+                coords[offset + 5], coords[offset + 2], coords[offset + 3]);
+    }
+
+    /**
+     * Gets the distance from the control point to the straight line segment
+     * connecting the start point and the end point of this QuadCurve2D.
+     * 
+     * @return the the distance from the control point to the straight line
+     *         segment connecting the start point and the end point of this
+     *         QuadCurve2D.
+     */
+    public double getFlatness() {
+        return Line2D.ptSegDist(getX1(), getY1(), getX2(), getY2(), getCtrlX(), getCtrlY());
+    }
+
+    /**
+     * Gets the distance from the control point to the straight line segment
+     * connecting the start point and the end point.
+     * 
+     * @param x1
+     *            the x coordinate of the starting point of the curved segment.
+     * @param y1
+     *            the y coordinate of the starting point of the curved segment.
+     * @param ctrlx
+     *            the x coordinate of the control point.
+     * @param ctrly
+     *            the y coordinate of the control point.
+     * @param x2
+     *            the x coordinate of the end point of the curved segment.
+     * @param y2
+     *            the y coordinate of the end point of the curved segment.
+     * @return the the distance from the control point to the straight line
+     *         segment connecting the start point and the end point.
+     */
+    public static double getFlatness(double x1, double y1, double ctrlx, double ctrly, double x2,
+            double y2) {
+        return Line2D.ptSegDist(x1, y1, x2, y2, ctrlx, ctrly);
+    }
+
+    /**
+     * Gets the the distance from the control point to the straight line segment
+     * connecting the start point and the end point. The values are read in the
+     * same order as the arguments of the method
+     * {@link QuadCurve2D#getFlatness(double, double, double, double, double, double)}
+     * .
+     * 
+     * @param coords
+     *            the array of points containing the coordinates to use for the
+     *            calculation.
+     * @param offset
+     *            the offset of the data to read within the array.
+     * @return the the distance from the control point to the straight line
+     *         segment connecting the start point and the end point.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if {code coords.length} < offset + 6.
+     * @throws NullPointerException
+     *             if the coordinate array is null.
+     */
+    public static double getFlatness(double coords[], int offset) {
+        return Line2D.ptSegDist(coords[offset + 0], coords[offset + 1], coords[offset + 4],
+                coords[offset + 5], coords[offset + 2], coords[offset + 3]);
+    }
+
+    /**
+     * Creates the data for two quadratic curves by dividing this curve in two.
+     * The division point is the point on the curve that is closest to this
+     * curve's control point. The data of this curve is left unchanged.
+     * 
+     * @param left
+     *            the QuadCurve2D where the left (start) segment's data is
+     *            written.
+     * @param right
+     *            the QuadCurve2D where the right (end) segment's data is
+     *            written.
+     * @throws NullPointerException
+     *             if either curve is null.
+     */
+    public void subdivide(QuadCurve2D left, QuadCurve2D right) {
+        subdivide(this, left, right);
+    }
+
+    /**
+     * Creates the data for two quadratic curves by dividing a source curve in
+     * two. The division point is the point on the curve that is closest to the
+     * source curve's control point. The data of the source curve is left
+     * unchanged.
+     * 
+     * @param src
+     *            the curve that provides the initial data.
+     * @param left
+     *            the QuadCurve2D where the left (start) segment's data is
+     *            written.
+     * @param right
+     *            the QuadCurve2D where the right (end) segment's data is
+     *            written.
+     * @throws NullPointerException
+     *             if one of the curves is null.
+     */
+    public static void subdivide(QuadCurve2D src, QuadCurve2D left, QuadCurve2D right) {
+        double x1 = src.getX1();
+        double y1 = src.getY1();
+        double cx = src.getCtrlX();
+        double cy = src.getCtrlY();
+        double x2 = src.getX2();
+        double y2 = src.getY2();
+        double cx1 = (x1 + cx) / 2.0;
+        double cy1 = (y1 + cy) / 2.0;
+        double cx2 = (x2 + cx) / 2.0;
+        double cy2 = (y2 + cy) / 2.0;
+        cx = (cx1 + cx2) / 2.0;
+        cy = (cy1 + cy2) / 2.0;
+        if (left != null) {
+            left.setCurve(x1, y1, cx1, cy1, cx, cy);
+        }
+        if (right != null) {
+            right.setCurve(cx, cy, cx2, cy2, x2, y2);
+        }
+    }
+
+    /**
+     * Creates the data for two quadratic curves by dividing a source curve in
+     * two. The division point is the point on the curve that is closest to the
+     * source curve's control point. The data for the three curves is read and
+     * written from arrays of values in the usual order: x1, y1, cx, cy, x2, y2.
+     * 
+     * @param src
+     *            the array that gives the data values for the source curve.
+     * @param srcoff
+     *            the offset in the src array to read the values from.
+     * @param left
+     *            the array where the coordinates of the start curve should be
+     *            written.
+     * @param leftOff
+     *            the offset in the left array to start writing the values.
+     * @param right
+     *            the array where the coordinates of the end curve should be
+     *            written.
+     * @param rightOff
+     *            the offset in the right array to start writing the values.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if {@code src.length} < srcoff + 6 or if {@code left.length}
+     *             < leftOff + 6 or if {@code right.length} < rightOff + 6.
+     * @throws NullPointerException
+     *             if one of the arrays is null.
+     */
+    public static void subdivide(double src[], int srcoff, double left[], int leftOff,
+            double right[], int rightOff) {
+        double x1 = src[srcoff + 0];
+        double y1 = src[srcoff + 1];
+        double cx = src[srcoff + 2];
+        double cy = src[srcoff + 3];
+        double x2 = src[srcoff + 4];
+        double y2 = src[srcoff + 5];
+        double cx1 = (x1 + cx) / 2.0;
+        double cy1 = (y1 + cy) / 2.0;
+        double cx2 = (x2 + cx) / 2.0;
+        double cy2 = (y2 + cy) / 2.0;
+        cx = (cx1 + cx2) / 2.0;
+        cy = (cy1 + cy2) / 2.0;
+        if (left != null) {
+            left[leftOff + 0] = x1;
+            left[leftOff + 1] = y1;
+            left[leftOff + 2] = cx1;
+            left[leftOff + 3] = cy1;
+            left[leftOff + 4] = cx;
+            left[leftOff + 5] = cy;
+        }
+        if (right != null) {
+            right[rightOff + 0] = cx;
+            right[rightOff + 1] = cy;
+            right[rightOff + 2] = cx2;
+            right[rightOff + 3] = cy2;
+            right[rightOff + 4] = x2;
+            right[rightOff + 5] = y2;
+        }
+    }
+
+    /**
+     * Finds the roots of the quadratic polynomial. This is accomplished by
+     * finding the (real) values of x that solve the following equation:
+     * eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. The solutions are written back into
+     * the array eqn starting from the index 0 in the array. The return value
+     * tells how many array elements have been changed by this method call.
+     * 
+     * @param eqn
+     *            an array containing the coefficients of the quadratic
+     *            polynomial to solve.
+     * @return the number of roots of the quadratic polynomial.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if {@code eqn.length} < 3.
+     * @throws NullPointerException
+     *             if the array is null.
+     */
+    public static int solveQuadratic(double eqn[]) {
+        return solveQuadratic(eqn, eqn);
+    }
+
+    /**
+     * Finds the roots of the quadratic polynomial. This is accomplished by
+     * finding the (real) values of x that solve the following equation:
+     * eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. The solutions are written into the
+     * array res starting from the index 0 in the array. The return value tells
+     * how many array elements have been written by this method call.
+     * 
+     * @param eqn
+     *            an array containing the coefficients of the quadratic
+     *            polynomial to solve.
+     * @param res
+     *            the array that this method writes the results into.
+     * @return the number of roots of the quadratic polynomial.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if {@code eqn.length} < 3 or if {@code res.length} is less
+     *             than the number of roots.
+     * @throws NullPointerException
+     *             if either array is null.
+     */
+    public static int solveQuadratic(double eqn[], double res[]) {
+        return Crossing.solveQuad(eqn, res);
+    }
+
+    public boolean contains(double px, double py) {
+        return Crossing.isInsideEvenOdd(Crossing.crossShape(this, px, py));
+    }
+
+    public boolean contains(double rx, double ry, double rw, double rh) {
+        int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+        return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross);
+    }
+
+    public boolean intersects(double rx, double ry, double rw, double rh) {
+        int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+        return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross);
+    }
+
+    public boolean contains(Point2D p) {
+        return contains(p.getX(), p.getY());
+    }
+
+    public boolean intersects(Rectangle2D r) {
+        return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+    }
+
+    public boolean contains(Rectangle2D r) {
+        return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+    }
+
+    public Rectangle getBounds() {
+        return getBounds2D().getBounds();
+    }
+
+    public PathIterator getPathIterator(AffineTransform t) {
+        return new Iterator(this, t);
+    }
+
+    public PathIterator getPathIterator(AffineTransform t, double flatness) {
+        return new FlatteningPathIterator(getPathIterator(t), flatness);
+    }
+
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+}
diff --git a/awt/java/awt/geom/Rectangle2D.java b/awt/java/awt/geom/Rectangle2D.java
new file mode 100644
index 0000000..8166134
--- /dev/null
+++ b/awt/java/awt/geom/Rectangle2D.java
@@ -0,0 +1,824 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Class Rectangle2D represents a rectangle whose coordinates are given with
+ * the correct precision to be used with the Graphics2D classes.
+ * 
+ * @since Android 1.0
+ */
+public abstract class Rectangle2D extends RectangularShape {
+
+    /**
+     * The Constant OUT_LEFT is a mask that is used to indicate that a given
+     * point is outside the rectangle and to its left.
+     */
+    public static final int OUT_LEFT = 1;
+
+    /**
+     * The Constant OUT_TOP is a mask that is used to indicate that a given
+     * point is outside the rectangle and above it.
+     */
+    public static final int OUT_TOP = 2;
+
+    /**
+     * The Constant OUT_RIGHT is a mask that is used to indicate that a given
+     * point is outside the rectangle and to its right.
+     */
+    public static final int OUT_RIGHT = 4;
+
+    /**
+     * The Constant OUT_BOTTOM is a mask that is used to indicate that a given
+     * point is outside the rectangle and above it.
+     */
+    public static final int OUT_BOTTOM = 8;
+
+    /**
+     * The Class Float is the subclass of Rectangle2D that represents a
+     * rectangle whose data values are given as floats (with float-level
+     * precision).
+     * 
+     * @since Android 1.0
+     */
+    public static class Float extends Rectangle2D {
+
+        /**
+         * The x coordinate of the rectangle's upper left corner.
+         */
+        public float x;
+
+        /**
+         * The y coordinate of the rectangle's upper left corner.
+         */
+        public float y;
+
+        /**
+         * The width of the rectangle.
+         */
+        public float width;
+
+        /**
+         * The height of the rectangle.
+         */
+        public float height;
+
+        /**
+         * Instantiates a new empty rectangle with float-precision data fields.
+         */
+        public Float() {
+        }
+
+        /**
+         * Instantiates a new rectangle with the specified float-precision data.
+         * 
+         * @param x
+         *            the x coordinate of the rectangle's upper left corner.
+         * @param y
+         *            the y coordinate of the rectangle's upper left corner.
+         * @param width
+         *            the width of the rectangle.
+         * @param height
+         *            the height of the rectangle.
+         */
+        public Float(float x, float y, float width, float height) {
+            setRect(x, y, width, height);
+        }
+
+        @Override
+        public double getX() {
+            return x;
+        }
+
+        @Override
+        public double getY() {
+            return y;
+        }
+
+        @Override
+        public double getWidth() {
+            return width;
+        }
+
+        @Override
+        public double getHeight() {
+            return height;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return width <= 0.0f || height <= 0.0f;
+        }
+
+        /**
+         * Sets the rectangle's data to the given values.
+         * 
+         * @param x
+         *            the x coordinate of the rectangle's upper left corner.
+         * @param y
+         *            the y coordinate of the rectangle's upper left corner.
+         * @param width
+         *            the width of the rectangle.
+         * @param height
+         *            the height of the rectangle.
+         */
+        public void setRect(float x, float y, float width, float height) {
+            this.x = x;
+            this.y = y;
+            this.width = width;
+            this.height = height;
+        }
+
+        @Override
+        public void setRect(double x, double y, double width, double height) {
+            this.x = (float)x;
+            this.y = (float)y;
+            this.width = (float)width;
+            this.height = (float)height;
+        }
+
+        @Override
+        public void setRect(Rectangle2D r) {
+            this.x = (float)r.getX();
+            this.y = (float)r.getY();
+            this.width = (float)r.getWidth();
+            this.height = (float)r.getHeight();
+        }
+
+        @Override
+        public int outcode(double px, double py) {
+            int code = 0;
+
+            if (width <= 0.0f) {
+                code |= OUT_LEFT | OUT_RIGHT;
+            } else if (px < x) {
+                code |= OUT_LEFT;
+            } else if (px > x + width) {
+                code |= OUT_RIGHT;
+            }
+
+            if (height <= 0.0f) {
+                code |= OUT_TOP | OUT_BOTTOM;
+            } else if (py < y) {
+                code |= OUT_TOP;
+            } else if (py > y + height) {
+                code |= OUT_BOTTOM;
+            }
+
+            return code;
+        }
+
+        @Override
+        public Rectangle2D getBounds2D() {
+            return new Float(x, y, width, height);
+        }
+
+        @Override
+        public Rectangle2D createIntersection(Rectangle2D r) {
+            Rectangle2D dst;
+            if (r instanceof Double) {
+                dst = new Rectangle2D.Double();
+            } else {
+                dst = new Rectangle2D.Float();
+            }
+            Rectangle2D.intersect(this, r, dst);
+            return dst;
+        }
+
+        @Override
+        public Rectangle2D createUnion(Rectangle2D r) {
+            Rectangle2D dst;
+            if (r instanceof Double) {
+                dst = new Rectangle2D.Double();
+            } else {
+                dst = new Rectangle2D.Float();
+            }
+            Rectangle2D.union(this, r, dst);
+            return dst;
+        }
+
+        @Override
+        public String toString() {
+            // The output format based on 1.5 release behaviour. It could be
+            // obtained in the following way
+            // System.out.println(new Rectangle2D.Float().toString())
+            return getClass().getName()
+                    + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+        }
+    }
+
+    /**
+     * The Class Double is the subclass of Rectangle2D that represents a
+     * rectangle whose data values are given as doubles (with
+     * double-precision-level precision).
+     * 
+     * @since Android 1.0
+     */
+    public static class Double extends Rectangle2D {
+
+        /**
+         * The x coordinate of the rectangle's upper left corner.
+         */
+        public double x;
+
+        /**
+         * The y coordinate of the rectangle's upper left corner.
+         */
+        public double y;
+
+        /**
+         * The width of the rectangle.
+         */
+        public double width;
+
+        /**
+         * The height of the rectangle.
+         */
+        public double height;
+
+        /**
+         * Instantiates a new empty rectangle with double-precision data fields.
+         */
+        public Double() {
+        }
+
+        /**
+         * Instantiates a new rectangle with the given double values.
+         * 
+         * @param x
+         *            the x coordinate of the rectangle's upper left corner.
+         * @param y
+         *            the y coordinate of the rectangle's upper left corner.
+         * @param width
+         *            the width of the rectangle.
+         * @param height
+         *            the height of the rectangle.
+         */
+        public Double(double x, double y, double width, double height) {
+            setRect(x, y, width, height);
+        }
+
+        @Override
+        public double getX() {
+            return x;
+        }
+
+        @Override
+        public double getY() {
+            return y;
+        }
+
+        @Override
+        public double getWidth() {
+            return width;
+        }
+
+        @Override
+        public double getHeight() {
+            return height;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return width <= 0.0 || height <= 0.0;
+        }
+
+        @Override
+        public void setRect(double x, double y, double width, double height) {
+            this.x = x;
+            this.y = y;
+            this.width = width;
+            this.height = height;
+        }
+
+        @Override
+        public void setRect(Rectangle2D r) {
+            this.x = r.getX();
+            this.y = r.getY();
+            this.width = r.getWidth();
+            this.height = r.getHeight();
+        }
+
+        @Override
+        public int outcode(double px, double py) {
+            int code = 0;
+
+            if (width <= 0.0) {
+                code |= OUT_LEFT | OUT_RIGHT;
+            } else if (px < x) {
+                code |= OUT_LEFT;
+            } else if (px > x + width) {
+                code |= OUT_RIGHT;
+            }
+
+            if (height <= 0.0) {
+                code |= OUT_TOP | OUT_BOTTOM;
+            } else if (py < y) {
+                code |= OUT_TOP;
+            } else if (py > y + height) {
+                code |= OUT_BOTTOM;
+            }
+
+            return code;
+        }
+
+        @Override
+        public Rectangle2D getBounds2D() {
+            return new Double(x, y, width, height);
+        }
+
+        @Override
+        public Rectangle2D createIntersection(Rectangle2D r) {
+            Rectangle2D dst = new Rectangle2D.Double();
+            Rectangle2D.intersect(this, r, dst);
+            return dst;
+        }
+
+        @Override
+        public Rectangle2D createUnion(Rectangle2D r) {
+            Rectangle2D dest = new Rectangle2D.Double();
+            Rectangle2D.union(this, r, dest);
+            return dest;
+        }
+
+        @Override
+        public String toString() {
+            // The output format based on 1.5 release behaviour. It could be
+            // obtained in the following way
+            // System.out.println(new Rectangle2D.Double().toString())
+            return getClass().getName()
+                    + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+        }
+    }
+
+    /**
+     * The Class Iterator provides access to the coordinates of the
+     * Rectangle2D's boundary modified by an AffineTransform.
+     */
+    class Iterator implements PathIterator {
+
+        /**
+         * The x coordinate of the rectangle's upper left corner.
+         */
+        double x;
+
+        /**
+         * The y coordinate of the rectangle's upper left corner.
+         */
+        double y;
+
+        /**
+         * The width of the rectangle.
+         */
+        double width;
+
+        /**
+         * The height of the rectangle.
+         */
+        double height;
+
+        /**
+         * The AffineTransform that is used to modify the coordinates that are
+         * returned by the path iterator.
+         */
+        AffineTransform t;
+
+        /**
+         * The current segment index.
+         */
+        int index;
+
+        /**
+         * Constructs a new Rectangle2D.Iterator for given rectangle and
+         * transformation.
+         * 
+         * @param r
+         *            the source Rectangle2D object.
+         * @param at
+         *            the AffineTransform object to apply to the coordinates
+         *            before returning them.
+         */
+        Iterator(Rectangle2D r, AffineTransform at) {
+            this.x = r.getX();
+            this.y = r.getY();
+            this.width = r.getWidth();
+            this.height = r.getHeight();
+            this.t = at;
+            if (width < 0.0 || height < 0.0) {
+                index = 6;
+            }
+        }
+
+        public int getWindingRule() {
+            return WIND_NON_ZERO;
+        }
+
+        public boolean isDone() {
+            return index > 5;
+        }
+
+        public void next() {
+            index++;
+        }
+
+        public int currentSegment(double[] coords) {
+            if (isDone()) {
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            if (index == 5) {
+                return SEG_CLOSE;
+            }
+            int type;
+            if (index == 0) {
+                type = SEG_MOVETO;
+                coords[0] = x;
+                coords[1] = y;
+            } else {
+                type = SEG_LINETO;
+                switch (index) {
+                    case 1:
+                        coords[0] = x + width;
+                        coords[1] = y;
+                        break;
+                    case 2:
+                        coords[0] = x + width;
+                        coords[1] = y + height;
+                        break;
+                    case 3:
+                        coords[0] = x;
+                        coords[1] = y + height;
+                        break;
+                    case 4:
+                        coords[0] = x;
+                        coords[1] = y;
+                        break;
+                }
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, 1);
+            }
+            return type;
+        }
+
+        public int currentSegment(float[] coords) {
+            if (isDone()) {
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            if (index == 5) {
+                return SEG_CLOSE;
+            }
+            int type;
+            if (index == 0) {
+                coords[0] = (float)x;
+                coords[1] = (float)y;
+                type = SEG_MOVETO;
+            } else {
+                type = SEG_LINETO;
+                switch (index) {
+                    case 1:
+                        coords[0] = (float)(x + width);
+                        coords[1] = (float)y;
+                        break;
+                    case 2:
+                        coords[0] = (float)(x + width);
+                        coords[1] = (float)(y + height);
+                        break;
+                    case 3:
+                        coords[0] = (float)x;
+                        coords[1] = (float)(y + height);
+                        break;
+                    case 4:
+                        coords[0] = (float)x;
+                        coords[1] = (float)y;
+                        break;
+                }
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, 1);
+            }
+            return type;
+        }
+
+    }
+
+    /**
+     * Instantiates a new Rectangle2D.
+     */
+    protected Rectangle2D() {
+    }
+
+    /**
+     * Sets the rectangle's location and dimension.
+     * 
+     * @param x
+     *            the x coordinate of the rectangle's upper left corner.
+     * @param y
+     *            the y coordinate of the rectangle's upper left corner.
+     * @param width
+     *            the width of the rectangle.
+     * @param height
+     *            the height of the rectangle.
+     */
+    public abstract void setRect(double x, double y, double width, double height);
+
+    /**
+     * Gets the location of the point with respect to the rectangle and packs
+     * the information into a single integer using the bitmasks
+     * {@link Rectangle2D#OUT_LEFT}, {@link Rectangle2D#OUT_RIGHT},
+     * {@link Rectangle2D#OUT_TOP}, and {@link Rectangle2D#OUT_BOTTOM}. If the
+     * rectangle has zero or negative width, then every point is regarded as
+     * being both to the left and to the right of the rectangle. Similarly, if
+     * the height is zero or negative then all points are considered to be both
+     * both above and below it.
+     * 
+     * @param x
+     *            the x coordinate of the point to check.
+     * @param y
+     *            the y coordinate of the point to check.
+     * @return the point's location with respect to the rectangle.
+     */
+    public abstract int outcode(double x, double y);
+
+    /**
+     * Creates an new rectangle that is the intersection of this rectangle with
+     * the given rectangle. The resulting rectangle may be empty. The data of
+     * this rectangle is left unchanged.
+     * 
+     * @param r
+     *            the rectangle to intersect with this rectangle.
+     * @return the new rectangle given by intersection.
+     */
+    public abstract Rectangle2D createIntersection(Rectangle2D r);
+
+    /**
+     * Creates an new rectangle that is the union of this rectangle with the
+     * given rectangle. The new rectangle is the smallest rectangle which
+     * contains both this rectangle and the rectangle specified as a parameter.
+     * The data of this rectangle is left unchanged.
+     * 
+     * @param r
+     *            the rectangle to combine with this rectangle.
+     * @return the new rectangle given by union.
+     */
+    public abstract Rectangle2D createUnion(Rectangle2D r);
+
+    /**
+     * Sets the data of this rectangle to match the data of the given rectangle.
+     * 
+     * @param r
+     *            the rectangle whose data is to be copied into this rectangle's
+     *            fields.
+     */
+    public void setRect(Rectangle2D r) {
+        setRect(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+    }
+
+    @Override
+    public void setFrame(double x, double y, double width, double height) {
+        setRect(x, y, width, height);
+    }
+
+    public Rectangle2D getBounds2D() {
+        return (Rectangle2D)clone();
+    }
+
+    /**
+     * Determines whether any part of the line segment between (and including)
+     * the two given points touches any part of the rectangle, including its
+     * boundary.
+     * 
+     * @param x1
+     *            the x coordinate of one of the points that determines the line
+     *            segment to test.
+     * @param y1
+     *            the y coordinate of one of the points that determines the line
+     *            segment to test.
+     * @param x2
+     *            the x coordinate of one of the points that determines the line
+     *            segment to test.
+     * @param y2
+     *            the y coordinate of one of the points that determines the line
+     *            segment to test.
+     * @return true, if at least one point of the line segment between the two
+     *         points matches any point of the interior of the rectangle or the
+     *         rectangle's boundary.
+     */
+    public boolean intersectsLine(double x1, double y1, double x2, double y2) {
+        double rx1 = getX();
+        double ry1 = getY();
+        double rx2 = rx1 + getWidth();
+        double ry2 = ry1 + getHeight();
+        return (rx1 <= x1 && x1 <= rx2 && ry1 <= y1 && y1 <= ry2)
+                || (rx1 <= x2 && x2 <= rx2 && ry1 <= y2 && y2 <= ry2)
+                || Line2D.linesIntersect(rx1, ry1, rx2, ry2, x1, y1, x2, y2)
+                || Line2D.linesIntersect(rx2, ry1, rx1, ry2, x1, y1, x2, y2);
+    }
+
+    /**
+     * Determines whether any part of the specified line segment touches any
+     * part of the rectangle, including its boundary.
+     * 
+     * @param l
+     *            the line segment to test.
+     * @return true, if at least one point of the given line segment matches any
+     *         point of the interior of the rectangle or the rectangle's
+     *         boundary.
+     */
+    public boolean intersectsLine(Line2D l) {
+        return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l.getY2());
+    }
+
+    /**
+     * Gets the location of the point with respect to the rectangle and packs
+     * the information into a single integer using the bitmasks
+     * {@link Rectangle2D#OUT_LEFT}, {@link Rectangle2D#OUT_RIGHT},
+     * {@link Rectangle2D#OUT_TOP}, and {@link Rectangle2D#OUT_BOTTOM}. If the
+     * rectangle has zero or negative width, then every point is regarded as
+     * being both to the left and to the right of the rectangle. Similarly, if
+     * the height is zero or negative then all points are considered to be both
+     * both above and below it.
+     * 
+     * @param p
+     *            the point to check.
+     * @return the point's location with respect to the rectangle.
+     */
+    public int outcode(Point2D p) {
+        return outcode(p.getX(), p.getY());
+    }
+
+    public boolean contains(double x, double y) {
+        if (isEmpty()) {
+            return false;
+        }
+
+        double x1 = getX();
+        double y1 = getY();
+        double x2 = x1 + getWidth();
+        double y2 = y1 + getHeight();
+
+        return x1 <= x && x < x2 && y1 <= y && y < y2;
+    }
+
+    public boolean intersects(double x, double y, double width, double height) {
+        if (isEmpty() || width <= 0.0 || height <= 0.0) {
+            return false;
+        }
+
+        double x1 = getX();
+        double y1 = getY();
+        double x2 = x1 + getWidth();
+        double y2 = y1 + getHeight();
+
+        return x + width > x1 && x < x2 && y + height > y1 && y < y2;
+    }
+
+    public boolean contains(double x, double y, double width, double height) {
+        if (isEmpty() || width <= 0.0 || height <= 0.0) {
+            return false;
+        }
+
+        double x1 = getX();
+        double y1 = getY();
+        double x2 = x1 + getWidth();
+        double y2 = y1 + getHeight();
+
+        return x1 <= x && x + width <= x2 && y1 <= y && y + height <= y2;
+    }
+
+    /**
+     * Changes the data values of the destination rectangle to match the
+     * intersection of the two source rectangles, leaving the two source
+     * rectangles unchanged. The resulting rectangle may be empty.
+     * 
+     * @param src1
+     *            one of the two source rectangles giving the data to intersect.
+     * @param src2
+     *            one of the two source rectangles giving the data to intersect.
+     * @param dst
+     *            the destination object where the data of the intersection is
+     *            written.
+     */
+    public static void intersect(Rectangle2D src1, Rectangle2D src2, Rectangle2D dst) {
+        double x1 = Math.max(src1.getMinX(), src2.getMinX());
+        double y1 = Math.max(src1.getMinY(), src2.getMinY());
+        double x2 = Math.min(src1.getMaxX(), src2.getMaxX());
+        double y2 = Math.min(src1.getMaxY(), src2.getMaxY());
+        dst.setFrame(x1, y1, x2 - x1, y2 - y1);
+    }
+
+    /**
+     * Changes the data values of the destination rectangle to match the union
+     * of the two source rectangles, leaving the two source rectangles
+     * unchanged. The union is the smallest rectangle that completely covers the
+     * two source rectangles.
+     * 
+     * @param src1
+     *            one of the two source rectangles giving the data.
+     * @param src2
+     *            one of the two source rectangles giving the data.
+     * @param dst
+     *            the destination object where the data of the union is written.
+     */
+    public static void union(Rectangle2D src1, Rectangle2D src2, Rectangle2D dst) {
+        double x1 = Math.min(src1.getMinX(), src2.getMinX());
+        double y1 = Math.min(src1.getMinY(), src2.getMinY());
+        double x2 = Math.max(src1.getMaxX(), src2.getMaxX());
+        double y2 = Math.max(src1.getMaxY(), src2.getMaxY());
+        dst.setFrame(x1, y1, x2 - x1, y2 - y1);
+    }
+
+    /**
+     * Enlarges the rectangle so that it includes the given point.
+     * 
+     * @param x
+     *            the x coordinate of the new point to be covered by the
+     *            rectangle.
+     * @param y
+     *            the y coordinate of the new point to be covered by the
+     *            rectangle.
+     */
+    public void add(double x, double y) {
+        double x1 = Math.min(getMinX(), x);
+        double y1 = Math.min(getMinY(), y);
+        double x2 = Math.max(getMaxX(), x);
+        double y2 = Math.max(getMaxY(), y);
+        setRect(x1, y1, x2 - x1, y2 - y1);
+    }
+
+    /**
+     * Enlarges the rectangle so that it includes the given point.
+     * 
+     * @param p
+     *            the new point to be covered by the rectangle.
+     */
+    public void add(Point2D p) {
+        add(p.getX(), p.getY());
+    }
+
+    /**
+     * Enlarges the rectangle so that it covers the given rectangle.
+     * 
+     * @param r
+     *            the new rectangle to be covered by this rectangle.
+     */
+    public void add(Rectangle2D r) {
+        union(this, r, this);
+    }
+
+    public PathIterator getPathIterator(AffineTransform t) {
+        return new Iterator(this, t);
+    }
+
+    @Override
+    public PathIterator getPathIterator(AffineTransform t, double flatness) {
+        return new Iterator(this, t);
+    }
+
+    @Override
+    public int hashCode() {
+        HashCode hash = new HashCode();
+        hash.append(getX());
+        hash.append(getY());
+        hash.append(getWidth());
+        hash.append(getHeight());
+        return hash.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof Rectangle2D) {
+            Rectangle2D r = (Rectangle2D)obj;
+            return getX() == r.getX() && getY() == r.getY() && getWidth() == r.getWidth()
+                    && getHeight() == r.getHeight();
+        }
+        return false;
+    }
+
+}
diff --git a/awt/java/awt/geom/RectangularShape.java b/awt/java/awt/geom/RectangularShape.java
new file mode 100644
index 0000000..0b0d05c
--- /dev/null
+++ b/awt/java/awt/geom/RectangularShape.java
@@ -0,0 +1,297 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+/**
+ * The Class RectangularShape represents a Shape whose data is (at least
+ * partially) described by a rectangular frame. This includes shapes which are
+ * obviously rectangular (such as Rectangle2D) as well as shapes like Arc2D
+ * which are largely determined by the rectangle they fit inside.
+ * 
+ * @since Android 1.0
+ */
+public abstract class RectangularShape implements Shape, Cloneable {
+
+    /**
+     * Instantiates a new rectangular shape.
+     */
+    protected RectangularShape() {
+    }
+
+    /**
+     * Gets the x coordinate of the upper left corner of the rectangle.
+     * 
+     * @return the x coordinate of the upper left corner of the rectangle.
+     */
+    public abstract double getX();
+
+    /**
+     * Gets the y coordinate of the upper left corner of the rectangle.
+     * 
+     * @return the y coordinate of the upper left corner of the rectangle.
+     */
+    public abstract double getY();
+
+    /**
+     * Gets the width of the rectangle.
+     * 
+     * @return the width of the rectangle.
+     */
+    public abstract double getWidth();
+
+    /**
+     * Gets the height of the rectangle.
+     * 
+     * @return the height of the rectangle.
+     */
+    public abstract double getHeight();
+
+    /**
+     * Checks if this is an empty rectangle: one with zero as its width or
+     * height.
+     * 
+     * @return true, if the width or height is empty.
+     */
+    public abstract boolean isEmpty();
+
+    /**
+     * Sets the data for the bounding rectangle in terms of double values.
+     * 
+     * @param x
+     *            the x coordinate of the upper left corner of the rectangle.
+     * @param y
+     *            the y coordinate of the upper left corner of the rectangle.
+     * @param w
+     *            the width of the rectangle.
+     * @param h
+     *            the height of the rectangle.
+     */
+    public abstract void setFrame(double x, double y, double w, double h);
+
+    /**
+     * Gets the minimum x value of the bounding rectangle (the x coordinate of
+     * the upper left corner of the rectangle).
+     * 
+     * @return the minimum x value of the bounding rectangle.
+     */
+    public double getMinX() {
+        return getX();
+    }
+
+    /**
+     * Gets the minimum y value of the bounding rectangle (the y coordinate of
+     * the upper left corner of the rectangle).
+     * 
+     * @return the minimum y value of the bounding rectangle.
+     */
+    public double getMinY() {
+        return getY();
+    }
+
+    /**
+     * Gets the maximum x value of the bounding rectangle (the x coordinate of
+     * the upper left corner of the rectangle plus the rectangle's width).
+     * 
+     * @return the maximum x value of the bounding rectangle.
+     */
+    public double getMaxX() {
+        return getX() + getWidth();
+    }
+
+    /**
+     * Gets the maximum y value of the bounding rectangle (the y coordinate of
+     * the upper left corner of the rectangle plus the rectangle's height).
+     * 
+     * @return the maximum y value of the bounding rectangle.
+     */
+    public double getMaxY() {
+        return getY() + getHeight();
+    }
+
+    /**
+     * Gets the x coordinate of the center of the rectangle.
+     * 
+     * @return the x coordinate of the center of the rectangle.
+     */
+    public double getCenterX() {
+        return getX() + getWidth() / 2.0;
+    }
+
+    /**
+     * Gets the y coordinate of the center of the rectangle.
+     * 
+     * @return the y coordinate of the center of the rectangle.
+     */
+    public double getCenterY() {
+        return getY() + getHeight() / 2.0;
+    }
+
+    /**
+     * Places the rectangle's size and location data in a new Rectangle2D object
+     * and returns it.
+     * 
+     * @return the bounding rectangle as a new Rectangle2D object.
+     */
+    public Rectangle2D getFrame() {
+        return new Rectangle2D.Double(getX(), getY(), getWidth(), getHeight());
+    }
+
+    /**
+     * Sets the bounding rectangle in terms of a Point2D which gives its upper
+     * left corner and a Dimension2D object giving its width and height.
+     * 
+     * @param loc
+     *            the new upper left corner coordinate.
+     * @param size
+     *            the new size dimensions.
+     */
+    public void setFrame(Point2D loc, Dimension2D size) {
+        setFrame(loc.getX(), loc.getY(), size.getWidth(), size.getHeight());
+    }
+
+    /**
+     * Sets the bounding rectangle to match the data contained in the specified
+     * Rectangle2D.
+     * 
+     * @param r
+     *            the rectangle that gives the new frame data.
+     */
+    public void setFrame(Rectangle2D r) {
+        setFrame(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+    }
+
+    /**
+     * Sets the framing rectangle given two opposite corners. Any two corners
+     * may be used in any order as long as they are diagonally opposite one
+     * another.
+     * 
+     * @param x1
+     *            the x coordinate of one of the corner points.
+     * @param y1
+     *            the y coordinate of one of the corner points.
+     * @param x2
+     *            the x coordinate of the other corner point.
+     * @param y2
+     *            the y coordinate of the other corner point.
+     */
+    public void setFrameFromDiagonal(double x1, double y1, double x2, double y2) {
+        double rx, ry, rw, rh;
+        if (x1 < x2) {
+            rx = x1;
+            rw = x2 - x1;
+        } else {
+            rx = x2;
+            rw = x1 - x2;
+        }
+        if (y1 < y2) {
+            ry = y1;
+            rh = y2 - y1;
+        } else {
+            ry = y2;
+            rh = y1 - y2;
+        }
+        setFrame(rx, ry, rw, rh);
+    }
+
+    /**
+     * Sets the framing rectangle given two opposite corners. Any two corners
+     * may be used in any order as long as they are diagonally opposite one
+     * another.
+     * 
+     * @param p1
+     *            one of the corner points.
+     * @param p2
+     *            the other corner point.
+     */
+    public void setFrameFromDiagonal(Point2D p1, Point2D p2) {
+        setFrameFromDiagonal(p1.getX(), p1.getY(), p2.getX(), p2.getY());
+    }
+
+    /**
+     * Sets the framing rectangle given the center point and one corner. Any
+     * corner may be used.
+     * 
+     * @param centerX
+     *            the x coordinate of the center point.
+     * @param centerY
+     *            the y coordinate of the center point.
+     * @param cornerX
+     *            the x coordinate of one of the corner points.
+     * @param cornerY
+     *            the y coordinate of one of the corner points.
+     */
+    public void setFrameFromCenter(double centerX, double centerY, double cornerX, double cornerY) {
+        double width = Math.abs(cornerX - centerX);
+        double height = Math.abs(cornerY - centerY);
+        setFrame(centerX - width, centerY - height, width * 2.0, height * 2.0);
+    }
+
+    /**
+     * Sets the framing rectangle given the center point and one corner. Any
+     * corner may be used.
+     * 
+     * @param center
+     *            the center point.
+     * @param corner
+     *            a corner point.
+     */
+    public void setFrameFromCenter(Point2D center, Point2D corner) {
+        setFrameFromCenter(center.getX(), center.getY(), corner.getX(), corner.getY());
+    }
+
+    public boolean contains(Point2D point) {
+        return contains(point.getX(), point.getY());
+    }
+
+    public boolean intersects(Rectangle2D rect) {
+        return intersects(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+    }
+
+    public boolean contains(Rectangle2D rect) {
+        return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+    }
+
+    public Rectangle getBounds() {
+        int x1 = (int)Math.floor(getMinX());
+        int y1 = (int)Math.floor(getMinY());
+        int x2 = (int)Math.ceil(getMaxX());
+        int y2 = (int)Math.ceil(getMaxY());
+        return new Rectangle(x1, y1, x2 - x1, y2 - y1);
+    }
+
+    public PathIterator getPathIterator(AffineTransform t, double flatness) {
+        return new FlatteningPathIterator(getPathIterator(t), flatness);
+    }
+
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+}
diff --git a/awt/java/awt/geom/RoundRectangle2D.java b/awt/java/awt/geom/RoundRectangle2D.java
new file mode 100644
index 0000000..8fbddd6
--- /dev/null
+++ b/awt/java/awt/geom/RoundRectangle2D.java
@@ -0,0 +1,635 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class RoundRectangle2D describes a rectangle with rounded corners with
+ * high-precision data that is appropriate for geometric operations.
+ * 
+ * @since Android 1.0
+ */
+public abstract class RoundRectangle2D extends RectangularShape {
+
+    /**
+     * The Class Float is the subclass of RoundRectangle2D that has all of its
+     * data values stored with float-level precision.
+     * 
+     * @since Android 1.0
+     */
+    public static class Float extends RoundRectangle2D {
+
+        /**
+         * The x coordinate of the rectangle's upper left corner.
+         */
+        public float x;
+
+        /**
+         * The y coordinate of the rectangle's upper left corner.
+         */
+        public float y;
+
+        /**
+         * The width of the rectangle.
+         */
+        public float width;
+
+        /**
+         * The height of the rectangle.
+         */
+        public float height;
+
+        /**
+         * The arc width of the rounded corners.
+         */
+        public float arcwidth;
+
+        /**
+         * The arc height of the rounded corners.
+         */
+        public float archeight;
+
+        /**
+         * Instantiates a new float-valued RoundRectangle2D with its data-values
+         * set to zero.
+         */
+        public Float() {
+        }
+
+        /**
+         * Instantiates a new float-valued RoundRectangle2D with the specified
+         * data values.
+         * 
+         * @param x
+         *            the x coordinate of the rectangle's upper left corner.
+         * @param y
+         *            the y coordinate of the rectangle's upper left corner.
+         * @param width
+         *            the width of the rectangle.
+         * @param height
+         *            the height of the rectangle.
+         * @param arcwidth
+         *            the arc width of the rounded corners.
+         * @param archeight
+         *            the arc height of the rounded corners.
+         */
+        public Float(float x, float y, float width, float height, float arcwidth, float archeight) {
+            setRoundRect(x, y, width, height, arcwidth, archeight);
+        }
+
+        @Override
+        public double getX() {
+            return x;
+        }
+
+        @Override
+        public double getY() {
+            return y;
+        }
+
+        @Override
+        public double getWidth() {
+            return width;
+        }
+
+        @Override
+        public double getHeight() {
+            return height;
+        }
+
+        @Override
+        public double getArcWidth() {
+            return arcwidth;
+        }
+
+        @Override
+        public double getArcHeight() {
+            return archeight;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return width <= 0.0f || height <= 0.0f;
+        }
+
+        /**
+         * Sets the data of the round rectangle.
+         * 
+         * @param x
+         *            the x coordinate of the rectangle's upper left corner.
+         * @param y
+         *            the y coordinate of the rectangle's upper left corner.
+         * @param width
+         *            the width of the rectangle.
+         * @param height
+         *            the height of the rectangle.
+         * @param arcwidth
+         *            the arc width of the rounded corners.
+         * @param archeight
+         *            the arc height of the rounded corners.
+         */
+        public void setRoundRect(float x, float y, float width, float height, float arcwidth,
+                float archeight) {
+            this.x = x;
+            this.y = y;
+            this.width = width;
+            this.height = height;
+            this.arcwidth = arcwidth;
+            this.archeight = archeight;
+        }
+
+        @Override
+        public void setRoundRect(double x, double y, double width, double height, double arcwidth,
+                double archeight) {
+            this.x = (float)x;
+            this.y = (float)y;
+            this.width = (float)width;
+            this.height = (float)height;
+            this.arcwidth = (float)arcwidth;
+            this.archeight = (float)archeight;
+        }
+
+        @Override
+        public void setRoundRect(RoundRectangle2D rr) {
+            this.x = (float)rr.getX();
+            this.y = (float)rr.getY();
+            this.width = (float)rr.getWidth();
+            this.height = (float)rr.getHeight();
+            this.arcwidth = (float)rr.getArcWidth();
+            this.archeight = (float)rr.getArcHeight();
+        }
+
+        public Rectangle2D getBounds2D() {
+            return new Rectangle2D.Float(x, y, width, height);
+        }
+    }
+
+    /**
+     * The Class Double is the subclass of RoundRectangle2D that has all of its
+     * data values stored with double-level precision.
+     * 
+     * @since Android 1.0
+     */
+    public static class Double extends RoundRectangle2D {
+
+        /**
+         * The x coordinate of the rectangle's upper left corner.
+         */
+        public double x;
+
+        /**
+         * The y coordinate of the rectangle's upper left corner.
+         */
+        public double y;
+
+        /**
+         * The width of the rectangle.
+         */
+        public double width;
+
+        /**
+         * The height of the rectangle.
+         */
+        public double height;
+
+        /**
+         * The arc width of the rounded corners.
+         */
+        public double arcwidth;
+
+        /**
+         * The arc height of the rounded corners.
+         */
+        public double archeight;
+
+        /**
+         * Instantiates a new double-valued RoundRectangle2D with its
+         * data-values set to zero.
+         */
+        public Double() {
+        }
+
+        /**
+         * Instantiates a new double-valued RoundRectangle2D with the specified
+         * data values.
+         * 
+         * @param x
+         *            the x coordinate of the rectangle's upper left corner.
+         * @param y
+         *            the y coordinate of the rectangle's upper left corner.
+         * @param width
+         *            the width of the rectangle.
+         * @param height
+         *            the height of the rectangle.
+         * @param arcwidth
+         *            the arc width of the rounded corners.
+         * @param archeight
+         *            the arc height of the rounded corners.
+         */
+        public Double(double x, double y, double width, double height, double arcwidth,
+                double archeight) {
+            setRoundRect(x, y, width, height, arcwidth, archeight);
+        }
+
+        @Override
+        public double getX() {
+            return x;
+        }
+
+        @Override
+        public double getY() {
+            return y;
+        }
+
+        @Override
+        public double getWidth() {
+            return width;
+        }
+
+        @Override
+        public double getHeight() {
+            return height;
+        }
+
+        @Override
+        public double getArcWidth() {
+            return arcwidth;
+        }
+
+        @Override
+        public double getArcHeight() {
+            return archeight;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return width <= 0.0 || height <= 0.0;
+        }
+
+        @Override
+        public void setRoundRect(double x, double y, double width, double height, double arcwidth,
+                double archeight) {
+            this.x = x;
+            this.y = y;
+            this.width = width;
+            this.height = height;
+            this.arcwidth = arcwidth;
+            this.archeight = archeight;
+        }
+
+        @Override
+        public void setRoundRect(RoundRectangle2D rr) {
+            this.x = rr.getX();
+            this.y = rr.getY();
+            this.width = rr.getWidth();
+            this.height = rr.getHeight();
+            this.arcwidth = rr.getArcWidth();
+            this.archeight = rr.getArcHeight();
+        }
+
+        public Rectangle2D getBounds2D() {
+            return new Rectangle2D.Double(x, y, width, height);
+        }
+    }
+
+    /*
+     * RoundRectangle2D path iterator
+     */
+    /**
+     * The subclass of PathIterator to traverse a RoundRectangle2D.
+     */
+    class Iterator implements PathIterator {
+
+        /*
+         * Path for round corners generated the same way as Ellipse2D
+         */
+
+        /**
+         * The coefficient to calculate control points of Bezier curves.
+         */
+        double u = 0.5 - 2.0 / 3.0 * (Math.sqrt(2.0) - 1.0);
+
+        /**
+         * The points coordinates calculation table.
+         */
+        double points[][] = {
+                {
+                        0.0, 0.5, 0.0, 0.0
+                }, // MOVETO
+                {
+                        1.0, -0.5, 0.0, 0.0
+                }, // LINETO
+                {
+                        1.0, -u, 0.0, 0.0, // CUBICTO
+                        1.0, 0.0, 0.0, u, 1.0, 0.0, 0.0, 0.5
+                }, {
+                        1.0, 0.0, 1.0, -0.5
+                }, // LINETO
+                {
+                        1.0, 0.0, 1.0, -u, // CUBICTO
+                        1.0, -u, 1.0, 0.0, 1.0, -0.5, 1.0, 0.0
+                }, {
+                        0.0, 0.5, 1.0, 0.0
+                }, // LINETO
+                {
+                        0.0, u, 1.0, 0.0, // CUBICTO
+                        0.0, 0.0, 1.0, -u, 0.0, 0.0, 1.0, -0.5
+                }, {
+                        0.0, 0.0, 0.0, 0.5
+                }, // LINETO
+                {
+                        0.0, 0.0, 0.0, u, // CUBICTO
+                        0.0, u, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0
+                }
+        };
+
+        /**
+         * The segment types correspond to points array.
+         */
+        int types[] = {
+                SEG_MOVETO, SEG_LINETO, SEG_CUBICTO, SEG_LINETO, SEG_CUBICTO, SEG_LINETO,
+                SEG_CUBICTO, SEG_LINETO, SEG_CUBICTO
+        };
+
+        /**
+         * The x coordinate of left-upper corner of the round rectangle bounds.
+         */
+        double x;
+
+        /**
+         * The y coordinate of left-upper corner of the round rectangle bounds.
+         */
+        double y;
+
+        /**
+         * The width of the round rectangle bounds.
+         */
+        double width;
+
+        /**
+         * The height of the round rectangle bounds.
+         */
+        double height;
+
+        /**
+         * The width of arc corners of the round rectangle.
+         */
+        double aw;
+
+        /**
+         * The height of arc corners of the round rectangle.
+         */
+        double ah;
+
+        /**
+         * The path iterator transformation.
+         */
+        AffineTransform t;
+
+        /**
+         * The current segment index.
+         */
+        int index;
+
+        /**
+         * Constructs a new RoundRectangle2D.Iterator for given round rectangle
+         * and transformation.
+         * 
+         * @param rr
+         *            - the source RoundRectangle2D object
+         * @param at
+         *            - the AffineTransform object to apply rectangle path
+         */
+        Iterator(RoundRectangle2D rr, AffineTransform at) {
+            this.x = rr.getX();
+            this.y = rr.getY();
+            this.width = rr.getWidth();
+            this.height = rr.getHeight();
+            this.aw = Math.min(width, rr.getArcWidth());
+            this.ah = Math.min(height, rr.getArcHeight());
+            this.t = at;
+            if (width < 0.0 || height < 0.0 || aw < 0.0 || ah < 0.0) {
+                index = points.length;
+            }
+        }
+
+        public int getWindingRule() {
+            return WIND_NON_ZERO;
+        }
+
+        public boolean isDone() {
+            return index > points.length;
+        }
+
+        public void next() {
+            index++;
+        }
+
+        public int currentSegment(double[] coords) {
+            if (isDone()) {
+                // awt.4B=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            if (index == points.length) {
+                return SEG_CLOSE;
+            }
+            int j = 0;
+            double p[] = points[index];
+            for (int i = 0; i < p.length; i += 4) {
+                coords[j++] = x + p[i + 0] * width + p[i + 1] * aw;
+                coords[j++] = y + p[i + 2] * height + p[i + 3] * ah;
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, j / 2);
+            }
+            return types[index];
+        }
+
+        public int currentSegment(float[] coords) {
+            if (isDone()) {
+                // awt.4B=Iterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            if (index == points.length) {
+                return SEG_CLOSE;
+            }
+            int j = 0;
+            double p[] = points[index];
+            for (int i = 0; i < p.length; i += 4) {
+                coords[j++] = (float)(x + p[i + 0] * width + p[i + 1] * aw);
+                coords[j++] = (float)(y + p[i + 2] * height + p[i + 3] * ah);
+            }
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, j / 2);
+            }
+            return types[index];
+        }
+
+    }
+
+    /**
+     * Instantiates a new RoundRectangle2D.
+     */
+    protected RoundRectangle2D() {
+    }
+
+    /**
+     * Gets the arc width.
+     * 
+     * @return the arc width.
+     */
+    public abstract double getArcWidth();
+
+    /**
+     * Gets the arc height.
+     * 
+     * @return the arc height.
+     */
+    public abstract double getArcHeight();
+
+    /**
+     * Sets the data of the RoundRectangle2D.
+     * 
+     * @param x
+     *            the x coordinate of the rectangle's upper left corner.
+     * @param y
+     *            the y coordinate of the rectangle's upper left corner.
+     * @param width
+     *            the width of the rectangle.
+     * @param height
+     *            the height of the rectangle.
+     * @param arcWidth
+     *            the arc width of the rounded corners.
+     * @param arcHeight
+     *            the arc height of the rounded corners.
+     */
+    public abstract void setRoundRect(double x, double y, double width, double height,
+            double arcWidth, double arcHeight);
+
+    /**
+     * Sets the data of the RoundRectangle2D by copying the values from an
+     * existing RoundRectangle2D.
+     * 
+     * @param rr
+     *            the round rectangle to copy the data from.
+     * @throws NullPointerException
+     *             if rr is null.
+     */
+    public void setRoundRect(RoundRectangle2D rr) {
+        setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(), rr.getArcWidth(), rr
+                .getArcHeight());
+    }
+
+    @Override
+    public void setFrame(double x, double y, double width, double height) {
+        setRoundRect(x, y, width, height, getArcWidth(), getArcHeight());
+    }
+
+    public boolean contains(double px, double py) {
+        if (isEmpty()) {
+            return false;
+        }
+
+        double rx1 = getX();
+        double ry1 = getY();
+        double rx2 = rx1 + getWidth();
+        double ry2 = ry1 + getHeight();
+
+        if (px < rx1 || px >= rx2 || py < ry1 || py >= ry2) {
+            return false;
+        }
+
+        double aw = getArcWidth() / 2.0;
+        double ah = getArcHeight() / 2.0;
+
+        double cx, cy;
+
+        if (px < rx1 + aw) {
+            cx = rx1 + aw;
+        } else if (px > rx2 - aw) {
+            cx = rx2 - aw;
+        } else {
+            return true;
+        }
+
+        if (py < ry1 + ah) {
+            cy = ry1 + ah;
+        } else if (py > ry2 - ah) {
+            cy = ry2 - ah;
+        } else {
+            return true;
+        }
+
+        px = (px - cx) / aw;
+        py = (py - cy) / ah;
+        return px * px + py * py <= 1.0;
+    }
+
+    public boolean intersects(double rx, double ry, double rw, double rh) {
+        if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+            return false;
+        }
+
+        double x1 = getX();
+        double y1 = getY();
+        double x2 = x1 + getWidth();
+        double y2 = y1 + getHeight();
+
+        double rx1 = rx;
+        double ry1 = ry;
+        double rx2 = rx + rw;
+        double ry2 = ry + rh;
+
+        if (rx2 < x1 || x2 < rx1 || ry2 < y1 || y2 < ry1) {
+            return false;
+        }
+
+        double cx = (x1 + x2) / 2.0;
+        double cy = (y1 + y2) / 2.0;
+
+        double nx = cx < rx1 ? rx1 : (cx > rx2 ? rx2 : cx);
+        double ny = cy < ry1 ? ry1 : (cy > ry2 ? ry2 : cy);
+
+        return contains(nx, ny);
+    }
+
+    public boolean contains(double rx, double ry, double rw, double rh) {
+        if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+            return false;
+        }
+
+        double rx1 = rx;
+        double ry1 = ry;
+        double rx2 = rx + rw;
+        double ry2 = ry + rh;
+
+        return contains(rx1, ry1) && contains(rx2, ry1) && contains(rx2, ry2) && contains(rx1, ry2);
+    }
+
+    public PathIterator getPathIterator(AffineTransform at) {
+        return new Iterator(this, at);
+    }
+
+}
diff --git a/awt/java/awt/geom/package.html b/awt/java/awt/geom/package.html
new file mode 100644
index 0000000..e3a236e
--- /dev/null
+++ b/awt/java/awt/geom/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      This package contains classes and interfaces related to Java2D shapes and geometry.
+    </p>
+    @since Android 1.0
+  </body>
+</html>
diff --git a/awt/java/awt/im/InputContext.java b/awt/java/awt/im/InputContext.java
new file mode 100644
index 0000000..cce5148
--- /dev/null
+++ b/awt/java/awt/im/InputContext.java
@@ -0,0 +1,83 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im;
+
+import java.awt.AWTEvent;
+//???AWT: import java.awt.Component;
+import java.util.Locale;
+
+import org.apache.harmony.awt.im.InputMethodContext;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class InputContext {
+    protected InputContext() {
+    }
+
+    public static InputContext getInstance() {
+        return new InputMethodContext();
+    }
+
+    public void dispatchEvent(AWTEvent event) {
+    }
+
+    public void dispose() {
+    }
+
+    public void endComposition() {
+    }
+
+    public Object getInputMethodControlObject() {
+        return null;
+    }
+
+    public Locale getLocale() {
+        return null;
+    }
+
+    public boolean isCompositionEnabled() {
+        return false;
+    }
+
+    public void reconvert() {
+    }
+
+    //???AWT
+    /*
+    public void removeNotify(Component client) {
+    }
+    */
+
+    public boolean selectInputMethod(Locale locale) {
+        return false;
+    }
+
+    public void setCharacterSubsets(Character.Subset[] subsets) {
+    }
+    
+    public void setCompositionEnabled(boolean enable) {
+    }
+}
+
diff --git a/awt/java/awt/im/InputMethodHighlight.java b/awt/java/awt/im/InputMethodHighlight.java
new file mode 100644
index 0000000..865d47c
--- /dev/null
+++ b/awt/java/awt/im/InputMethodHighlight.java
@@ -0,0 +1,95 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt.im;
+
+import java.util.Map;
+import java.awt.font.TextAttribute;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public class InputMethodHighlight {
+
+    public static final int RAW_TEXT = 0;
+
+    public static final int CONVERTED_TEXT = 1;
+
+    public static final InputMethodHighlight
+        UNSELECTED_RAW_TEXT_HIGHLIGHT = new InputMethodHighlight(false, RAW_TEXT);
+
+    public static final InputMethodHighlight
+        SELECTED_RAW_TEXT_HIGHLIGHT = new InputMethodHighlight(true, RAW_TEXT);
+
+    public static final InputMethodHighlight
+        UNSELECTED_CONVERTED_TEXT_HIGHLIGHT = 
+            new InputMethodHighlight(false, CONVERTED_TEXT);
+
+    public static final InputMethodHighlight
+        SELECTED_CONVERTED_TEXT_HIGHLIGHT = 
+            new InputMethodHighlight(true, CONVERTED_TEXT);
+    
+    private boolean selected;
+    private int state;
+    private int variation;
+    private Map<TextAttribute,?> style;
+
+    public InputMethodHighlight(boolean selected, int state, int variation) {
+        this(selected, state, variation, null);
+    }
+
+    public InputMethodHighlight(boolean selected, int state,
+                                int variation, Map<java.awt.font.TextAttribute, ?> style) {
+        if ((state != RAW_TEXT) && (state != CONVERTED_TEXT)) {
+            // awt.20B=unknown input method highlight state
+            throw new IllegalArgumentException(Messages.getString("awt.20B")); //$NON-NLS-1$
+        }
+        this.selected = selected;
+        this.state = state;
+        this.variation = variation;
+        this.style = style;
+    }
+
+    public InputMethodHighlight(boolean selected, int state) {
+        this(selected, state, 0, null);
+    }
+
+    public int getState() {
+        return state;
+    }
+
+    public Map<java.awt.font.TextAttribute, ?> getStyle() {
+        return style;
+    }
+
+    public int getVariation() {
+        return variation;
+    }
+
+    public boolean isSelected() {
+        return selected;
+    }
+}
+
diff --git a/awt/java/awt/im/InputMethodRequests.java b/awt/java/awt/im/InputMethodRequests.java
new file mode 100644
index 0000000..b12d397
--- /dev/null
+++ b/awt/java/awt/im/InputMethodRequests.java
@@ -0,0 +1,49 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im;
+
+import java.awt.Rectangle;
+import java.awt.font.TextHitInfo;
+import java.text.AttributedCharacterIterator;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface InputMethodRequests {
+
+    public AttributedCharacterIterator cancelLatestCommittedText(AttributedCharacterIterator.Attribute[] attributes);
+
+    public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex, AttributedCharacterIterator.Attribute[] attributes);
+
+    public int getCommittedTextLength();
+
+    public int getInsertPositionOffset();
+
+    public TextHitInfo getLocationOffset(int x, int y);
+
+    public AttributedCharacterIterator getSelectedText(AttributedCharacterIterator.Attribute[] attributes);
+
+    public Rectangle getTextLocation(TextHitInfo offset);
+}
+
diff --git a/awt/java/awt/im/InputSubset.java b/awt/java/awt/im/InputSubset.java
new file mode 100644
index 0000000..708881e
--- /dev/null
+++ b/awt/java/awt/im/InputSubset.java
@@ -0,0 +1,59 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt.im;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public final class InputSubset extends Character.Subset {
+
+    public static final InputSubset LATIN = new InputSubset("LATIN"); //$NON-NLS-1$
+
+    public static final InputSubset 
+        LATIN_DIGITS = new InputSubset("LATIN_DIGITS"); //$NON-NLS-1$
+
+    public static final InputSubset 
+        TRADITIONAL_HANZI = new InputSubset("TRADITIONAL_HANZI"); //$NON-NLS-1$
+
+    public static final InputSubset 
+        SIMPLIFIED_HANZI = new InputSubset("SIMPLIFIED_HANZI"); //$NON-NLS-1$
+
+    public static final InputSubset KANJI = new InputSubset("KANJI"); //$NON-NLS-1$
+
+    public static final InputSubset HANJA = new InputSubset("HANJA"); //$NON-NLS-1$
+
+    public static final InputSubset 
+        HALFWIDTH_KATAKANA = new InputSubset("HALFWIDTH_KATAKANA"); //$NON-NLS-1$
+
+    public static final InputSubset 
+        FULLWIDTH_LATIN = new InputSubset("FULLWIDTH_LATIN"); //$NON-NLS-1$
+
+    public static final InputSubset 
+        FULLWIDTH_DIGITS = new InputSubset("FULLWIDTH_DIGITS"); //$NON-NLS-1$
+
+    private InputSubset(String name) {
+        super(name);
+    }
+}
+
diff --git a/awt/java/awt/im/spi/InputMethod.java b/awt/java/awt/im/spi/InputMethod.java
new file mode 100644
index 0000000..67a8834
--- /dev/null
+++ b/awt/java/awt/im/spi/InputMethod.java
@@ -0,0 +1,67 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im.spi;
+
+import java.awt.AWTEvent;
+import java.awt.Rectangle;
+import java.util.Locale;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface InputMethod {
+
+    public void activate();
+
+    public void deactivate(boolean isTemporary);
+
+    public void dispatchEvent(AWTEvent event);
+
+    public void dispose();
+
+    public void endComposition();
+
+    public Object getControlObject();
+
+    public Locale getLocale();
+
+    public void hideWindows();
+
+    public boolean isCompositionEnabled();
+
+    public void notifyClientWindowChange(Rectangle bounds);
+
+    public void reconvert();
+
+    public void removeNotify();
+
+    public void setCharacterSubsets(Character.Subset[] subsets);
+
+    public void setCompositionEnabled(boolean enable);
+
+    public void setInputMethodContext(InputMethodContext context);
+
+    public boolean setLocale(Locale locale);
+}
+
diff --git a/awt/java/awt/im/spi/InputMethodContext.java b/awt/java/awt/im/spi/InputMethodContext.java
new file mode 100644
index 0000000..bfc773c
--- /dev/null
+++ b/awt/java/awt/im/spi/InputMethodContext.java
@@ -0,0 +1,46 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im.spi;
+
+//???AWT: import java.awt.Window;
+import java.awt.font.TextHitInfo;
+import java.awt.im.InputMethodRequests;
+import java.text.AttributedCharacterIterator;
+//???AWT: import javax.swing.JFrame;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface InputMethodContext extends InputMethodRequests {
+
+//    ???AWT: public JFrame createInputMethodJFrame(String title, boolean attachToInputContext);
+
+//    ???AWT: public Window createInputMethodWindow(String title, boolean attachToInputContext);
+
+    public void dispatchInputMethodEvent(int id, AttributedCharacterIterator text, int committedCharacterCount, TextHitInfo caret, TextHitInfo visiblePosition);
+
+    public void enableClientWindowNotification(InputMethod inputMethod, boolean enable);
+
+}
+
diff --git a/awt/java/awt/im/spi/InputMethodDescriptor.java b/awt/java/awt/im/spi/InputMethodDescriptor.java
new file mode 100644
index 0000000..c800bc1
--- /dev/null
+++ b/awt/java/awt/im/spi/InputMethodDescriptor.java
@@ -0,0 +1,46 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im.spi;
+
+import java.awt.AWTException;
+import java.awt.Image;
+import java.util.Locale;
+
+/**
+ * This class is not supported in Android 1.0. It is merely provided to maintain
+ * interface compatibility with desktop Java implementations.
+ * 
+ * @since Android 1.0
+ */
+public interface InputMethodDescriptor {
+
+    public Locale[] getAvailableLocales() throws AWTException;
+
+    public InputMethod createInputMethod() throws Exception;
+
+    public String getInputMethodDisplayName(Locale inputLocale, Locale displayLanguage);
+
+    public Image getInputMethodIcon(Locale inputLocale);
+
+    public boolean hasDynamicLocaleList();
+
+}
+
diff --git a/awt/java/awt/image/AffineTransformOp.java b/awt/java/awt/image/AffineTransformOp.java
new file mode 100644
index 0000000..db25e1a
--- /dev/null
+++ b/awt/java/awt/image/AffineTransformOp.java
@@ -0,0 +1,618 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky, Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.*;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The AffineTransform class translates coordinates from 2D coordinates in the
+ * source image or Raster to 2D coordinates in the destination image or Raster
+ * using affine transformation. The number of bands in the source Raster should
+ * equal to the number of bands in the destination Raster.
+ * 
+ * @since Android 1.0
+ */
+public class AffineTransformOp implements BufferedImageOp, RasterOp {
+
+    /**
+     * The Constant TYPE_NEAREST_NEIGHBOR indicates nearest-neighbor
+     * interpolation type.
+     */
+    public static final int TYPE_NEAREST_NEIGHBOR = 1;
+
+    /**
+     * The Constant TYPE_BILINEAR indicates bilinear interpolation type.
+     */
+    public static final int TYPE_BILINEAR = 2;
+
+    /**
+     * The Constant TYPE_BICUBIC indicates bi-cubic interpolation type.
+     */
+    public static final int TYPE_BICUBIC = 3;
+
+    /**
+     * The i type.
+     */
+    private int iType; // interpolation type
+
+    /**
+     * The at.
+     */
+    private AffineTransform at;
+
+    /**
+     * The hints.
+     */
+    private RenderingHints hints;
+
+    static {
+        // TODO - uncomment
+        // System.loadLibrary("imageops");
+    }
+
+    /**
+     * Instantiates a new AffineTransformOp with the specified AffineTransform
+     * and RenderingHints object which defines the interpolation type.
+     * 
+     * @param xform
+     *            the AffineTransform.
+     * @param hints
+     *            the RenderingHints object which defines the interpolation
+     *            type.
+     */
+    public AffineTransformOp(AffineTransform xform, RenderingHints hints) {
+        this(xform, TYPE_NEAREST_NEIGHBOR);
+        this.hints = hints;
+
+        if (hints != null) {
+            Object hint = hints.get(RenderingHints.KEY_INTERPOLATION);
+            if (hint != null) {
+                // Nearest neighbor is default
+                if (hint == RenderingHints.VALUE_INTERPOLATION_BILINEAR) {
+                    this.iType = TYPE_BILINEAR;
+                } else if (hint == RenderingHints.VALUE_INTERPOLATION_BICUBIC) {
+                    this.iType = TYPE_BICUBIC;
+                }
+            } else {
+                hint = hints.get(RenderingHints.KEY_RENDERING);
+                // Determine from rendering quality
+                if (hint == RenderingHints.VALUE_RENDER_QUALITY) {
+                    this.iType = TYPE_BILINEAR;
+                    // For speed use nearest neighbor
+                }
+            }
+        }
+    }
+
+    /**
+     * Instantiates a new AffineTransformOp with the specified AffineTransform
+     * and a specified interpolation type from the list of predefined
+     * interpolation types.
+     * 
+     * @param xform
+     *            the AffineTransform.
+     * @param interp
+     *            the one of predefined interpolation types:
+     *            TYPE_NEAREST_NEIGHBOR, TYPE_BILINEAR, or TYPE_BICUBIC.
+     */
+    public AffineTransformOp(AffineTransform xform, int interp) {
+        if (Math.abs(xform.getDeterminant()) <= Double.MIN_VALUE) {
+            // awt.24F=Unable to invert transform {0}
+            throw new ImagingOpException(Messages.getString("awt.24F", xform)); //$NON-NLS-1$
+        }
+
+        this.at = (AffineTransform)xform.clone();
+
+        if (interp != TYPE_NEAREST_NEIGHBOR && interp != TYPE_BILINEAR && interp != TYPE_BICUBIC) {
+            // awt.250=Unknown interpolation type: {0}
+            throw new IllegalArgumentException(Messages.getString("awt.250", interp)); //$NON-NLS-1$
+        }
+
+        this.iType = interp;
+    }
+
+    /**
+     * Gets the interpolation type.
+     * 
+     * @return the interpolation type.
+     */
+    public final int getInterpolationType() {
+        return iType;
+    }
+
+    public final RenderingHints getRenderingHints() {
+        if (hints == null) {
+            Object value = null;
+
+            switch (iType) {
+                case TYPE_NEAREST_NEIGHBOR:
+                    value = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
+                    break;
+                case TYPE_BILINEAR:
+                    value = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
+                    break;
+                case TYPE_BICUBIC:
+                    value = RenderingHints.VALUE_INTERPOLATION_BICUBIC;
+                    break;
+                default:
+                    value = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
+            }
+
+            hints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, value);
+        }
+
+        return hints;
+    }
+
+    /**
+     * Gets the affine transform associated with this AffineTransformOp.
+     * 
+     * @return the AffineTransform.
+     */
+    public final AffineTransform getTransform() {
+        return (AffineTransform)at.clone();
+    }
+
+    public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+        return at.transform(srcPt, dstPt);
+    }
+
+    public final Rectangle2D getBounds2D(BufferedImage src) {
+        return getBounds2D(src.getRaster());
+    }
+
+    public final Rectangle2D getBounds2D(Raster src) {
+        // We position source raster to (0,0) even if it is translated child
+        // raster.
+        // This means that we need only width and height of the src
+        int width = src.getWidth();
+        int height = src.getHeight();
+
+        float[] corners = {
+                0, 0, width, 0, width, height, 0, height
+        };
+
+        at.transform(corners, 0, corners, 0, 4);
+
+        Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0, 0);
+        bounds.add(corners[2], corners[3]);
+        bounds.add(corners[4], corners[5]);
+        bounds.add(corners[6], corners[7]);
+
+        return bounds;
+    }
+
+    public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
+        Rectangle2D newBounds = getBounds2D(src);
+
+        // Destination image should include (0,0) + positive part
+        // of the area bounded by newBounds (in source coordinate system).
+        double dstWidth = newBounds.getX() + newBounds.getWidth();
+        double dstHeight = newBounds.getY() + newBounds.getHeight();
+
+        if (dstWidth <= 0 || dstHeight <= 0) {
+            // awt.251=Transformed width ({0}) and height ({1}) should be
+            // greater than 0
+            throw new RasterFormatException(Messages.getString("awt.251", dstWidth, dstHeight)); //$NON-NLS-1$
+        }
+
+        if (destCM != null) {
+            return new BufferedImage(destCM, destCM.createCompatibleWritableRaster((int)dstWidth,
+                    (int)dstHeight), destCM.isAlphaPremultiplied(), null);
+        }
+
+        ColorModel cm = src.getColorModel();
+
+        // Interpolation other than NN doesn't make any sense for index color
+        if (iType != TYPE_NEAREST_NEIGHBOR && cm instanceof IndexColorModel) {
+            return new BufferedImage((int)dstWidth, (int)dstHeight, BufferedImage.TYPE_INT_ARGB);
+        }
+
+        // OK, we can get source color model
+        return new BufferedImage(cm, src.getRaster().createCompatibleWritableRaster((int)dstWidth,
+                (int)dstHeight), cm.isAlphaPremultiplied(), null);
+    }
+
+    public WritableRaster createCompatibleDestRaster(Raster src) {
+        // Here approach is other then in createCompatibleDestImage -
+        // destination should include only
+        // transformed image, but not (0,0) in source coordinate system
+
+        Rectangle2D newBounds = getBounds2D(src);
+        return src.createCompatibleWritableRaster((int)newBounds.getX(), (int)newBounds.getY(),
+                (int)newBounds.getWidth(), (int)newBounds.getHeight());
+    }
+
+    public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+        if (src == dst) {
+            // awt.252=Source can't be same as the destination
+            throw new IllegalArgumentException(Messages.getString("awt.252")); //$NON-NLS-1$
+        }
+
+        ColorModel srcCM = src.getColorModel();
+        BufferedImage finalDst = null;
+
+        if (srcCM instanceof IndexColorModel
+                && (iType != TYPE_NEAREST_NEIGHBOR || srcCM.getPixelSize() % 8 != 0)) {
+            src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true);
+            srcCM = src.getColorModel();
+        }
+
+        if (dst == null) {
+            dst = createCompatibleDestImage(src, srcCM);
+        } else {
+            if (!srcCM.equals(dst.getColorModel())) {
+                // Treat BufferedImage.TYPE_INT_RGB and
+                // BufferedImage.TYPE_INT_ARGB as same
+                if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst
+                        .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) {
+                    finalDst = dst;
+                    dst = createCompatibleDestImage(src, srcCM);
+                }
+            }
+        }
+
+        // Skip alpha channel for TYPE_INT_RGB images
+        if (slowFilter(src.getRaster(), dst.getRaster()) != 0) {
+            // awt.21F=Unable to transform source
+            throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$
+            // TODO - uncomment
+            // if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) !=
+            // 0)
+            // throw new ImagingOpException ("Unable to transform source");
+        }
+
+        if (finalDst != null) {
+            Graphics2D g = finalDst.createGraphics();
+            g.setComposite(AlphaComposite.Src);
+            g.drawImage(dst, 0, 0, null);
+        } else {
+            finalDst = dst;
+        }
+
+        return finalDst;
+    }
+
+    public final WritableRaster filter(Raster src, WritableRaster dst) {
+        if (src == dst) {
+            // awt.252=Source can't be same as the destination
+            throw new IllegalArgumentException(Messages.getString("awt.252")); //$NON-NLS-1$
+        }
+
+        if (dst == null) {
+            dst = createCompatibleDestRaster(src);
+        } else if (src.getNumBands() != dst.getNumBands()) {
+            // awt.253=Different number of bands in source and destination
+            throw new IllegalArgumentException(Messages.getString("awt.253")); //$NON-NLS-1$
+        }
+
+        if (slowFilter(src, dst) != 0) {
+            // awt.21F=Unable to transform source
+            throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$
+            // TODO - uncomment
+            // if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0)
+            // throw new ImagingOpException("Unable to transform source");
+        }
+
+        return dst;
+    }
+
+    // TODO remove when method is used
+    /**
+     * Ipp filter.
+     * 
+     * @param src
+     *            the src.
+     * @param dst
+     *            the dst.
+     * @param imageType
+     *            the image type.
+     * @return the int.
+     */
+    @SuppressWarnings("unused")
+    private int ippFilter(Raster src, WritableRaster dst, int imageType) {
+        int srcStride, dstStride;
+        boolean skipChannel = false;
+        int channels;
+        int offsets[] = null;
+
+        switch (imageType) {
+            case BufferedImage.TYPE_INT_RGB:
+            case BufferedImage.TYPE_INT_BGR: {
+                channels = 4;
+                srcStride = src.getWidth() * 4;
+                dstStride = dst.getWidth() * 4;
+                skipChannel = true;
+                break;
+            }
+
+            case BufferedImage.TYPE_INT_ARGB:
+            case BufferedImage.TYPE_INT_ARGB_PRE:
+            case BufferedImage.TYPE_4BYTE_ABGR:
+            case BufferedImage.TYPE_4BYTE_ABGR_PRE: {
+                channels = 4;
+                srcStride = src.getWidth() * 4;
+                dstStride = dst.getWidth() * 4;
+                break;
+            }
+
+            case BufferedImage.TYPE_BYTE_GRAY:
+            case BufferedImage.TYPE_BYTE_INDEXED: {
+                channels = 1;
+                srcStride = src.getWidth();
+                dstStride = dst.getWidth();
+                break;
+            }
+
+            case BufferedImage.TYPE_3BYTE_BGR: {
+                channels = 3;
+                srcStride = src.getWidth() * 3;
+                dstStride = dst.getWidth() * 3;
+                break;
+            }
+
+            case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in
+                // native code?
+            case BufferedImage.TYPE_USHORT_565_RGB:
+            case BufferedImage.TYPE_USHORT_555_RGB:
+            case BufferedImage.TYPE_BYTE_BINARY: {
+                return slowFilter(src, dst);
+            }
+
+            default: {
+                SampleModel srcSM = src.getSampleModel();
+                SampleModel dstSM = dst.getSampleModel();
+
+                if (srcSM instanceof PixelInterleavedSampleModel
+                        && dstSM instanceof PixelInterleavedSampleModel) {
+                    // Check PixelInterleavedSampleModel
+                    if (srcSM.getDataType() != DataBuffer.TYPE_BYTE
+                            || dstSM.getDataType() != DataBuffer.TYPE_BYTE) {
+                        return slowFilter(src, dst);
+                    }
+
+                    channels = srcSM.getNumBands(); // Have IPP functions for 1,
+                    // 3 and 4 channels
+                    if (channels != 1 && channels != 3 && channels != 4) {
+                        return slowFilter(src, dst);
+                    }
+
+                    int dataTypeSize = DataBuffer.getDataTypeSize(srcSM.getDataType()) / 8;
+
+                    srcStride = ((ComponentSampleModel)srcSM).getScanlineStride() * dataTypeSize;
+                    dstStride = ((ComponentSampleModel)dstSM).getScanlineStride() * dataTypeSize;
+                } else if (srcSM instanceof SinglePixelPackedSampleModel
+                        && dstSM instanceof SinglePixelPackedSampleModel) {
+                    // Check SinglePixelPackedSampleModel
+                    SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM;
+                    SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM;
+
+                    // No IPP function for this type
+                    if (sppsm1.getDataType() == DataBuffer.TYPE_USHORT) {
+                        return slowFilter(src, dst);
+                    }
+
+                    channels = sppsm1.getNumBands();
+                    // Have IPP functions for 1, 3 and 4 channels
+                    if (channels != 1 && channels != 3 && channels != 4) {
+                        return slowFilter(src, dst);
+                    }
+
+                    // Check compatibility of sample models
+                    if (sppsm1.getDataType() != sppsm2.getDataType()
+                            || !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets())
+                            || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) {
+                        return slowFilter(src, dst);
+                    }
+
+                    for (int i = 0; i < channels; i++) {
+                        if (sppsm1.getSampleSize(i) != 8) {
+                            return slowFilter(src, dst);
+                        }
+                    }
+
+                    if (channels == 3) {
+                        channels = 4;
+                    }
+
+                    int dataTypeSize = DataBuffer.getDataTypeSize(sppsm1.getDataType()) / 8;
+
+                    srcStride = sppsm1.getScanlineStride() * dataTypeSize;
+                    dstStride = sppsm2.getScanlineStride() * dataTypeSize;
+                } else {
+                    return slowFilter(src, dst);
+                }
+
+                // Fill offsets if there's a child raster
+                if (src.getParent() != null || dst.getParent() != null) {
+                    if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0
+                            || dst.getSampleModelTranslateX() != 0
+                            || dst.getSampleModelTranslateY() != 0) {
+                        offsets = new int[4];
+                        offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+                        offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+                        offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+                        offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+                    }
+                }
+            }
+        }
+
+        double m00 = at.getScaleX();
+        double m01 = at.getShearX();
+        double m02 = at.getTranslateX();
+        double m10 = at.getShearY();
+        double m11 = at.getScaleY();
+        double m12 = at.getTranslateY();
+
+        Object srcData, dstData;
+        AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+        try {
+            srcData = dbAccess.getData(src.getDataBuffer());
+            dstData = dbAccess.getData(dst.getDataBuffer());
+        } catch (IllegalArgumentException e) {
+            return -1; // Unknown data buffer type
+        }
+
+        return ippAffineTransform(m00, m01, m02, m10, m11, m12, srcData, src.getWidth(), src
+                .getHeight(), srcStride, dstData, dst.getWidth(), dst.getHeight(), dstStride,
+                iType, channels, skipChannel, offsets);
+    }
+
+    /**
+     * Slow filter.
+     * 
+     * @param src
+     *            the src.
+     * @param dst
+     *            the dst.
+     * @return the int.
+     */
+    private int slowFilter(Raster src, WritableRaster dst) {
+        // TODO: make correct interpolation
+        // TODO: what if there are different data types?
+
+        Rectangle srcBounds = src.getBounds();
+        Rectangle dstBounds = dst.getBounds();
+        Rectangle normDstBounds = new Rectangle(0, 0, dstBounds.width, dstBounds.height);
+        Rectangle bounds = getBounds2D(src).getBounds().intersection(normDstBounds);
+
+        AffineTransform inv = null;
+        try {
+            inv = at.createInverse();
+        } catch (NoninvertibleTransformException e) {
+            return -1;
+        }
+
+        double[] m = new double[6];
+        inv.getMatrix(m);
+
+        int minSrcX = srcBounds.x;
+        int minSrcY = srcBounds.y;
+        int maxSrcX = srcBounds.x + srcBounds.width;
+        int maxSrcY = srcBounds.y + srcBounds.height;
+
+        int minX = bounds.x + dstBounds.x;
+        int minY = bounds.y + dstBounds.y;
+        int maxX = minX + bounds.width;
+        int maxY = minY + bounds.height;
+
+        int hx = (int)(m[0] * 256);
+        int hy = (int)(m[1] * 256);
+        int vx = (int)(m[2] * 256);
+        int vy = (int)(m[3] * 256);
+        int sx = (int)(m[4] * 256) + hx * bounds.x + vx * bounds.y + (srcBounds.x) * 256;
+        int sy = (int)(m[5] * 256) + hy * bounds.x + vy * bounds.y + (srcBounds.y) * 256;
+
+        vx -= hx * bounds.width;
+        vy -= hy * bounds.width;
+
+        if (src.getTransferType() == dst.getTransferType()) {
+            for (int y = minY; y < maxY; y++) {
+                for (int x = minX; x < maxX; x++) {
+                    int px = sx >> 8;
+                    int py = sy >> 8;
+                    if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) {
+                        Object val = src.getDataElements(px, py, null);
+                        dst.setDataElements(x, y, val);
+                    }
+                    sx += hx;
+                    sy += hy;
+                }
+                sx += vx;
+                sy += vy;
+            }
+        } else {
+            float pixel[] = null;
+            for (int y = minY; y < maxY; y++) {
+                for (int x = minX; x < maxX; x++) {
+                    int px = sx >> 8;
+                    int py = sy >> 8;
+                    if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) {
+                        pixel = src.getPixel(px, py, pixel);
+                        dst.setPixel(x, y, pixel);
+                    }
+                    sx += hx;
+                    sy += hy;
+                }
+                sx += vx;
+                sy += vy;
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     * Ipp affine transform.
+     * 
+     * @param m00
+     *            the m00.
+     * @param m01
+     *            the m01.
+     * @param m02
+     *            the m02.
+     * @param m10
+     *            the m10.
+     * @param m11
+     *            the m11.
+     * @param m12
+     *            the m12.
+     * @param src
+     *            the src.
+     * @param srcWidth
+     *            the src width.
+     * @param srcHeight
+     *            the src height.
+     * @param srcStride
+     *            the src stride.
+     * @param dst
+     *            the dst.
+     * @param dstWidth
+     *            the dst width.
+     * @param dstHeight
+     *            the dst height.
+     * @param dstStride
+     *            the dst stride.
+     * @param iType
+     *            the i type.
+     * @param channels
+     *            the channels.
+     * @param skipChannel
+     *            the skip channel.
+     * @param offsets
+     *            the offsets.
+     * @return the int.
+     */
+    private native int ippAffineTransform(double m00, double m01, double m02, double m10,
+            double m11, double m12, Object src, int srcWidth, int srcHeight, int srcStride,
+            Object dst, int dstWidth, int dstHeight, int dstStride, int iType, int channels,
+            boolean skipChannel, int offsets[]);
+}
\ No newline at end of file
diff --git a/awt/java/awt/image/AreaAveragingScaleFilter.java b/awt/java/awt/image/AreaAveragingScaleFilter.java
new file mode 100644
index 0000000..7fb138e
--- /dev/null
+++ b/awt/java/awt/image/AreaAveragingScaleFilter.java
@@ -0,0 +1,288 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.util.Arrays;
+
+/**
+ * The AreaAveragingScaleFilter class scales the source image using area
+ * averaging algorithm. This algorithm provides a source image with a new image
+ * containing the resampled image.
+ * 
+ * @since Android 1.0
+ */
+public class AreaAveragingScaleFilter extends ReplicateScaleFilter {
+
+    /**
+     * The Constant rgbCM.
+     */
+    private static final ColorModel rgbCM = ColorModel.getRGBdefault();
+
+    /**
+     * The Constant averagingFlags.
+     */
+    private static final int averagingFlags = (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES);
+
+    /**
+     * The reset.
+     */
+    private boolean reset = true; // Flag for used superclass filter
+
+    /**
+     * The inited.
+     */
+    private boolean inited = false; // All data inited
+
+    /**
+     * The sum_r.
+     */
+    private int sum_r[]; // Array for average Red samples
+
+    /**
+     * The sum_g.
+     */
+    private int sum_g[]; // Array for average Green samples
+
+    /**
+     * The sum_b.
+     */
+    private int sum_b[]; // Array for average Blue samples
+
+    /**
+     * The sum_a.
+     */
+    private int sum_a[]; // Array for average Alpha samples
+
+    /**
+     * The buff.
+     */
+    private int buff[]; // Stride buffer
+
+    /**
+     * The avg factor.
+     */
+    private int avgFactor; // Global averaging factor
+
+    /**
+     * The cached dy.
+     */
+    private int cachedDY; // Cached number of the destination scanline
+
+    /**
+     * The cached dv rest.
+     */
+    private int cachedDVRest; // Cached value of rest src scanlines for sum
+
+    // pixel samples
+    // Because data if transferring by whole scanlines
+    // we are caching only Y coordinate values
+
+    /**
+     * Instantiates a new AreaAveragingScaleFilter object which scales a source
+     * image with the specified width and height.
+     * 
+     * @param width
+     *            the scaled width of the image.
+     * @param height
+     *            the scaled height of the image.
+     */
+    public AreaAveragingScaleFilter(int width, int height) {
+        super(width, height);
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off,
+            int scansize) {
+        if (reset) {
+            super.setPixels(x, y, w, h, model, pixels, off, scansize);
+        } else {
+            setFilteredPixels(x, y, w, h, model, pixels, off, scansize);
+        }
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off,
+            int scansize) {
+        if (reset) {
+            super.setPixels(x, y, w, h, model, pixels, off, scansize);
+        } else {
+            setFilteredPixels(x, y, w, h, model, pixels, off, scansize);
+        }
+    }
+
+    @Override
+    public void setHints(int hints) {
+        super.setHints(hints);
+        reset = ((hints & averagingFlags) != averagingFlags);
+    }
+
+    /**
+     * This method implements the Area Averaging Scale filter. The description
+     * of algorithm is presented in Java API Specification. Arrays sum_r, sum_g,
+     * sum_b, sum_a have length equals width of destination image. In each
+     * array's element is accumulating pixel's component values, proportional to
+     * the area which source pixels will occupy in destination image. Then that
+     * values will divide by Global averaging factor (area of the destination
+     * image) for receiving average values of destination pixels.
+     * 
+     * @param x
+     *            the source pixels X coordinate.
+     * @param y
+     *            the source pixels Y coordinate.
+     * @param w
+     *            the width of the area of the source pixels.
+     * @param h
+     *            the height of the area of the source pixels.
+     * @param model
+     *            the color model of the source pixels.
+     * @param pixels
+     *            the array of source pixels.
+     * @param off
+     *            the offset into the source pixels array.
+     * @param scansize
+     *            the length of scanline in the pixels array.
+     */
+    private void setFilteredPixels(int x, int y, int w, int h, ColorModel model, Object pixels,
+            int off, int scansize) {
+        if (!inited) {
+            initialize();
+        }
+
+        int srcX, srcY, dx, dy;
+        int svRest, dvRest, shRest, dhRest, vDif, hDif;
+
+        if (y == 0) {
+            dy = 0;
+            dvRest = srcHeight;
+        } else {
+            dy = cachedDY;
+            dvRest = cachedDVRest;
+        }
+
+        srcY = y;
+        svRest = destHeight;
+
+        int srcOff = off;
+        while (srcY < y + h) {
+            if (svRest < dvRest) {
+                vDif = svRest;
+            } else {
+                vDif = dvRest;
+            }
+
+            srcX = 0;
+            dx = 0;
+            shRest = destWidth;
+            dhRest = srcWidth;
+            while (srcX < w) {
+                if (shRest < dhRest) {
+                    hDif = shRest;
+                } else {
+                    hDif = dhRest;
+                }
+                int avg = hDif * vDif; // calculation of contribution factor
+
+                int rgb, pix;
+                if (pixels instanceof int[]) {
+                    pix = ((int[])pixels)[srcOff + srcX];
+                } else {
+                    pix = ((byte[])pixels)[srcOff + srcX] & 0xff;
+                }
+
+                rgb = model.getRGB(pix);
+                int a = rgb >>> 24;
+                int r = (rgb >> 16) & 0xff;
+                int g = (rgb >> 8) & 0xff;
+                int b = rgb & 0xff;
+
+                // accumulating pixel's component values
+                sum_a[dx] += a * avg;
+                sum_r[dx] += r * avg;
+                sum_g[dx] += g * avg;
+                sum_b[dx] += b * avg;
+
+                shRest -= hDif;
+                dhRest -= hDif;
+
+                if (shRest == 0) {
+                    srcX++;
+                    shRest = destWidth;
+                }
+
+                if (dhRest == 0) {
+                    dx++;
+                    dhRest = srcWidth;
+                }
+            }
+
+            svRest -= vDif;
+            dvRest -= vDif;
+
+            if (svRest == 0) {
+                svRest = destHeight;
+                srcY++;
+                srcOff += scansize;
+            }
+
+            if (dvRest == 0) {
+                // averaging destination pixel's values
+                for (int i = 0; i < destWidth; i++) {
+                    int a = (sum_a[i] / avgFactor) & 0xff;
+                    int r = (sum_r[i] / avgFactor) & 0xff;
+                    int g = (sum_g[i] / avgFactor) & 0xff;
+                    int b = (sum_b[i] / avgFactor) & 0xff;
+                    int frgb = (a << 24) | (r << 16) | (g << 8) | b;
+                    buff[i] = frgb;
+                }
+                consumer.setPixels(0, dy, destWidth, 1, rgbCM, buff, 0, destWidth);
+                dy++;
+                dvRest = srcHeight;
+                Arrays.fill(sum_a, 0);
+                Arrays.fill(sum_r, 0);
+                Arrays.fill(sum_g, 0);
+                Arrays.fill(sum_b, 0);
+            }
+
+        }
+
+        cachedDY = dy;
+        cachedDVRest = dvRest;
+
+    }
+
+    /**
+     * Initialization of the auxiliary data.
+     */
+    private void initialize() {
+
+        sum_a = new int[destWidth];
+        sum_r = new int[destWidth];
+        sum_g = new int[destWidth];
+        sum_b = new int[destWidth];
+
+        buff = new int[destWidth];
+        outpixbuf = buff;
+        avgFactor = srcWidth * srcHeight;
+
+        inited = true;
+    }
+}
diff --git a/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java b/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java
new file mode 100644
index 0000000..6dffee8
--- /dev/null
+++ b/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java
@@ -0,0 +1,156 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 23.11.2005
+ *
+ */
+
+package java.awt.image;
+
+import java.awt.Image;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferDouble;
+import java.awt.image.DataBufferFloat;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DataBufferShort;
+import java.awt.image.DataBufferUShort;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.gl.GLVolatileImage;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.image.DataBufferListener;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class not part of public API. It useful for receiving package private
+ * data from other packages.
+ * 
+ * @since Android 1.0
+ */
+class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor {
+
+    static void init() {
+        inst = new AwtImageBackdoorAccessorImpl();
+    }
+
+    @Override
+    public Surface getImageSurface(Image image) {
+        if (image instanceof BufferedImage) {
+            return ((BufferedImage)image).getImageSurface();
+        } else if (image instanceof GLVolatileImage) {
+            return ((GLVolatileImage)image).getImageSurface();
+        }
+        return null;
+    }
+
+    @Override
+    public boolean isGrayPallete(IndexColorModel icm) {
+        return icm.isGrayPallete();
+    }
+
+    @Override
+    public Object getData(DataBuffer db) {
+        if (db instanceof DataBufferByte) {
+            return ((DataBufferByte)db).getData();
+        } else if (db instanceof DataBufferUShort) {
+            return ((DataBufferUShort)db).getData();
+        } else if (db instanceof DataBufferShort) {
+            return ((DataBufferShort)db).getData();
+        } else if (db instanceof DataBufferInt) {
+            return ((DataBufferInt)db).getData();
+        } else if (db instanceof DataBufferFloat) {
+            return ((DataBufferFloat)db).getData();
+        } else if (db instanceof DataBufferDouble) {
+            return ((DataBufferDouble)db).getData();
+        } else {
+            // awt.235=Wrong Data Buffer type : {0}
+            throw new IllegalArgumentException(Messages.getString("awt.235", //$NON-NLS-1$
+                    db.getClass()));
+        }
+    }
+
+    @Override
+    public int[] getDataInt(DataBuffer db) {
+        if (db instanceof DataBufferInt) {
+            return ((DataBufferInt)db).getData();
+        }
+        return null;
+    }
+
+    @Override
+    public byte[] getDataByte(DataBuffer db) {
+        if (db instanceof DataBufferByte) {
+            return ((DataBufferByte)db).getData();
+        }
+        return null;
+    }
+
+    @Override
+    public short[] getDataShort(DataBuffer db) {
+        if (db instanceof DataBufferShort) {
+            return ((DataBufferShort)db).getData();
+        }
+        return null;
+    }
+
+    @Override
+    public short[] getDataUShort(DataBuffer db) {
+        if (db instanceof DataBufferUShort) {
+            return ((DataBufferUShort)db).getData();
+        }
+        return null;
+    }
+
+    @Override
+    public double[] getDataDouble(DataBuffer db) {
+        if (db instanceof DataBufferDouble) {
+            return ((DataBufferDouble)db).getData();
+        }
+        return null;
+    }
+
+    @Override
+    public float[] getDataFloat(DataBuffer db) {
+        if (db instanceof DataBufferFloat) {
+            return ((DataBufferFloat)db).getData();
+        }
+        return null;
+    }
+
+    @Override
+    public void addDataBufferListener(DataBuffer db, DataBufferListener listener) {
+        db.addDataBufferListener(listener);
+    }
+
+    @Override
+    public void removeDataBufferListener(DataBuffer db) {
+        db.removeDataBufferListener();
+    }
+
+    @Override
+    public void validate(DataBuffer db) {
+        db.validate();
+    }
+
+    @Override
+    public void releaseData(DataBuffer db) {
+        db.releaseData();
+    }
+}
diff --git a/awt/java/awt/image/BandCombineOp.java b/awt/java/awt/image/BandCombineOp.java
new file mode 100644
index 0000000..da2cc89
--- /dev/null
+++ b/awt/java/awt/image/BandCombineOp.java
@@ -0,0 +1,658 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Sep 20, 2005
+ */
+
+package java.awt.image;
+
+import java.awt.*;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The BandCombineOp class translates coordinates from coordinates in the source
+ * Raster to coordinates in the destination Raster by an arbitrary linear
+ * combination of the bands in a source Raster, using a specified matrix. The
+ * number of bands in the matrix should equal to the number of bands in the
+ * source Raster plus 1.
+ * 
+ * @since Android 1.0
+ */
+public class BandCombineOp implements RasterOp {
+
+    /**
+     * The Constant offsets3c.
+     */
+    static final int offsets3c[] = {
+            16, 8, 0
+    };
+
+    /**
+     * The Constant offsets4ac.
+     */
+    static final int offsets4ac[] = {
+            16, 8, 0, 24
+    };
+
+    /**
+     * The Constant masks3c.
+     */
+    static final int masks3c[] = {
+            0xFF0000, 0xFF00, 0xFF
+    };
+
+    /**
+     * The Constant masks4ac.
+     */
+    static final int masks4ac[] = {
+            0xFF0000, 0xFF00, 0xFF, 0xFF000000
+    };
+
+    /**
+     * The Constant piOffsets.
+     */
+    private static final int piOffsets[] = {
+            0, 1, 2
+    };
+
+    /**
+     * The Constant piInvOffsets.
+     */
+    private static final int piInvOffsets[] = {
+            2, 1, 0
+    };
+
+    /**
+     * The Constant TYPE_BYTE3C.
+     */
+    private static final int TYPE_BYTE3C = 0;
+
+    /**
+     * The Constant TYPE_BYTE4AC.
+     */
+    private static final int TYPE_BYTE4AC = 1;
+
+    /**
+     * The Constant TYPE_USHORT3C.
+     */
+    private static final int TYPE_USHORT3C = 2;
+
+    /**
+     * The Constant TYPE_SHORT3C.
+     */
+    private static final int TYPE_SHORT3C = 3;
+
+    /**
+     * The mx width.
+     */
+    private int mxWidth;
+
+    /**
+     * The mx height.
+     */
+    private int mxHeight;
+
+    /**
+     * The matrix.
+     */
+    private float matrix[][];
+
+    /**
+     * The r hints.
+     */
+    private RenderingHints rHints;
+
+    static {
+        // XXX - todo
+        // System.loadLibrary("imageops");
+    }
+
+    /**
+     * Instantiates a new BandCombineOp object with the specified matrix.
+     * 
+     * @param matrix
+     *            the specified matrix for band combining.
+     * @param hints
+     *            the RenderingHints.
+     */
+    public BandCombineOp(float matrix[][], RenderingHints hints) {
+        this.mxHeight = matrix.length;
+        this.mxWidth = matrix[0].length;
+        this.matrix = new float[mxHeight][mxWidth];
+
+        for (int i = 0; i < mxHeight; i++) {
+            System.arraycopy(matrix[i], 0, this.matrix[i], 0, mxWidth);
+        }
+
+        this.rHints = hints;
+    }
+
+    public final RenderingHints getRenderingHints() {
+        return this.rHints;
+    }
+
+    /**
+     * Gets the matrix associated with this BandCombineOp object.
+     * 
+     * @return the matrix associated with this BandCombineOp object.
+     */
+    public final float[][] getMatrix() {
+        float res[][] = new float[mxHeight][mxWidth];
+
+        for (int i = 0; i < mxHeight; i++) {
+            System.arraycopy(matrix[i], 0, res[i], 0, mxWidth);
+        }
+
+        return res;
+    }
+
+    public final Point2D getPoint2D(Point2D srcPoint, Point2D dstPoint) {
+        if (dstPoint == null) {
+            dstPoint = new Point2D.Float();
+        }
+
+        dstPoint.setLocation(srcPoint);
+        return dstPoint;
+    }
+
+    public final Rectangle2D getBounds2D(Raster src) {
+        return src.getBounds();
+    }
+
+    public WritableRaster createCompatibleDestRaster(Raster src) {
+        int numBands = src.getNumBands();
+        if (mxWidth != numBands && mxWidth != (numBands + 1) || numBands != mxHeight) {
+            // awt.254=Number of bands in the source raster ({0}) is
+            // incompatible with the matrix [{1}x{2}]
+            throw new IllegalArgumentException(Messages.getString("awt.254", //$NON-NLS-1$
+                    new Object[] {
+                            numBands, mxWidth, mxHeight
+                    }));
+        }
+
+        return src.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
+    }
+
+    public WritableRaster filter(Raster src, WritableRaster dst) {
+        int numBands = src.getNumBands();
+
+        if (mxWidth != numBands && mxWidth != (numBands + 1)) {
+            // awt.254=Number of bands in the source raster ({0}) is
+            // incompatible with the matrix [{1}x{2}]
+            throw new IllegalArgumentException(Messages.getString("awt.254", //$NON-NLS-1$
+                    new Object[] {
+                            numBands, mxWidth, mxHeight
+                    }));
+        }
+
+        if (dst == null) {
+            dst = createCompatibleDestRaster(src);
+        } else if (dst.getNumBands() != mxHeight) {
+            // awt.255=Number of bands in the destination raster ({0}) is
+            // incompatible with the matrix [{1}x{2}]
+            throw new IllegalArgumentException(Messages.getString("awt.255", //$NON-NLS-1$
+                    new Object[] {
+                            dst.getNumBands(), mxWidth, mxHeight
+                    }));
+        }
+
+        // XXX - todo
+        // if (ippFilter(src, dst) != 0)
+        if (verySlowFilter(src, dst) != 0) {
+            // awt.21F=Unable to transform source
+            throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$
+        }
+
+        return dst;
+    }
+
+    /**
+     * The Class SampleModelInfo.
+     */
+    private static final class SampleModelInfo {
+
+        /**
+         * The channels.
+         */
+        int channels;
+
+        /**
+         * The channels order.
+         */
+        int channelsOrder[];
+
+        /**
+         * The stride.
+         */
+        int stride;
+    }
+
+    /**
+     * Check sample model.
+     * 
+     * @param sm
+     *            the sm.
+     * @return the sample model info.
+     */
+    private final SampleModelInfo checkSampleModel(SampleModel sm) {
+        SampleModelInfo ret = new SampleModelInfo();
+
+        if (sm instanceof PixelInterleavedSampleModel) {
+            // Check PixelInterleavedSampleModel
+            if (sm.getDataType() != DataBuffer.TYPE_BYTE) {
+                return null;
+            }
+
+            ret.channels = sm.getNumBands();
+            ret.stride = ((ComponentSampleModel)sm).getScanlineStride();
+            ret.channelsOrder = ((ComponentSampleModel)sm).getBandOffsets();
+
+        } else if (sm instanceof SinglePixelPackedSampleModel) {
+            // Check SinglePixelPackedSampleModel
+            SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)sm;
+
+            ret.channels = sppsm1.getNumBands();
+            if (sppsm1.getDataType() != DataBuffer.TYPE_INT) {
+                return null;
+            }
+
+            // Check sample models
+            for (int i = 0; i < ret.channels; i++) {
+                if (sppsm1.getSampleSize(i) != 8) {
+                    return null;
+                }
+            }
+
+            ret.channelsOrder = new int[ret.channels];
+            int bitOffsets[] = sppsm1.getBitOffsets();
+            for (int i = 0; i < ret.channels; i++) {
+                if (bitOffsets[i] % 8 != 0) {
+                    return null;
+                }
+
+                ret.channelsOrder[i] = bitOffsets[i] / 8;
+            }
+
+            ret.channels = 4;
+            ret.stride = sppsm1.getScanlineStride() * 4;
+        } else {
+            return null;
+        }
+
+        return ret;
+    }
+
+    /**
+     * Slow filter.
+     * 
+     * @param src
+     *            the src.
+     * @param dst
+     *            the dst.
+     * @return the int.
+     */
+    private final int slowFilter(Raster src, WritableRaster dst) {
+        int res = 0;
+
+        SampleModelInfo srcInfo, dstInfo;
+        int offsets[] = null;
+
+        srcInfo = checkSampleModel(src.getSampleModel());
+        dstInfo = checkSampleModel(dst.getSampleModel());
+        if (srcInfo == null || dstInfo == null) {
+            return verySlowFilter(src, dst);
+        }
+
+        // Fill offsets if there's a child raster
+        if (src.getParent() != null || dst.getParent() != null) {
+            if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0
+                    || dst.getSampleModelTranslateX() != 0 || dst.getSampleModelTranslateY() != 0) {
+                offsets = new int[4];
+                offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+                offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+                offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+                offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+            }
+        }
+
+        int rmxWidth = (srcInfo.channels + 1); // width of the reordered matrix
+        float reorderedMatrix[] = new float[rmxWidth * dstInfo.channels];
+        for (int j = 0; j < dstInfo.channels; j++) {
+            if (j >= dstInfo.channelsOrder.length) {
+                continue;
+            }
+
+            for (int i = 0; i < srcInfo.channels; i++) {
+                if (i >= srcInfo.channelsOrder.length) {
+                    break;
+                }
+
+                reorderedMatrix[dstInfo.channelsOrder[j] * rmxWidth + srcInfo.channelsOrder[i]] = matrix[j][i];
+            }
+            if (mxWidth == rmxWidth) {
+                reorderedMatrix[(dstInfo.channelsOrder[j] + 1) * rmxWidth - 1] = matrix[j][mxWidth - 1];
+            }
+        }
+
+        Object srcData, dstData;
+        AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+        try {
+            srcData = dbAccess.getData(src.getDataBuffer());
+            dstData = dbAccess.getData(dst.getDataBuffer());
+        } catch (IllegalArgumentException e) {
+            return -1; // Unknown data buffer type
+        }
+
+        simpleCombineBands(srcData, src.getWidth(), src.getHeight(), srcInfo.stride,
+                srcInfo.channels, dstData, dstInfo.stride, dstInfo.channels, reorderedMatrix,
+                offsets);
+
+        return res;
+    }
+
+    /**
+     * Very slow filter.
+     * 
+     * @param src
+     *            the src.
+     * @param dst
+     *            the dst.
+     * @return the int.
+     */
+    private int verySlowFilter(Raster src, WritableRaster dst) {
+        int numBands = src.getNumBands();
+
+        int srcMinX = src.getMinX();
+        int srcY = src.getMinY();
+
+        int dstMinX = dst.getMinX();
+        int dstY = dst.getMinY();
+
+        int dX = src.getWidth();// < dst.getWidth() ? src.getWidth() :
+        // dst.getWidth();
+        int dY = src.getHeight();// < dst.getHeight() ? src.getHeight() :
+        // dst.getHeight();
+
+        float sample;
+        int srcPixels[] = new int[numBands * dX * dY];
+        int dstPixels[] = new int[mxHeight * dX * dY];
+
+        srcPixels = src.getPixels(srcMinX, srcY, dX, dY, srcPixels);
+
+        if (numBands == mxWidth) {
+            for (int i = 0, j = 0; i < srcPixels.length; i += numBands) {
+                for (int dstB = 0; dstB < mxHeight; dstB++) {
+                    sample = 0f;
+                    for (int srcB = 0; srcB < numBands; srcB++) {
+                        sample += matrix[dstB][srcB] * srcPixels[i + srcB];
+                    }
+                    dstPixels[j++] = (int)sample;
+                }
+            }
+        } else {
+            for (int i = 0, j = 0; i < srcPixels.length; i += numBands) {
+                for (int dstB = 0; dstB < mxHeight; dstB++) {
+                    sample = 0f;
+                    for (int srcB = 0; srcB < numBands; srcB++) {
+                        sample += matrix[dstB][srcB] * srcPixels[i + srcB];
+                    }
+                    dstPixels[j++] = (int)(sample + matrix[dstB][numBands]);
+                }
+            }
+        }
+
+        dst.setPixels(dstMinX, dstY, dX, dY, dstPixels);
+
+        return 0;
+    }
+
+    // TODO remove when method is used
+    /**
+     * Ipp filter.
+     * 
+     * @param src
+     *            the src.
+     * @param dst
+     *            the dst.
+     * @return the int.
+     */
+    @SuppressWarnings("unused")
+    private int ippFilter(Raster src, WritableRaster dst) {
+        boolean invertChannels;
+        boolean inPlace = (src == dst);
+        int type;
+        int srcStride, dstStride;
+        int offsets[] = null;
+
+        int srcBands = src.getNumBands();
+        int dstBands = dst.getNumBands();
+
+        if (dstBands != 3
+                || (srcBands != 3 && !(srcBands == 4 && matrix[0][3] == 0 && matrix[1][3] == 0 && matrix[2][3] == 0))) {
+            return slowFilter(src, dst);
+        }
+
+        SampleModel srcSM = src.getSampleModel();
+        SampleModel dstSM = dst.getSampleModel();
+
+        if (srcSM instanceof SinglePixelPackedSampleModel
+                && dstSM instanceof SinglePixelPackedSampleModel) {
+            // Check SinglePixelPackedSampleModel
+            SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM;
+            SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM;
+
+            if (sppsm1.getDataType() != DataBuffer.TYPE_INT
+                    || sppsm2.getDataType() != DataBuffer.TYPE_INT) {
+                return slowFilter(src, dst);
+            }
+
+            // Check sample models
+            if (!Arrays.equals(sppsm2.getBitOffsets(), offsets3c)
+                    || !Arrays.equals(sppsm2.getBitMasks(), masks3c)) {
+                return slowFilter(src, dst);
+            }
+
+            if (srcBands == 3) {
+                if (!Arrays.equals(sppsm1.getBitOffsets(), offsets3c)
+                        || !Arrays.equals(sppsm1.getBitMasks(), masks3c)) {
+                    return slowFilter(src, dst);
+                }
+            } else if (srcBands == 4) {
+                if (!Arrays.equals(sppsm1.getBitOffsets(), offsets4ac)
+                        || !Arrays.equals(sppsm1.getBitMasks(), masks4ac)) {
+                    return slowFilter(src, dst);
+                }
+            }
+
+            type = TYPE_BYTE4AC;
+            invertChannels = true;
+
+            srcStride = sppsm1.getScanlineStride() * 4;
+            dstStride = sppsm2.getScanlineStride() * 4;
+        } else if (srcSM instanceof PixelInterleavedSampleModel
+                && dstSM instanceof PixelInterleavedSampleModel) {
+            if (srcBands != 3) {
+                return slowFilter(src, dst);
+            }
+
+            int srcDataType = srcSM.getDataType();
+
+            switch (srcDataType) {
+                case DataBuffer.TYPE_BYTE:
+                    type = TYPE_BYTE3C;
+                    break;
+                case DataBuffer.TYPE_USHORT:
+                    type = TYPE_USHORT3C;
+                    break;
+                case DataBuffer.TYPE_SHORT:
+                    type = TYPE_SHORT3C;
+                    break;
+                default:
+                    return slowFilter(src, dst);
+            }
+
+            // Check PixelInterleavedSampleModel
+            PixelInterleavedSampleModel pism1 = (PixelInterleavedSampleModel)srcSM;
+            PixelInterleavedSampleModel pism2 = (PixelInterleavedSampleModel)dstSM;
+
+            if (srcDataType != pism2.getDataType() || pism1.getPixelStride() != 3
+                    || pism2.getPixelStride() != 3
+                    || !Arrays.equals(pism1.getBandOffsets(), pism2.getBandOffsets())) {
+                return slowFilter(src, dst);
+            }
+
+            if (Arrays.equals(pism1.getBandOffsets(), piInvOffsets)) {
+                invertChannels = true;
+            } else if (Arrays.equals(pism1.getBandOffsets(), piOffsets)) {
+                invertChannels = false;
+            } else {
+                return slowFilter(src, dst);
+            }
+
+            int dataTypeSize = DataBuffer.getDataTypeSize(srcDataType) / 8;
+
+            srcStride = pism1.getScanlineStride() * dataTypeSize;
+            dstStride = pism2.getScanlineStride() * dataTypeSize;
+        } else { // XXX - todo - IPP allows support for planar data also
+            return slowFilter(src, dst);
+        }
+
+        // Fill offsets if there's a child raster
+        if (src.getParent() != null || dst.getParent() != null) {
+            if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0
+                    || dst.getSampleModelTranslateX() != 0 || dst.getSampleModelTranslateY() != 0) {
+                offsets = new int[4];
+                offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+                offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+                offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+                offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+            }
+        }
+
+        Object srcData, dstData;
+        AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+        try {
+            srcData = dbAccess.getData(src.getDataBuffer());
+            dstData = dbAccess.getData(dst.getDataBuffer());
+        } catch (IllegalArgumentException e) {
+            return -1; // Unknown data buffer type
+        }
+
+        float ippMatrix[] = new float[12];
+
+        if (invertChannels) {
+            // IPP treats big endian integers like BGR, so we have to
+            // swap columns 1 and 3 and rows 1 and 3
+            for (int i = 0; i < mxHeight; i++) {
+                ippMatrix[i * 4] = matrix[2 - i][2];
+                ippMatrix[i * 4 + 1] = matrix[2 - i][1];
+                ippMatrix[i * 4 + 2] = matrix[2 - i][0];
+
+                if (mxWidth == 4) {
+                    ippMatrix[i * 4 + 3] = matrix[2 - i][3];
+                } else if (mxWidth == 5) {
+                    ippMatrix[i * 4 + 3] = matrix[2 - i][4];
+                }
+            }
+        } else {
+            for (int i = 0; i < mxHeight; i++) {
+                ippMatrix[i * 4] = matrix[i][0];
+                ippMatrix[i * 4 + 1] = matrix[i][1];
+                ippMatrix[i * 4 + 2] = matrix[i][2];
+
+                if (mxWidth == 4) {
+                    ippMatrix[i * 4 + 3] = matrix[i][3];
+                } else if (mxWidth == 5) {
+                    ippMatrix[i * 4 + 3] = matrix[i][4];
+                }
+            }
+        }
+
+        return ippColorTwist(srcData, src.getWidth(), src.getHeight(), srcStride, dstData, dst
+                .getWidth(), dst.getHeight(), dstStride, ippMatrix, type, offsets, inPlace);
+    }
+
+    /**
+     * Ipp color twist.
+     * 
+     * @param srcData
+     *            the src data.
+     * @param srcWidth
+     *            the src width.
+     * @param srcHeight
+     *            the src height.
+     * @param srcStride
+     *            the src stride.
+     * @param dstData
+     *            the dst data.
+     * @param dstWidth
+     *            the dst width.
+     * @param dstHeight
+     *            the dst height.
+     * @param dstStride
+     *            the dst stride.
+     * @param ippMatrix
+     *            the ipp matrix.
+     * @param type
+     *            the type.
+     * @param offsets
+     *            the offsets.
+     * @param inPlace
+     *            the in place.
+     * @return the int.
+     */
+    private final native int ippColorTwist(Object srcData, int srcWidth, int srcHeight,
+            int srcStride, Object dstData, int dstWidth, int dstHeight, int dstStride,
+            float ippMatrix[], int type, int offsets[], boolean inPlace);
+
+    /**
+     * Simple combine bands.
+     * 
+     * @param srcData
+     *            the src data.
+     * @param srcWidth
+     *            the src width.
+     * @param srcHeight
+     *            the src height.
+     * @param srcStride
+     *            the src stride.
+     * @param srcChannels
+     *            the src channels.
+     * @param dstData
+     *            the dst data.
+     * @param dstStride
+     *            the dst stride.
+     * @param dstChannels
+     *            the dst channels.
+     * @param m
+     *            the m.
+     * @param offsets
+     *            the offsets.
+     * @return the int.
+     */
+    private final native int simpleCombineBands(Object srcData, int srcWidth, int srcHeight,
+            int srcStride, int srcChannels, Object dstData, int dstStride, int dstChannels,
+            float m[], int offsets[]);
+}
diff --git a/awt/java/awt/image/BandedSampleModel.java b/awt/java/awt/image/BandedSampleModel.java
new file mode 100644
index 0000000..0aa30d7
--- /dev/null
+++ b/awt/java/awt/image/BandedSampleModel.java
@@ -0,0 +1,425 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The BandedSampleModel class provides samples of pixels in an image which is
+ * stored in a band interleaved method. Each pixel's sample takes one data
+ * element of the DataBuffer. The pixel stride for a BandedSampleModel is one.
+ * 
+ * @since Android 1.0
+ */
+public final class BandedSampleModel extends ComponentSampleModel {
+
+    /**
+     * Creates the indices.
+     * 
+     * @param numBands
+     *            the num bands.
+     * @return the int[].
+     */
+    private static int[] createIndices(int numBands) {
+        int indices[] = new int[numBands];
+        for (int i = 0; i < numBands; i++) {
+            indices[i] = i;
+        }
+        return indices;
+    }
+
+    /**
+     * Creates the offsets.
+     * 
+     * @param numBands
+     *            the num bands.
+     * @return the int[].
+     */
+    private static int[] createOffsets(int numBands) {
+        int offsets[] = new int[numBands];
+        for (int i = 0; i < numBands; i++) {
+            offsets[i] = 0;
+        }
+        return offsets;
+    }
+
+    /**
+     * Instantiates a new BandedSampleModel object with the specified data type
+     * of samples, the width, height and bands number of image data.
+     * 
+     * @param dataType
+     *            the data type of samples.
+     * @param w
+     *            the width of image data.
+     * @param h
+     *            the height of image data.
+     * @param numBands
+     *            the number of bands.
+     */
+    public BandedSampleModel(int dataType, int w, int h, int numBands) {
+        this(dataType, w, h, w, BandedSampleModel.createIndices(numBands), BandedSampleModel
+                .createOffsets(numBands));
+    }
+
+    /**
+     * Instantiates a new BandedSampleModel object with the specified data type
+     * of samples, the width, height and bands number of image data.
+     * 
+     * @param dataType
+     *            the data type of samples.
+     * @param w
+     *            the width of image data.
+     * @param h
+     *            the height of image data.
+     * @param scanlineStride
+     *            the scanline stride of the of the image data.
+     * @param bankIndices
+     *            the array of the bank indices.
+     * @param bandOffsets
+     *            the array of the band offsets.
+     */
+    public BandedSampleModel(int dataType, int w, int h, int scanlineStride, int bankIndices[],
+            int bandOffsets[]) {
+        super(dataType, w, h, 1, scanlineStride, bankIndices, bandOffsets);
+    }
+
+    @Override
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+        return new BandedSampleModel(dataType, w, h, w, bankIndices, bandOffsets);
+    }
+
+    @Override
+    public DataBuffer createDataBuffer() {
+        DataBuffer data = null;
+        int size = scanlineStride * height;
+
+        switch (dataType) {
+            case DataBuffer.TYPE_BYTE:
+                data = new DataBufferByte(size, numBanks);
+                break;
+            case DataBuffer.TYPE_SHORT:
+            case DataBuffer.TYPE_USHORT:
+                data = new DataBufferShort(size, numBanks);
+                break;
+            case DataBuffer.TYPE_INT:
+                data = new DataBufferInt(size, numBanks);
+                break;
+            case DataBuffer.TYPE_FLOAT:
+                data = new DataBufferFloat(size, numBanks);
+                break;
+            case DataBuffer.TYPE_DOUBLE:
+                data = new DataBufferDouble(size, numBanks);
+                break;
+        }
+
+        return data;
+
+    }
+
+    @Override
+    public SampleModel createSubsetSampleModel(int[] bands) {
+        if (bands.length > numBands) {
+            // awt.64=The number of the bands in the subset is greater than the
+            // number of bands in the sample model
+            throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$
+        }
+
+        int indices[] = new int[bands.length];
+        int offsets[] = new int[bands.length];
+
+        for (int i = 0; i < bands.length; i++) {
+            indices[i] = bankIndices[bands[i]];
+            offsets[i] = bandOffsets[bands[i]];
+        }
+
+        return new BandedSampleModel(dataType, width, height, scanlineStride, indices, offsets);
+    }
+
+    @Override
+    public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+        switch (dataType) {
+            case DataBuffer.TYPE_BYTE: {
+                byte bdata[];
+
+                if (obj == null) {
+                    bdata = new byte[numBands];
+                } else {
+                    bdata = (byte[])obj;
+                }
+
+                for (int i = 0; i < numBands; i++) {
+                    bdata[i] = (byte)getSample(x, y, i, data);
+                }
+
+                obj = bdata;
+                break;
+            }
+            case DataBuffer.TYPE_SHORT:
+            case DataBuffer.TYPE_USHORT: {
+                short sdata[];
+
+                if (obj == null) {
+                    sdata = new short[numBands];
+                } else {
+                    sdata = (short[])obj;
+                }
+
+                for (int i = 0; i < numBands; i++) {
+                    sdata[i] = (short)getSample(x, y, i, data);
+                }
+
+                obj = sdata;
+                break;
+            }
+            case DataBuffer.TYPE_INT: {
+                int idata[];
+
+                if (obj == null) {
+                    idata = new int[numBands];
+                } else {
+                    idata = (int[])obj;
+                }
+
+                for (int i = 0; i < numBands; i++) {
+                    idata[i] = getSample(x, y, i, data);
+                }
+
+                obj = idata;
+                break;
+            }
+            case DataBuffer.TYPE_FLOAT: {
+                float fdata[];
+
+                if (obj == null) {
+                    fdata = new float[numBands];
+                } else {
+                    fdata = (float[])obj;
+                }
+
+                for (int i = 0; i < numBands; i++) {
+                    fdata[i] = getSampleFloat(x, y, i, data);
+                }
+
+                obj = fdata;
+                break;
+            }
+            case DataBuffer.TYPE_DOUBLE: {
+                double ddata[];
+
+                if (obj == null) {
+                    ddata = new double[numBands];
+                } else {
+                    ddata = (double[])obj;
+                }
+
+                for (int i = 0; i < numBands; i++) {
+                    ddata[i] = getSampleDouble(x, y, i, data);
+                }
+
+                obj = ddata;
+                break;
+            }
+        }
+
+        return obj;
+    }
+
+    @Override
+    public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+        int pixel[];
+        if (iArray == null) {
+            pixel = new int[numBands];
+        } else {
+            pixel = iArray;
+        }
+
+        for (int i = 0; i < numBands; i++) {
+            pixel[i] = getSample(x, y, i, data);
+        }
+
+        return pixel;
+    }
+
+    @Override
+    public int getSample(int x, int y, int b, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        return data.getElem(bankIndices[b], y * scanlineStride + x + bandOffsets[b]);
+    }
+
+    @Override
+    public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        return data.getElemDouble(bankIndices[b], y * scanlineStride + x + bandOffsets[b]);
+    }
+
+    @Override
+    public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        return data.getElemFloat(bankIndices[b], y * scanlineStride + x + bandOffsets[b]);
+    }
+
+    @Override
+    public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) {
+        int samples[];
+        int idx = 0;
+
+        if (iArray == null) {
+            samples = new int[w * h];
+        } else {
+            samples = iArray;
+        }
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                samples[idx++] = getSample(j, i, b, data);
+            }
+        }
+
+        return samples;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = super.hashCode();
+        int tmp = hash >>> 8;
+        hash <<= 8;
+        hash |= tmp;
+
+        return hash ^ 0x55;
+    }
+
+    @Override
+    public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+        switch (dataType) {
+            case DataBuffer.TYPE_BYTE:
+                byte bdata[] = (byte[])obj;
+                for (int i = 0; i < numBands; i++) {
+                    setSample(x, y, i, bdata[i] & 0xff, data);
+                }
+                break;
+
+            case DataBuffer.TYPE_SHORT:
+            case DataBuffer.TYPE_USHORT:
+                short sdata[] = (short[])obj;
+                for (int i = 0; i < numBands; i++) {
+                    setSample(x, y, i, sdata[i] & 0xffff, data);
+                }
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int idata[] = (int[])obj;
+                for (int i = 0; i < numBands; i++) {
+                    setSample(x, y, i, idata[i], data);
+                }
+                break;
+
+            case DataBuffer.TYPE_FLOAT:
+                float fdata[] = (float[])obj;
+                for (int i = 0; i < numBands; i++) {
+                    setSample(x, y, i, fdata[i], data);
+                }
+                break;
+
+            case DataBuffer.TYPE_DOUBLE:
+                double ddata[] = (double[])obj;
+                for (int i = 0; i < numBands; i++) {
+                    setSample(x, y, i, ddata[i], data);
+                }
+                break;
+        }
+    }
+
+    @Override
+    public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+        for (int i = 0; i < numBands; i++) {
+            setSample(x, y, i, iArray[i], data);
+        }
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) {
+        int idx = 0;
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                for (int n = 0; n < numBands; n++) {
+                    setSample(j, i, n, iArray[idx++], data);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setSample(int x, int y, int b, double s, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        data.setElemDouble(bankIndices[b], y * scanlineStride + x + bandOffsets[b], s);
+    }
+
+    @Override
+    public void setSample(int x, int y, int b, float s, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        data.setElemFloat(bankIndices[b], y * scanlineStride + x + bandOffsets[b], s);
+    }
+
+    @Override
+    public void setSample(int x, int y, int b, int s, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        data.setElem(bankIndices[b], y * scanlineStride + x + bandOffsets[b], s);
+    }
+
+    @Override
+    public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) {
+        int idx = 0;
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                setSample(j, i, b, iArray[idx++], data);
+            }
+        }
+
+    }
+
+}
diff --git a/awt/java/awt/image/BufferStrategy.java b/awt/java/awt/image/BufferStrategy.java
new file mode 100644
index 0000000..3c8779d
--- /dev/null
+++ b/awt/java/awt/image/BufferStrategy.java
@@ -0,0 +1,74 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.BufferCapabilities;
+import java.awt.Graphics;
+
+/**
+ * The BufferStrategy abstract class provides an opportunity to organize the
+ * buffers for a Canvas or Window. The BufferStrategy implementation depends on
+ * hardware and software limitations. These limitations are detectable through
+ * the capabilities object which can be obtained by the GraphicsConfiguration of
+ * the Canvas or Window.
+ * 
+ * @since Android 1.0
+ */
+public abstract class BufferStrategy {
+
+    /**
+     * Returns true if the drawing buffer was lost since the last call of
+     * getDrawGraphics.
+     * 
+     * @return true if the drawing buffer was lost since the last call of
+     *         getDrawGraphics, false otherwise.
+     */
+    public abstract boolean contentsLost();
+
+    /**
+     * Returns true if the drawing buffer is restored from a lost state.
+     * 
+     * @return true if the drawing buffer is restored from a lost state, false
+     *         otherwise.
+     */
+    public abstract boolean contentsRestored();
+
+    /**
+     * Gets the BufferCapabilities of BufferStrategy.
+     * 
+     * @return the BufferCapabilities of BufferStrategy.
+     */
+    public abstract BufferCapabilities getCapabilities();
+
+    /**
+     * Gets the Graphics object to use to draw to the buffer.
+     * 
+     * @return the Graphics object to use to draw to the buffer.
+     */
+    public abstract Graphics getDrawGraphics();
+
+    /**
+     * Shows the next available buffer.
+     */
+    public abstract void show();
+
+}
diff --git a/awt/java/awt/image/BufferedImage.java b/awt/java/awt/image/BufferedImage.java
new file mode 100644
index 0000000..c9d58d9
--- /dev/null
+++ b/awt/java/awt/image/BufferedImage.java
@@ -0,0 +1,952 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.image.BufferedImageSource;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The BufferedImage class describes an Image which contains a buffer of image
+ * data and includes a ColorModel and a Raster for this data. This class
+ * provides methods for obtaining and setting the Raster and for manipulating
+ * the ColorModel parameters.
+ * 
+ * @since Android 1.0
+ */
+public class BufferedImage extends Image implements WritableRenderedImage, Transparency {
+
+    /**
+     * The Constant TYPE_CUSTOM indicates that Image type is unknown.
+     */
+    public static final int TYPE_CUSTOM = 0;
+
+    /**
+     * The Constant TYPE_INT_RGB indicates an image with 8 bit RGB color
+     * components, it has a DirectColorModel without alpha.
+     */
+    public static final int TYPE_INT_RGB = 1;
+
+    /**
+     * The Constant TYPE_INT_ARGB indicates an image with 8 bit RGBA color
+     * components, it has a DirectColorModel with alpha.
+     */
+    public static final int TYPE_INT_ARGB = 2;
+
+    /**
+     * The Constant TYPE_INT_ARGB_PRE indicates an image with 8 bit RGBA color
+     * components, it has a DirectColorModel with alpha, and image data is
+     * pre-multiplied by alpha.
+     */
+    public static final int TYPE_INT_ARGB_PRE = 3;
+
+    /**
+     * The Constant TYPE_INT_BGR indicates an image with 8 bit RGB color
+     * components, BGR color model (with the colors Blue, Green, and Red). There
+     * is no alpha. The image has a DirectColorModel.
+     */
+    public static final int TYPE_INT_BGR = 4;
+
+    /**
+     * The Constant TYPE_3BYTE_BGR indicates an image with 8 bit RGB color
+     * components, BGR color model (with the colors Blue, Green, and Red stored
+     * in 3 bytes). There is no alpha. The image has a ComponentColorModel.
+     */
+    public static final int TYPE_3BYTE_BGR = 5;
+
+    /**
+     * The Constant TYPE_4BYTE_ABGR indicates an image with 8 bit RGBA color
+     * components stored in 3 bytes and 1 byte of alpha. It has a
+     * ComponentColorModel with alpha.
+     */
+    public static final int TYPE_4BYTE_ABGR = 6;
+
+    /**
+     * The Constant TYPE_4BYTE_ABGR_PRE indicates an image with 8 bit RGBA color
+     * components stored in 3 bytes and 1 byte for alpha. The image has a
+     * ComponentColorModel with alpha. The color data is pre-multiplied with
+     * alpha.
+     */
+    public static final int TYPE_4BYTE_ABGR_PRE = 7;
+
+    /**
+     * The Constant TYPE_USHORT_565_RGB indicates an image with 565 RGB color
+     * components (5-bits red, 6-bits green, 5-bits blue) with no alpha. This
+     * image has a DirectColorModel.
+     */
+    public static final int TYPE_USHORT_565_RGB = 8;
+
+    /**
+     * The Constant TYPE_USHORT_555_RGB indicates an image with 555 RGB color
+     * components (5-bits red, 5-bits green, 5-bits blue) with no alpha. This
+     * image has a DirectColorModel.
+     */
+    public static final int TYPE_USHORT_555_RGB = 9;
+
+    /**
+     * The Constant TYPE_BYTE_GRAY indicates a unsigned byte image. This image
+     * has a ComponentColorModel with a CS_GRAY ColorSpace.
+     */
+    public static final int TYPE_BYTE_GRAY = 10;
+
+    /**
+     * The Constant TYPE_USHORT_GRAY indicates an unsigned short image. This
+     * image has a ComponentColorModel with a CS_GRAY ColorSpace.
+     */
+    public static final int TYPE_USHORT_GRAY = 11;
+
+    /**
+     * The Constant TYPE_BYTE_BINARY indicates an opaque byte-packed 1, 2 or 4
+     * bit image. The image has an IndexColorModel without alpha.
+     */
+    public static final int TYPE_BYTE_BINARY = 12;
+
+    /**
+     * The Constant TYPE_BYTE_INDEXED indicates an indexed byte image.
+     */
+    public static final int TYPE_BYTE_INDEXED = 13;
+
+    /**
+     * The Constant ALPHA_MASK.
+     */
+    private static final int ALPHA_MASK = 0xff000000;
+
+    /**
+     * The Constant RED_MASK.
+     */
+    private static final int RED_MASK = 0x00ff0000;
+
+    /**
+     * The Constant GREEN_MASK.
+     */
+    private static final int GREEN_MASK = 0x0000ff00;
+
+    /**
+     * The Constant BLUE_MASK.
+     */
+    private static final int BLUE_MASK = 0x000000ff;
+
+    /**
+     * The Constant RED_BGR_MASK.
+     */
+    private static final int RED_BGR_MASK = 0x000000ff;
+
+    /**
+     * The Constant GREEN_BGR_MASK.
+     */
+    private static final int GREEN_BGR_MASK = 0x0000ff00;
+
+    /**
+     * The Constant BLUE_BGR_MASK.
+     */
+    private static final int BLUE_BGR_MASK = 0x00ff0000;
+
+    /**
+     * The Constant RED_565_MASK.
+     */
+    private static final int RED_565_MASK = 0xf800;
+
+    /**
+     * The Constant GREEN_565_MASK.
+     */
+    private static final int GREEN_565_MASK = 0x07e0;
+
+    /**
+     * The Constant BLUE_565_MASK.
+     */
+    private static final int BLUE_565_MASK = 0x001f;
+
+    /**
+     * The Constant RED_555_MASK.
+     */
+    private static final int RED_555_MASK = 0x7c00;
+
+    /**
+     * The Constant GREEN_555_MASK.
+     */
+    private static final int GREEN_555_MASK = 0x03e0;
+
+    /**
+     * The Constant BLUE_555_MASK.
+     */
+    private static final int BLUE_555_MASK = 0x001f;
+
+    /**
+     * The cm.
+     */
+    private ColorModel cm;
+
+    /**
+     * The raster.
+     */
+    private final WritableRaster raster;
+
+    /**
+     * The image type.
+     */
+    private final int imageType;
+
+    /**
+     * The properties.
+     */
+    private Hashtable<?, ?> properties;
+
+    // Surface of the Buffered Image - used for blitting one Buffered Image
+    // on the other one or on the Component
+    /**
+     * The image surf.
+     */
+    private final ImageSurface imageSurf;
+
+    /**
+     * Instantiates a new BufferedImage with the specified ColorModel, and
+     * WritableRaster objects. The Raster data can be be divided or multiplied
+     * by alpha. It depends on the alphaPremultiplied state in the ColorModel.
+     * 
+     * @param cm
+     *            the ColorModel of the new image.
+     * @param raster
+     *            the WritableRaster of the new image.
+     * @param isRasterPremultiplied
+     *            if true the data of the specified Raster is pre-multiplied by
+     *            alpha.
+     * @param properties
+     *            the properties of new Image.
+     */
+    public BufferedImage(ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied,
+            Hashtable<?, ?> properties) {
+        if (!cm.isCompatibleRaster(raster)) {
+            // awt.4D=The raster is incompatible with this ColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
+        }
+
+        if (raster.getMinX() != 0 || raster.getMinY() != 0) {
+            // awt.228=minX or minY of this raster not equal to zero
+            throw new IllegalArgumentException(Messages.getString("awt.228")); //$NON-NLS-1$
+        }
+
+        this.cm = cm;
+        this.raster = raster;
+        this.properties = properties;
+
+        coerceData(isRasterPremultiplied);
+
+        imageType = Surface.getType(cm, raster);
+
+        imageSurf = createImageSurface(imageType);
+    }
+
+    /**
+     * Instantiates a new BufferedImage with the specified width, height
+     * predefined image type (TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED) and the
+     * specified IndexColorModel.
+     * 
+     * @param width
+     *            the width of new image.
+     * @param height
+     *            the height of new image.
+     * @param imageType
+     *            the predefined image type.
+     * @param cm
+     *            the specified IndexColorModel.
+     */
+    public BufferedImage(int width, int height, int imageType, IndexColorModel cm) {
+        switch (imageType) {
+            case TYPE_BYTE_BINARY:
+                if (cm.hasAlpha()) {
+                    // awt.227=This image type can't have alpha
+                    throw new IllegalArgumentException(Messages.getString("awt.227")); //$NON-NLS-1$
+                }
+                int pixel_bits = 0;
+                int mapSize = cm.getMapSize();
+                if (mapSize <= 2) {
+                    pixel_bits = 1;
+                } else if (mapSize <= 4) {
+                    pixel_bits = 2;
+                } else if (mapSize <= 16) {
+                    pixel_bits = 4;
+                } else {
+                    // awt.221=The imageType is TYPE_BYTE_BINARY and the color
+                    // map has more than 16 entries
+                    throw new IllegalArgumentException(Messages.getString("awt.221")); //$NON-NLS-1$
+                }
+
+                raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1,
+                        pixel_bits, null);
+                break;
+
+            case TYPE_BYTE_INDEXED:
+                raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1,
+                        null);
+                break;
+
+            default:
+                // awt.222=The imageType is not TYPE_BYTE_BINARY or
+                // TYPE_BYTE_INDEXED
+                throw new IllegalArgumentException(Messages.getString("awt.222")); //$NON-NLS-1$
+
+        }
+
+        if (!cm.isCompatibleRaster(raster)) {
+            // awt.223=The imageType is not compatible with ColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.223")); //$NON-NLS-1$
+        }
+
+        this.cm = cm;
+        this.imageType = imageType;
+        imageSurf = createImageSurface(imageType);
+
+    }
+
+    /**
+     * Instantiates a new BufferedImage with the specified width, height and
+     * predefined image type.
+     * 
+     * @param width
+     *            the width of new image.
+     * @param height
+     *            the height of new image.
+     * @param imageType
+     *            the predefined image type.
+     */
+    public BufferedImage(int width, int height, int imageType) {
+
+        switch (imageType) {
+            case TYPE_INT_RGB:
+                cm = new DirectColorModel(24, RED_MASK, GREEN_MASK, BLUE_MASK);
+                raster = cm.createCompatibleWritableRaster(width, height);
+                break;
+
+            case TYPE_INT_ARGB:
+                cm = ColorModel.getRGBdefault();
+                raster = cm.createCompatibleWritableRaster(width, height);
+                break;
+
+            case TYPE_INT_ARGB_PRE:
+                cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, RED_MASK,
+                        GREEN_MASK, BLUE_MASK, ALPHA_MASK, true, DataBuffer.TYPE_INT);
+
+                raster = cm.createCompatibleWritableRaster(width, height);
+                break;
+
+            case TYPE_INT_BGR:
+                cm = new DirectColorModel(24, RED_BGR_MASK, GREEN_BGR_MASK, BLUE_BGR_MASK);
+
+                raster = cm.createCompatibleWritableRaster(width, height);
+                break;
+
+            case TYPE_3BYTE_BGR: {
+                int bits[] = {
+                        8, 8, 8
+                };
+                int bandOffsets[] = {
+                        2, 1, 0
+                };
+                cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits,
+                        false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
+
+                raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height,
+                        width * 3, 3, bandOffsets, null);
+            }
+                break;
+
+            case TYPE_4BYTE_ABGR: {
+                int bits[] = {
+                        8, 8, 8, 8
+                };
+                int bandOffsets[] = {
+                        3, 2, 1, 0
+                };
+                cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits,
+                        true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
+
+                raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height,
+                        width * 4, 4, bandOffsets, null);
+            }
+                break;
+
+            case TYPE_4BYTE_ABGR_PRE: {
+                int bits[] = {
+                        8, 8, 8, 8
+                };
+                int bandOffsets[] = {
+                        3, 2, 1, 0
+                };
+                cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits,
+                        true, true, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
+
+                raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height,
+                        width * 4, 4, bandOffsets, null);
+            }
+                break;
+
+            case TYPE_USHORT_565_RGB:
+                cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 16,
+                        RED_565_MASK, GREEN_565_MASK, BLUE_565_MASK, 0, false,
+                        DataBuffer.TYPE_USHORT);
+
+                raster = cm.createCompatibleWritableRaster(width, height);
+                break;
+
+            case TYPE_USHORT_555_RGB:
+                cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 15,
+                        RED_555_MASK, GREEN_555_MASK, BLUE_555_MASK, 0, false,
+                        DataBuffer.TYPE_USHORT);
+
+                raster = cm.createCompatibleWritableRaster(width, height);
+                break;
+
+            case TYPE_BYTE_GRAY: {
+                int bits[] = {
+                    8
+                };
+                cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bits,
+                        false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
+
+                raster = cm.createCompatibleWritableRaster(width, height);
+            }
+                break;
+
+            case TYPE_USHORT_GRAY: {
+                int bits[] = {
+                    16
+                };
+                cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bits,
+                        false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
+                raster = cm.createCompatibleWritableRaster(width, height);
+            }
+                break;
+
+            case TYPE_BYTE_BINARY: {
+                int colorMap[] = {
+                        0, 0xffffff
+                };
+                cm = new IndexColorModel(1, 2, colorMap, 0, false, -1, DataBuffer.TYPE_BYTE);
+
+                raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, 1, null);
+            }
+                break;
+
+            case TYPE_BYTE_INDEXED: {
+                int colorMap[] = new int[256];
+                int i = 0;
+                for (int r = 0; r < 256; r += 51) {
+                    for (int g = 0; g < 256; g += 51) {
+                        for (int b = 0; b < 256; b += 51) {
+                            colorMap[i] = (r << 16) | (g << 8) | b;
+                            i++;
+                        }
+                    }
+                }
+
+                int gray = 0x12;
+                for (; i < 256; i++, gray += 6) {
+                    colorMap[i] = (gray << 16) | (gray << 8) | gray;
+                }
+                cm = new IndexColorModel(8, 256, colorMap, 0, false, -1, DataBuffer.TYPE_BYTE);
+                raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1,
+                        null);
+
+            }
+                break;
+            default:
+                // awt.224=Unknown image type
+                throw new IllegalArgumentException(Messages.getString("awt.224")); //$NON-NLS-1$
+        }
+        this.imageType = imageType;
+        imageSurf = createImageSurface(imageType);
+    }
+
+    @Override
+    public Object getProperty(String name, ImageObserver observer) {
+        return getProperty(name);
+    }
+
+    public Object getProperty(String name) {
+        if (name == null) {
+            // awt.225=Property name is null
+            throw new NullPointerException(Messages.getString("awt.225")); //$NON-NLS-1$
+        }
+        if (properties == null) {
+            return Image.UndefinedProperty;
+        }
+        Object property = properties.get(name);
+        if (property == null) {
+            property = Image.UndefinedProperty;
+        }
+        return property;
+    }
+
+    public WritableRaster copyData(WritableRaster outRaster) {
+        if (outRaster == null) {
+            outRaster = Raster.createWritableRaster(raster.getSampleModel(), new Point(raster
+                    .getSampleModelTranslateX(), raster.getSampleModelTranslateY()));
+        }
+
+        int w = outRaster.getWidth();
+        int h = outRaster.getHeight();
+        int minX = outRaster.getMinX();
+        int minY = outRaster.getMinY();
+
+        Object data = null;
+
+        data = raster.getDataElements(minX, minY, w, h, data);
+        outRaster.setDataElements(minX, minY, w, h, data);
+
+        return outRaster;
+    }
+
+    public Raster getData(Rectangle rect) {
+        int minX = rect.x;
+        int minY = rect.y;
+        int w = rect.width;
+        int h = rect.height;
+
+        SampleModel sm = raster.getSampleModel();
+        SampleModel nsm = sm.createCompatibleSampleModel(w, h);
+        WritableRaster outr = Raster.createWritableRaster(nsm, rect.getLocation());
+        Object data = null;
+
+        data = raster.getDataElements(minX, minY, w, h, data);
+        outr.setDataElements(minX, minY, w, h, data);
+        return outr;
+    }
+
+    public Vector<RenderedImage> getSources() {
+        return null;
+    }
+
+    public String[] getPropertyNames() {
+        if (properties == null) {
+            return null;
+        }
+        Vector<String> v = new Vector<String>();
+        for (Enumeration<?> e = properties.keys(); e.hasMoreElements();) {
+            try {
+                v.add((String)e.nextElement());
+            } catch (ClassCastException ex) {
+            }
+        }
+        int size = v.size();
+        if (size > 0) {
+            String names[] = new String[size];
+            for (int i = 0; i < size; i++) {
+                names[i] = v.elementAt(i);
+            }
+            return names;
+        }
+        return null;
+    }
+
+    /**
+     * Returns the string representation of this BufferedImage object.
+     * 
+     * @return the string representation of this BufferedImage object.
+     */
+    @Override
+    public String toString() {
+        return "BufferedImage@" + Integer.toHexString(hashCode()) + //$NON-NLS-1$
+                ": type = " + imageType + " " + cm + " " + raster; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+
+    public WritableRaster getWritableTile(int tileX, int tileY) {
+        return raster;
+    }
+
+    /**
+     * Gets the WritableRaster of this BufferedImage.
+     * 
+     * @return the WritableRaster of this BufferedImage.
+     */
+    public WritableRaster getRaster() {
+        return raster;
+    }
+
+    /**
+     * Gets a WritableRaster object which contains the alpha channel of
+     * BufferedImage object with ColorModel objects that supports a separate
+     * alpha channel such as ComponentColorModel or DirectColorModel.
+     * 
+     * @return the WritableRaster object which contains the alpha channel of
+     *         this BufferedImage.
+     */
+    public WritableRaster getAlphaRaster() {
+        return cm.getAlphaRaster(raster);
+    }
+
+    public void removeTileObserver(TileObserver to) {
+    }
+
+    public void addTileObserver(TileObserver to) {
+    }
+
+    public SampleModel getSampleModel() {
+        return raster.getSampleModel();
+    }
+
+    public void setData(Raster r) {
+
+        Rectangle from = r.getBounds();
+        Rectangle to = raster.getBounds();
+        Rectangle intersection = to.intersection(from);
+
+        int minX = intersection.x;
+        int minY = intersection.y;
+        int w = intersection.width;
+        int h = intersection.height;
+
+        Object data = null;
+
+        data = r.getDataElements(minX, minY, w, h, data);
+        raster.setDataElements(minX, minY, w, h, data);
+    }
+
+    public Raster getTile(int tileX, int tileY) {
+        if (tileX == 0 && tileY == 0) {
+            return raster;
+        }
+        // awt.226=Both tileX and tileY are not equal to 0
+        throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$
+    }
+
+    public Raster getData() {
+        int w = raster.getWidth();
+        int h = raster.getHeight();
+        int minX = raster.getMinX();
+        int minY = raster.getMinY();
+
+        WritableRaster outr = Raster.createWritableRaster(raster.getSampleModel(), new Point(raster
+                .getSampleModelTranslateX(), raster.getSampleModelTranslateY()));
+
+        Object data = null;
+
+        data = raster.getDataElements(minX, minY, w, h, data);
+        outr.setDataElements(minX, minY, w, h, data);
+
+        return outr;
+    }
+
+    @Override
+    public ImageProducer getSource() {
+        return new BufferedImageSource(this, properties);
+    }
+
+    @Override
+    public int getWidth(ImageObserver observer) {
+        return raster.getWidth();
+    }
+
+    @Override
+    public int getHeight(ImageObserver observer) {
+        return raster.getHeight();
+    }
+
+    public ColorModel getColorModel() {
+        return cm;
+    }
+
+    /**
+     * Gets the rectangular area of this BufferedImage as a subimage.
+     * 
+     * @param x
+     *            the x coordinate.
+     * @param y
+     *            the y coordinate.
+     * @param w
+     *            the width of the subimage.
+     * @param h
+     *            the height of the subimage.
+     * @return the BufferedImage.
+     */
+    public BufferedImage getSubimage(int x, int y, int w, int h) {
+        WritableRaster wr = raster.createWritableChild(x, y, w, h, 0, 0, null);
+        return new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), properties);
+    }
+
+    public Point[] getWritableTileIndices() {
+        Point points[] = new Point[1];
+        points[0] = new Point(0, 0);
+        return points;
+    }
+
+    /**
+     * Creates the Graphics2D object which allows to draw into this
+     * BufferedImage.
+     * 
+     * @return the graphics2D object.
+     */
+    public Graphics2D createGraphics() {
+        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        // return ge.createGraphics(this);
+        // ???AWT hack, FIXME
+        // return AndroidGraphics2D.getInstance();
+        // throw new RuntimeException("Not implemented!");
+        return null;
+    }
+
+    @Override
+    public Graphics getGraphics() {
+        return createGraphics();
+    }
+
+    /**
+     * Coerces the data to achieve the state which is specified by the
+     * isAlphaPremultiplied variable.
+     * 
+     * @param isAlphaPremultiplied
+     *            the is alpha pre-multiplied state.
+     */
+    public void coerceData(boolean isAlphaPremultiplied) {
+        if (cm.hasAlpha() && cm.isAlphaPremultiplied() != isAlphaPremultiplied) {
+            cm = cm.coerceData(raster, isAlphaPremultiplied);
+        }
+    }
+
+    /**
+     * Gets an array of colors in the TYPE_INT_ARGB color model and default sRGB
+     * color space of the specified area of this BufferedImage. The result array
+     * is composed by the following algorithm:
+     * <p>
+     * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)]
+     * </p>
+     * 
+     * @param startX
+     *            the start X area coordinate.
+     * @param startY
+     *            the start Y area coordinate.
+     * @param w
+     *            the width of the area.
+     * @param h
+     *            the height of the area.
+     * @param rgbArray
+     *            the result array will be stored to this array.
+     * @param offset
+     *            the offset of the rgbArray array.
+     * @param scansize
+     *            the scanline stride for the rgbArray.
+     * @return an array of colors for the specified area.
+     */
+    public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset,
+            int scansize) {
+        if (rgbArray == null) {
+            rgbArray = new int[offset + h * scansize];
+        }
+
+        int off = offset;
+        for (int y = startY; y < startY + h; y++, off += scansize) {
+            int i = off;
+            for (int x = startX; x < startX + w; x++, i++) {
+                rgbArray[i] = cm.getRGB(raster.getDataElements(x, y, null));
+            }
+        }
+        return rgbArray;
+    }
+
+    /**
+     * Sets RGB values from the specified array to the specified BufferedImage
+     * area. The pixels are in the default RGB color model (TYPE_INT_ARGB) and
+     * default sRGB color space.
+     * 
+     * @param startX
+     *            the start X coordinate.
+     * @param startY
+     *            the start Y coordinate.
+     * @param w
+     *            the width of the BufferedImage area.
+     * @param h
+     *            the height of the BufferedImage area.
+     * @param rgbArray
+     *            the array of RGB values.
+     * @param offset
+     *            the offset of the rgbArray array.
+     * @param scansize
+     *            the scanline stride for the rgbArray.
+     */
+    public void setRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset,
+            int scansize) {
+        int off = offset;
+        for (int y = startY; y < startY + h; y++, off += scansize) {
+            int i = off;
+            for (int x = startX; x < startX + w; x++, i++) {
+                raster.setDataElements(x, y, cm.getDataElements(rgbArray[i], null));
+            }
+        }
+    }
+
+    /**
+     * Sets a the specified RGB value to the specified pixel of this
+     * BufferedImage. The pixel should be in the default RGB color model
+     * (TYPE_INT_ARGB) and default sRGB color space.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param rgb
+     *            the RGB value to be set.
+     */
+    public synchronized void setRGB(int x, int y, int rgb) {
+        raster.setDataElements(x, y, cm.getDataElements(rgb, null));
+    }
+
+    public boolean isTileWritable(int tileX, int tileY) {
+        if (tileX == 0 && tileY == 0) {
+            return true;
+        }
+        // awt.226=Both tileX and tileY are not equal to 0
+        throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$
+    }
+
+    public void releaseWritableTile(int tileX, int tileY) {
+    }
+
+    /**
+     * Gets a color in the TYPE_INT_ARGB color model and default sRGB color
+     * space of the specified pixel.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @return the color of the specified pixel in the TYPE_INT_ARGB color model
+     *         and default sRGB color space.
+     */
+    public int getRGB(int x, int y) {
+        return cm.getRGB(raster.getDataElements(x, y, null));
+    }
+
+    /**
+     * Returns true if alpha is pre-multiplied, false if alpha is not
+     * pre-multiplied or there is no alpha.
+     * 
+     * @return true if alpha is pre-multiplied, false if alpha is not
+     *         pre-multiplied or there is no alpha.
+     */
+    public boolean isAlphaPremultiplied() {
+        return cm.isAlphaPremultiplied();
+    }
+
+    public boolean hasTileWriters() {
+        return true;
+    }
+
+    @Override
+    public void flush() {
+        imageSurf.dispose();
+    }
+
+    public int getWidth() {
+        return raster.getWidth();
+    }
+
+    /**
+     * Gets the image type.
+     * 
+     * @return the image type.
+     */
+    public int getType() {
+        return imageType;
+    }
+
+    public int getTileWidth() {
+        return raster.getWidth();
+    }
+
+    public int getTileHeight() {
+        return raster.getHeight();
+    }
+
+    public int getTileGridYOffset() {
+        return raster.getSampleModelTranslateY();
+    }
+
+    public int getTileGridXOffset() {
+        return raster.getSampleModelTranslateX();
+    }
+
+    public int getNumYTiles() {
+        return 1;
+    }
+
+    public int getNumXTiles() {
+        return 1;
+    }
+
+    public int getMinY() {
+        return raster.getMinY();
+    }
+
+    public int getMinX() {
+        return raster.getMinX();
+    }
+
+    public int getMinTileY() {
+        return 0;
+    }
+
+    public int getMinTileX() {
+        return 0;
+    }
+
+    public int getHeight() {
+        return raster.getHeight();
+    }
+
+    /**
+     * Creates the image surface.
+     * 
+     * @param type
+     *            the type.
+     * @return the image surface.
+     */
+    private ImageSurface createImageSurface(int type) {
+        return new ImageSurface(getColorModel(), getRaster(), type);
+    }
+
+    /**
+     * Gets the image surface.
+     * 
+     * @return the image surface.
+     */
+    ImageSurface getImageSurface() {
+        return imageSurf;
+    }
+
+    public int getTransparency() {
+        return cm.getTransparency();
+    }
+}
diff --git a/awt/java/awt/image/BufferedImageFilter.java b/awt/java/awt/image/BufferedImageFilter.java
new file mode 100644
index 0000000..8b6fcf0
--- /dev/null
+++ b/awt/java/awt/image/BufferedImageFilter.java
@@ -0,0 +1,397 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The BufferedImageFilter class provides filtering operations to the
+ * BufferedImage objects using operators which implement BufferedImageOp
+ * interface.
+ * 
+ * @since Android 1.0
+ */
+public class BufferedImageFilter extends ImageFilter implements Cloneable {
+
+    /**
+     * The Constant accessor.
+     */
+    private static final AwtImageBackdoorAccessor accessor = AwtImageBackdoorAccessor.getInstance();
+
+    /**
+     * The op.
+     */
+    private BufferedImageOp op;
+
+    /**
+     * The raster.
+     */
+    private WritableRaster raster;
+
+    /**
+     * The i data.
+     */
+    private int iData[];
+
+    /**
+     * The b data.
+     */
+    private byte bData[];
+
+    /**
+     * The width.
+     */
+    private int width;
+
+    /**
+     * The height.
+     */
+    private int height;
+
+    /**
+     * The cm.
+     */
+    private ColorModel cm;
+
+    /**
+     * The forced rgb.
+     */
+    private boolean forcedRGB = false;
+
+    /**
+     * The transfer type.
+     */
+    private int transferType = DataBuffer.TYPE_UNDEFINED;
+
+    /**
+     * Instantiates a new BufferedImageFilter with the specified BufferedImageOp
+     * operator.
+     * 
+     * @param op
+     *            the specified BufferedImageOp operator.
+     * @throws NullPointerException
+     *             if BufferedImageOp is null.
+     */
+    public BufferedImageFilter(BufferedImageOp op) {
+        if (op == null) {
+            throw new NullPointerException(Messages.getString("awt.05")); //$NON-NLS-1$
+        }
+        this.op = op;
+    }
+
+    /**
+     * Gets the BufferedImageOp operator associated with this
+     * BufferedImageFilter object.
+     * 
+     * @return the BufferedImageOp associated with this BufferedImageFilter
+     *         object.
+     */
+    public BufferedImageOp getBufferedImageOp() {
+        return op;
+    }
+
+    @Override
+    public void setDimensions(int width, int height) {
+        this.width = width;
+        this.height = height;
+        // Stop image consuming if no pixels expected.
+        if (width <= 0 || height <= 0) {
+            consumer.imageComplete(ImageConsumer.STATICIMAGEDONE);
+            reset();
+        }
+    }
+
+    @Override
+    public void setColorModel(ColorModel model) {
+        if (this.cm != null && this.cm != model && raster != null) {
+            forceRGB();
+        } else {
+            this.cm = model;
+        }
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off,
+            int scansize) {
+        setPixels(x, y, w, h, model, pixels, off, scansize, true);
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off,
+            int scansize) {
+        setPixels(x, y, w, h, model, pixels, off, scansize, false);
+    }
+
+    @Override
+    public void imageComplete(int status) {
+        if (status == STATICIMAGEDONE || status == SINGLEFRAMEDONE) {
+            BufferedImage bim = new BufferedImage(cm, raster, cm.isAlphaPremultiplied, null);
+            bim = op.filter(bim, null);
+            DataBuffer dstDb = bim.getRaster().getDataBuffer();
+            ColorModel dstCm = bim.getColorModel();
+            int dstW = bim.getWidth();
+            int dstH = bim.getHeight();
+
+            consumer.setDimensions(dstW, dstH);
+
+            if (dstDb.getDataType() == DataBuffer.TYPE_INT) {
+                consumer.setColorModel(dstCm);
+                consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataInt(dstDb), 0, dstW);
+            } else if (dstDb.getDataType() == DataBuffer.TYPE_BYTE) {
+                consumer.setColorModel(dstCm);
+                consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataByte(dstDb), 0, dstW);
+            } else {
+                int dstData[] = bim.getRGB(0, 0, dstW, dstH, null, 0, dstW);
+                dstCm = ColorModel.getRGBdefault();
+                consumer.setColorModel(dstCm);
+                consumer.setPixels(0, 0, dstW, dstH, dstCm, dstData, 0, dstW);
+            }
+        } else if (status == IMAGEERROR || status == IMAGEABORTED) {
+            reset();
+        }
+
+        consumer.imageComplete(status);
+    }
+
+    /**
+     * Sets the pixels.
+     * 
+     * @param x
+     *            the x.
+     * @param y
+     *            the y.
+     * @param w
+     *            the w.
+     * @param h
+     *            the h.
+     * @param model
+     *            the model.
+     * @param pixels
+     *            the pixels.
+     * @param off
+     *            the off.
+     * @param scansize
+     *            the scansize.
+     * @param isByteData
+     *            the is byte data.
+     */
+    private void setPixels(int x, int y, int w, int h, ColorModel model, Object pixels, int off,
+            int scansize, boolean isByteData) {
+        // Check bounds
+        // Need to copy only the pixels that will fit into the destination area
+        if (x < 0) {
+            w -= x;
+            off += x;
+            x = 0;
+        }
+
+        if (y < 0) {
+            h -= y;
+            off += y * scansize;
+            y = 0;
+        }
+
+        if (x + w > width) {
+            w = width - x;
+        }
+
+        if (y + h > height) {
+            h = height - y;
+        }
+
+        if (w <= 0 || h <= 0) {
+            return;
+        }
+
+        // Check model
+        if (this.cm == null) {
+            setColorModel(model);
+        } else if (model == null) {
+            model = this.cm;
+        } else if (!model.equals(this.cm)) {
+            forceRGB();
+        }
+
+        boolean canArraycopy;
+        // Process pixels
+        switch (transferType) {
+            case DataBuffer.TYPE_UNDEFINED: {
+                if (isByteData) {
+                    transferType = DataBuffer.TYPE_BYTE;
+                    createRaster(transferType);
+                    // bData = new byte[width*height];
+                    canArraycopy = !forcedRGB;
+                    break;
+                }
+                transferType = DataBuffer.TYPE_INT;
+                createRaster(transferType);
+                // iData = new int[width*height];
+                canArraycopy = !forcedRGB || model.equals(ColorModel.getRGBdefault());
+                break;
+            } // And proceed to copy the pixels
+            case DataBuffer.TYPE_INT: {
+                if (isByteData) { // There are int data already but the new data
+                    // are bytes
+                    forceRGB();
+                    canArraycopy = false;
+                    break;
+                } else if (!forcedRGB || model.equals(ColorModel.getRGBdefault())) {
+                    canArraycopy = true;
+                    break;
+                } // Else fallback to the RGB conversion
+            }
+            case DataBuffer.TYPE_BYTE: {
+                if (isByteData && !forcedRGB) {
+                    canArraycopy = true;
+                    break;
+                }
+
+                // RGB conversion
+                canArraycopy = false;
+                break;
+            }
+            default: {
+                throw new IllegalStateException(Messages.getString("awt.06")); //$NON-NLS-1$
+            }
+        }
+
+        off += x;
+        int maxOffset = off + h * scansize;
+        int dstOffset = x + y * width;
+
+        if (canArraycopy) {
+            Object dstArray = isByteData ? (Object)bData : (Object)iData;
+            for (; off < maxOffset; off += scansize, dstOffset += width) {
+                System.arraycopy(pixels, off, dstArray, dstOffset, w);
+            }
+        } else {
+            // RGB conversion
+            for (; off < maxOffset; off += scansize, dstOffset += width) {
+                int srcPos = off;
+                int dstPos = dstOffset;
+                int maxDstPos = dstOffset + w;
+                for (; dstPos < maxDstPos; dstPos++, srcPos++) {
+                    iData[dstPos] = model.getRGB(isByteData ? ((byte[])pixels)[srcPos]
+                            : ((int[])pixels)[srcPos]);
+                }
+            }
+        }
+    }
+
+    /**
+     * Force rgb.
+     */
+    private void forceRGB() {
+        if (!forcedRGB) {
+            forcedRGB = true;
+            int size = width * height;
+            int rgbData[] = new int[size];
+
+            if (bData != null) {
+                for (int i = 0; i < size; i++) {
+                    rgbData[i] = cm.getRGB(bData[i]);
+                }
+            } else if (iData != null) {
+                for (int i = 0; i < size; i++) {
+                    rgbData[i] = cm.getRGB(iData[i]);
+                }
+            }
+
+            cm = ColorModel.getRGBdefault();
+            DataBufferInt db = new DataBufferInt(rgbData, size);
+            int masks[] = new int[] {
+                    0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000
+            };
+            raster = Raster.createPackedRaster(db, width, height, width, masks, null);
+            iData = accessor.getDataInt(db);
+            bData = null;
+            transferType = DataBuffer.TYPE_INT;
+        }
+    }
+
+    /**
+     * Reset.
+     */
+    private void reset() {
+        width = 0;
+        height = 0;
+        forcedRGB = false;
+        cm = null;
+        iData = null;
+        bData = null;
+        transferType = DataBuffer.TYPE_UNDEFINED;
+        raster = null;
+    }
+
+    /**
+     * Creates the raster.
+     * 
+     * @param dataType
+     *            the data type.
+     */
+    private void createRaster(int dataType) {
+        boolean createdValidBuffer = false;
+        try {
+            raster = cm.createCompatibleWritableRaster(width, height);
+            int rasterType = raster.getDataBuffer().getDataType();
+            if (rasterType == dataType) {
+                switch (rasterType) {
+                    case DataBuffer.TYPE_INT: {
+                        iData = accessor.getDataInt(raster.getDataBuffer());
+                        if (iData != null) {
+                            createdValidBuffer = true;
+                        }
+                        break;
+                    }
+                    case DataBuffer.TYPE_BYTE: {
+                        bData = accessor.getDataByte(raster.getDataBuffer());
+                        if (bData != null) {
+                            createdValidBuffer = true;
+                        }
+                        break;
+                    }
+                    default:
+                        createdValidBuffer = false;
+                }
+
+                if (cm == ColorModel.getRGBdefault()) {
+                    forcedRGB = true;
+                }
+            } else {
+                createdValidBuffer = false;
+            }
+        } catch (Exception e) {
+            createdValidBuffer = false;
+        }
+
+        if (createdValidBuffer == false) {
+            cm = ColorModel.getRGBdefault();
+            raster = cm.createCompatibleWritableRaster(width, height);
+            iData = accessor.getDataInt(raster.getDataBuffer());
+            bData = null;
+            forcedRGB = true;
+        }
+    }
+}
diff --git a/awt/java/awt/image/BufferedImageOp.java b/awt/java/awt/image/BufferedImageOp.java
new file mode 100644
index 0000000..883a39d
--- /dev/null
+++ b/awt/java/awt/image/BufferedImageOp.java
@@ -0,0 +1,92 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.RenderingHints;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The BufferedImageOp interface provides methods for performing transformations
+ * from source data to destination data for BufferedImage objects. An object
+ * implementing this interface can be passed into a BufferedImageFilter to
+ * operate on a BufferedImage.
+ * 
+ * @since Android 1.0
+ */
+public interface BufferedImageOp {
+
+    /**
+     * Creates a destination image with the specified BufferedImage and
+     * ColorModel; this destination image is empty and has the correct size and
+     * number of bands.
+     * 
+     * @param src
+     *            the source BufferedImage.
+     * @param destCM
+     *            the destination ColorModel.
+     * @return the BufferedImage.
+     */
+    public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM);
+
+    /**
+     * Performs a filter operation on the source BufferedImage and stores the
+     * resulting BufferedImage to the destination BufferedImage. If the
+     * destination BufferedImage is null, a BufferedImage with an appropriate
+     * ColorModel is created.
+     * 
+     * @param src
+     *            the source BufferedImage.
+     * @param dest
+     *            the destination BufferedImage, where the result is stored.
+     * @return the filtered BufferedImage.
+     */
+    public BufferedImage filter(BufferedImage src, BufferedImage dest);
+
+    /**
+     * Gets the bounds of filtered image.
+     * 
+     * @param src
+     *            the source BufferedImage to be filtered.
+     * @return the rectangle bounds of filtered image.
+     */
+    public Rectangle2D getBounds2D(BufferedImage src);
+
+    /**
+     * Gets the point of the destination image which corresponds to the
+     * specified point in the source image.
+     * 
+     * @param srcPt
+     *            the point of the source image.
+     * @param dstPt
+     *            the point where the result will be stored.
+     * @return the destination point.
+     */
+    public Point2D getPoint2D(Point2D srcPt, Point2D dstPt);
+
+    /**
+     * Gets the RenderingHints of the BufferedImageOp.
+     * 
+     * @return the RenderingHints of the BufferedImageOp.
+     */
+    public RenderingHints getRenderingHints();
+}
diff --git a/awt/java/awt/image/ByteLookupTable.java b/awt/java/awt/image/ByteLookupTable.java
new file mode 100644
index 0000000..27cee30
--- /dev/null
+++ b/awt/java/awt/image/ByteLookupTable.java
@@ -0,0 +1,140 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 14, 2005
+ */
+
+package java.awt.image;
+
+/**
+ * The ByteLookupTable class provides functionality for lookup operations, and
+ * is defined by an input byte array for bands or components of image and an
+ * offset value. The offset value will be subtracted from the input values
+ * before indexing the input arrays. The output of a lookup operation is
+ * represented as an array of unsigned bytes.
+ * 
+ * @since Android 1.0
+ */
+public class ByteLookupTable extends LookupTable {
+
+    /**
+     * The data.
+     */
+    private byte data[][];
+
+    /**
+     * Instantiates a new ByteLookupTable with the specified offset value and
+     * the specified byte array which represents the lookup table for all bands.
+     * 
+     * @param offset
+     *            the offset value.
+     * @param data
+     *            the data array of bytes.
+     */
+    public ByteLookupTable(int offset, byte[] data) {
+        super(offset, 1);
+        if (data.length < 1)
+            throw new IllegalArgumentException("Length of data should not be less then one");
+        this.data = new byte[1][data.length];
+        // The data array stored as a reference
+        this.data[0] = data;
+    }
+
+    /**
+     * Instantiates a new ByteLookupTable with the specified offset value and
+     * the specified byte array of arrays which represents the lookup table for
+     * each band.
+     * 
+     * @param offset
+     *            the offset value.
+     * @param data
+     *            the data array of bytes array for each band.
+     */
+    public ByteLookupTable(int offset, byte[][] data) {
+        super(offset, data.length);
+        this.data = new byte[data.length][data[0].length];
+        for (int i = 0; i < data.length; i++) {
+            // The data array for each band stored as a reference
+            this.data[i] = data[i];
+        }
+    }
+
+    /**
+     * Gets the lookup table of this ByteLookupTable object. If this
+     * ByteLookupTable object has one byte array for all bands, the returned
+     * array length is one.
+     * 
+     * @return the lookup table of this ByteLookupTable object.
+     */
+    public final byte[][] getTable() {
+        // Returns data by reference
+        return data;
+    }
+
+    @Override
+    public int[] lookupPixel(int[] src, int[] dst) {
+        if (dst == null) {
+            dst = new int[src.length];
+        }
+
+        int offset = getOffset();
+        if (getNumComponents() == 1) {
+            for (int i = 0; i < src.length; i++) {
+                dst[i] = data[0][src[i] - offset];
+            }
+        } else {
+            for (int i = 0; i < getNumComponents(); i++) {
+                dst[i] = data[i][src[i] - offset];
+            }
+        }
+
+        return dst;
+    }
+
+    /**
+     * Returns a byte array which contains samples of the specified pixel which
+     * is translated with the lookup table of this ByteLookupTable object. The
+     * resulted array is stored to the dst array.
+     * 
+     * @param src
+     *            the source array.
+     * @param dst
+     *            the destination array where the result can be stored.
+     * @return the byte array of translated samples of a pixel.
+     */
+    public byte[] lookupPixel(byte[] src, byte[] dst) {
+        if (dst == null) {
+            dst = new byte[src.length];
+        }
+
+        int offset = getOffset();
+        if (getNumComponents() == 1) {
+            for (int i = 0; i < src.length; i++) {
+                dst[i] = data[0][src[i] - offset];
+            }
+        } else {
+            for (int i = 0; i < getNumComponents(); i++) {
+                dst[i] = data[i][src[i] - offset];
+            }
+        }
+
+        return dst;
+    }
+}
diff --git a/awt/java/awt/image/ColorConvertOp.java b/awt/java/awt/image/ColorConvertOp.java
new file mode 100644
index 0000000..1a1700b
--- /dev/null
+++ b/awt/java/awt/image/ColorConvertOp.java
@@ -0,0 +1,710 @@
+/*
+ *  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.
+ */
+/** 
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.RenderingHints;
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_ColorSpace;
+import java.awt.color.ICC_Profile;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.gl.color.ColorConverter;
+import org.apache.harmony.awt.gl.color.ColorScaler;
+import org.apache.harmony.awt.gl.color.ICC_Transform;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ColorConvertOp class converts the pixels of the data in the source image
+ * with the specified ColorSpace objects or an array of ICC_Profile objects. The
+ * result pixels are scaled to the precision of the destination image.
+ * 
+ * @since Android 1.0
+ */
+public class ColorConvertOp implements BufferedImageOp, RasterOp {
+    // Unused but required by interfaces
+    /**
+     * The rendering hints.
+     */
+    RenderingHints renderingHints;
+
+    // Sequence consisting of ColorSpace and ICC_Profile elements
+    /**
+     * The conversion sequence.
+     */
+    Object conversionSequence[] = new ICC_Profile[0]; // To eliminate checks for
+
+    // null
+
+    // Not null if ColorConvertOp is constructed from the array of ICC profiles
+    /**
+     * The mid profiles.
+     */
+    private ICC_Profile midProfiles[];
+
+    /**
+     * The cc.
+     */
+    private final ColorConverter cc = new ColorConverter();
+
+    /**
+     * The t creator.
+     */
+    private final ICC_TransfomCreator tCreator = new ICC_TransfomCreator();
+
+    /**
+     * The is icc.
+     */
+    private boolean isICC = true;
+
+    // Cached ICC_Transform
+    /**
+     * The Class ICC_TransfomCreator.
+     */
+    private class ICC_TransfomCreator {
+
+        /**
+         * The transform.
+         */
+        private ICC_Transform transform;
+
+        /**
+         * The max components.
+         */
+        private int maxComponents;
+
+        /**
+         * For the full ICC case.
+         * 
+         * @param src
+         *            the src.
+         * @param dst
+         *            the dst.
+         * @param convSeq
+         *            the conv seq.
+         * @return the transform.
+         */
+        public ICC_Transform getTransform(ICC_Profile src, ICC_Profile dst, ICC_Profile convSeq[]) {
+            if (transform != null && src == transform.getSrc() && dst == transform.getDst()) {
+                return transform;
+            }
+
+            int length = convSeq.length;
+            int srcFlg = 0, dstFlg = 0;
+
+            if (length == 0 || src != convSeq[0]) {
+                if (src != null) {
+                    srcFlg = 1; // need src profile
+                }
+            }
+            if (length == 0 || dst != convSeq[length - 1]) {
+                if (dst != null) {
+                    dstFlg = 1; // need dst profile
+                }
+            }
+
+            ICC_Profile profiles[];
+            int nProfiles = length + srcFlg + dstFlg;
+            if (nProfiles == length) {
+                profiles = convSeq;
+            } else {
+                profiles = new ICC_Profile[nProfiles];
+                int pos = 0;
+                if (srcFlg != 0) {
+                    profiles[pos++] = src;
+                }
+                for (int i = 0; i < length; i++) {
+                    profiles[pos++] = convSeq[i];
+                }
+                if (dstFlg != 0) {
+                    profiles[pos++] = dst;
+                }
+            }
+
+            return transform = new ICC_Transform(profiles);
+        }
+
+        /**
+         * Used only when there are non-ICC color spaces. Returns sequence of
+         * non-ICC color spaces and ICC transforms made from src, dst and
+         * conversionSequence.
+         * 
+         * @param src
+         *            the src.
+         * @param dst
+         *            the dst.
+         * @return the sequence.
+         */
+        public Object[] getSequence(Object src, Object dst) {
+            ArrayList<Object> profiles = new ArrayList<Object>(10);
+            ArrayList<Object> sequence = new ArrayList<Object>(10);
+
+            // We need this profile anyway
+            ICC_Profile xyzProfile = ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ);
+
+            Object conversionFirst = null, conversionLast = null;
+            int conversionLength = conversionSequence.length;
+            if (conversionLength > 0) {
+                conversionFirst = conversionSequence[0];
+                conversionLast = conversionSequence[conversionLength - 1];
+            }
+
+            boolean iccSequenceStarted = false;
+
+            if (src != conversionFirst && src != null) {
+                if (src instanceof ICC_Profile) {
+                    profiles.add(src);
+                    iccSequenceStarted = true;
+                } else {
+                    profiles.add(xyzProfile);
+                    sequence.add(src); // Add non-ICC color space to the
+                    // sequence
+                }
+            } else {
+                profiles.add(xyzProfile);
+            }
+
+            for (int i = 0; i < conversionLength; i++) {
+                if (conversionSequence[i] instanceof ICC_Profile) {
+                    profiles.add(conversionSequence[i]);
+                    iccSequenceStarted = true;
+                } else if (iccSequenceStarted) {
+                    profiles.add(xyzProfile);
+
+                    // Eliminate same profiles if there are any
+                    // (e.g. xyzProfile may occur several times)
+                    Object prev = profiles.get(0);
+                    for (int k = 1; k < profiles.size(); k++) {
+                        if (prev == profiles.get(k)) {
+                            k--;
+                            profiles.remove(k);
+                        }
+                        prev = profiles.get(k);
+                    }
+
+                    // If only one profile left we skip the transform -
+                    // it can be only CIEXYZ
+                    if (profiles.size() > 1) {
+                        sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0])));
+
+                        // Add non-ICC color space to the sequence
+                        sequence.add(conversionSequence[i]);
+                    }
+
+                    profiles.clear();
+                    profiles.add(xyzProfile);
+                    iccSequenceStarted = false; // Sequence of ICC profiles is
+                    // processed
+                } else { // Add non-ICC color space to the sequence
+                    sequence.add(conversionSequence[i]);
+                }
+            }
+
+            if (dst != conversionLast && dst != null) { // Add last profile if
+                // needed
+                if (dst instanceof ICC_Profile) {
+                    profiles.add(dst);
+                    iccSequenceStarted = true;
+                } else if (iccSequenceStarted) {
+                    profiles.add(xyzProfile);
+                } else {
+                    sequence.add(dst); // Add last non-ICC color space to the
+                    // sequence
+                }
+            }
+
+            if (iccSequenceStarted) { // Make last transform if needed
+                sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0])));
+                if (dst != null && !(dst instanceof ICC_Profile)) {
+                    sequence.add(dst); // Add last non-ICC color space to the
+                    // sequence
+                }
+            }
+
+            // Calculate max number of components
+            // This number will be used for memory allocation
+            maxComponents = 0;
+            Object o;
+            for (int i = 0, size = sequence.size(); i < size; i++) {
+                o = sequence.get(i);
+                if (o instanceof ICC_Transform) {
+                    ICC_Transform t = (ICC_Transform)o;
+                    maxComponents = (maxComponents > t.getNumInputChannels() + 1) ? maxComponents
+                            : t.getNumInputChannels() + 1;
+                    maxComponents = (maxComponents > t.getNumOutputChannels() + 1) ? maxComponents
+                            : t.getNumOutputChannels() + 1;
+                } else {
+                    ColorSpace cs = (ColorSpace)o;
+                    maxComponents = (maxComponents > cs.getNumComponents() + 1) ? maxComponents
+                            : cs.getNumComponents() + 1;
+                }
+            }
+
+            return sequence.toArray();
+        }
+    }
+
+    /**
+     * Instantiates a new ColorConvertOp object using two specified ColorSpace
+     * objects.
+     * 
+     * @param srcCS
+     *            the source ColorSpace.
+     * @param dstCS
+     *            the destination ColorSpace.
+     * @param hints
+     *            the RenderingHints object used for the color conversion, or
+     *            null.
+     */
+    public ColorConvertOp(ColorSpace srcCS, ColorSpace dstCS, RenderingHints hints) {
+        if (srcCS == null || dstCS == null) {
+            throw new NullPointerException(Messages.getString("awt.25B")); //$NON-NLS-1$
+        }
+
+        renderingHints = hints;
+
+        boolean srcICC = srcCS instanceof ICC_ColorSpace;
+        boolean dstICC = dstCS instanceof ICC_ColorSpace;
+
+        if (srcICC && dstICC) {
+            conversionSequence = new ICC_Profile[2];
+        } else {
+            conversionSequence = new Object[2];
+            isICC = false;
+        }
+
+        if (srcICC) {
+            conversionSequence[0] = ((ICC_ColorSpace)srcCS).getProfile();
+        } else {
+            conversionSequence[0] = srcCS;
+        }
+
+        if (dstICC) {
+            conversionSequence[1] = ((ICC_ColorSpace)dstCS).getProfile();
+        } else {
+            conversionSequence[1] = dstCS;
+        }
+    }
+
+    /**
+     * Instantiates a new ColorConvertOp object from the specified ICC_Profile
+     * objects.
+     * 
+     * @param profiles
+     *            the array of ICC_Profile objects.
+     * @param hints
+     *            the RenderingHints object used for the color conversion, or
+     *            null.
+     */
+    public ColorConvertOp(ICC_Profile profiles[], RenderingHints hints) {
+        if (profiles == null) {
+            throw new NullPointerException(Messages.getString("awt.25C")); //$NON-NLS-1$
+        }
+
+        renderingHints = hints;
+
+        // This array is not used in the program logic, so don't need to copy it
+        // Store it only to return back
+        midProfiles = profiles;
+
+        conversionSequence = new ICC_Profile[midProfiles.length];
+
+        // Add profiles to the conversion sequence
+        for (int i = 0, length = midProfiles.length; i < length; i++) {
+            conversionSequence[i] = midProfiles[i];
+        }
+    }
+
+    /**
+     * Instantiates a new ColorConvertOp object using the specified ColorSpace
+     * object.
+     * 
+     * @param cs
+     *            the destination ColorSpace or an intermediate ColorSpace.
+     * @param hints
+     *            the RenderingHints object used for the color conversion, or
+     *            null.
+     */
+    public ColorConvertOp(ColorSpace cs, RenderingHints hints) {
+        if (cs == null) {
+            throw new NullPointerException(Messages.getString("awt.25B")); //$NON-NLS-1$
+        }
+
+        renderingHints = hints;
+
+        if (cs instanceof ICC_ColorSpace) {
+            conversionSequence = new ICC_Profile[1];
+            conversionSequence[0] = ((ICC_ColorSpace)cs).getProfile();
+        } else {
+            conversionSequence = new Object[1];
+            conversionSequence[0] = cs;
+            isICC = false;
+        }
+    }
+
+    /**
+     * Instantiates a new ColorConvertOp object which converts from a source
+     * color space to a destination color space.
+     * 
+     * @param hints
+     *            the RenderingHints object used for the color conversion, or
+     *            null.
+     */
+    public ColorConvertOp(RenderingHints hints) {
+        renderingHints = hints;
+    }
+
+    public final WritableRaster filter(Raster src, WritableRaster dst) {
+        if (conversionSequence.length < 2) {
+            throw new IllegalArgumentException(Messages.getString("awt.25D")); //$NON-NLS-1$
+        }
+
+        ICC_Profile srcPf = null, dstPf = null; // unused if isICC is false
+        int nSrcColorComps, nDstColorComps;
+        Object first = conversionSequence[0];
+        Object last = conversionSequence[conversionSequence.length - 1];
+
+        // Get the number of input/output color components
+        if (isICC) {
+            srcPf = (ICC_Profile)first;
+            dstPf = (ICC_Profile)last;
+            nSrcColorComps = srcPf.getNumComponents();
+            nDstColorComps = dstPf.getNumComponents();
+        } else {
+            if (first instanceof ICC_Profile) {
+                srcPf = (ICC_Profile)first;
+                nSrcColorComps = srcPf.getNumComponents();
+            } else {
+                nSrcColorComps = ((ColorSpace)first).getNumComponents();
+            }
+
+            if (last instanceof ICC_Profile) {
+                dstPf = (ICC_Profile)last;
+                nDstColorComps = dstPf.getNumComponents();
+            } else {
+                nDstColorComps = ((ColorSpace)last).getNumComponents();
+            }
+        }
+
+        // Check that source and destination rasters are compatible with
+        // transforms and with each other
+        if (src.getNumBands() != nSrcColorComps) {
+            // awt.25E=Incorrect number of source raster bands. Should be equal
+            // to the number of color components of source colorspace.
+            throw new IllegalArgumentException(Messages.getString("awt.25E")); //$NON-NLS-1$
+        }
+
+        if (dst != null) { // Check destination raster
+            if (dst.getNumBands() != nDstColorComps) {
+                // awt.25F=Incorrect number of destination raster bands. Should
+                // be equal to the number of color components of destination
+                // colorspace.
+                throw new IllegalArgumentException(Messages.getString("awt.25F")); //$NON-NLS-1$
+            }
+
+            if (src.getWidth() != dst.getWidth() || src.getHeight() != dst.getHeight()) {
+                throw new IllegalArgumentException(Messages.getString("awt.260")); //$NON-NLS-1$
+            }
+
+        } else {
+            dst = createCompatibleDestRaster(src);
+        }
+
+        if (isICC) {
+            // Create transform
+            ICC_Transform t = tCreator
+                    .getTransform(srcPf, dstPf, (ICC_Profile[])conversionSequence);
+            cc.translateColor(t, src, dst);
+        } else {
+            Object[] sequence = tCreator.getSequence(null, null);
+
+            // Get data from the source raster
+            ColorScaler scaler = new ColorScaler();
+            scaler.loadScalingData(src, null);
+            float tmpData[][] = scaler.scaleNormalize(src);
+
+            // Get source and destination color spaces
+            ColorSpace srcCS = (srcPf == null) ? (ColorSpace)first : new ICC_ColorSpace(srcPf);
+            ColorSpace dstCS = (dstPf == null) ? (ColorSpace)last : new ICC_ColorSpace(dstPf);
+
+            applySequence(sequence, tmpData, srcCS, dstCS);
+
+            scaler.loadScalingData(dst, null);
+            scaler.unscaleNormalized(dst, tmpData);
+        }
+
+        return dst;
+    }
+
+    public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
+        // If destination color model is passed only one line needed
+        if (destCM != null) {
+            return new BufferedImage(destCM, destCM.createCompatibleWritableRaster(src.getWidth(),
+                    src.getHeight()), destCM.isAlphaPremultiplied(), null);
+        }
+
+        int nSpaces = conversionSequence.length;
+
+        if (nSpaces < 1) {
+            throw new IllegalArgumentException(Messages.getString("awt.261")); //$NON-NLS-1$
+        }
+
+        // Get destination color space
+        Object destination = conversionSequence[nSpaces - 1];
+        ColorSpace dstCS = (destination instanceof ColorSpace) ? (ColorSpace)destination
+                : new ICC_ColorSpace((ICC_Profile)destination);
+
+        ColorModel srcCM = src.getColorModel();
+        ColorModel dstCM = new ComponentColorModel(dstCS, srcCM.hasAlpha(), srcCM
+                .isAlphaPremultiplied(), srcCM.getTransparency(), srcCM.getTransferType());
+
+        return new BufferedImage(dstCM, destCM.createCompatibleWritableRaster(src.getWidth(), src
+                .getHeight()), destCM.isAlphaPremultiplied(), null);
+    }
+
+    public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+        if (dst == null && conversionSequence.length < 1) {
+            throw new IllegalArgumentException(Messages.getString("awt.262")); //$NON-NLS-1$
+        }
+
+        ColorModel srcCM = src.getColorModel();
+        // First handle index color model
+        if (srcCM instanceof IndexColorModel) {
+            src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), false);
+        }
+        ColorSpace srcCS = srcCM.getColorSpace();
+
+        BufferedImage res;
+        boolean isDstIndex = false;
+        if (dst != null) {
+
+            if (src.getWidth() != dst.getWidth() || src.getHeight() != dst.getHeight()) {
+                throw new IllegalArgumentException(Messages.getString("awt.263")); //$NON-NLS-1$
+            }
+
+            if (dst.getColorModel() instanceof IndexColorModel) {
+                isDstIndex = true;
+                res = createCompatibleDestImage(src, null);
+            } else {
+                res = dst;
+            }
+        } else {
+            res = createCompatibleDestImage(src, null);
+        }
+        ColorModel dstCM = res.getColorModel();
+        ColorSpace dstCS = dstCM.getColorSpace();
+
+        ICC_Profile srcPf = null, dstPf = null;
+        if (srcCS instanceof ICC_ColorSpace) {
+            srcPf = ((ICC_ColorSpace)srcCS).getProfile();
+        }
+        if (dstCS instanceof ICC_ColorSpace) {
+            dstPf = ((ICC_ColorSpace)dstCS).getProfile();
+        }
+
+        boolean isFullICC = isICC && srcPf != null && dstPf != null;
+
+        if (isFullICC) {
+            ICC_Transform t = tCreator
+                    .getTransform(srcPf, dstPf, (ICC_Profile[])conversionSequence);
+            cc.translateColor(t, src, res);
+        } else { // Perform non-ICC transform
+            Object sequence[] = tCreator.getSequence(srcPf == null ? (Object)srcCS : srcPf,
+                    dstPf == null ? (Object)dstCS : dstPf);
+
+            int srcW = src.getWidth();
+            int srcH = src.getHeight();
+            int numPixels = srcW * srcH;
+
+            // Load all pixel data into array tmpData
+            float tmpData[][] = new float[numPixels][tCreator.maxComponents];
+            for (int row = 0, dataPos = 0; row < srcW; row++) {
+                for (int col = 0; col < srcH; col++) {
+                    tmpData[dataPos] = srcCM.getNormalizedComponents(src.getRaster()
+                            .getDataElements(row, col, null), tmpData[dataPos], 0);
+                    dataPos++;
+                }
+            }
+
+            // Copy alpha channel if needed
+            float alpha[] = null;
+            int alphaIdx = srcCM.numComponents - 1;
+            if (srcCM.hasAlpha() && dstCM.hasAlpha()) {
+                alpha = new float[numPixels];
+                for (int i = 0; i < numPixels; i++) {
+                    alpha[i] = tmpData[i][alphaIdx];
+                }
+            }
+
+            // Translate colors
+            applySequence(sequence, tmpData, srcCS, dstCS);
+
+            // Copy alpha if needed
+            if (dstCM.hasAlpha()) {
+                alphaIdx = dstCM.numComponents - 1;
+                if (alpha != null) {
+                    for (int i = 0; i < numPixels; i++) {
+                        tmpData[i][alphaIdx] = alpha[i];
+                    }
+                } else {
+                    for (int i = 0; i < numPixels; i++) {
+                        tmpData[i][alphaIdx] = 1f;
+                    }
+                }
+            }
+
+            // Store data back to the image
+            for (int row = 0, dataPos = 0; row < srcW; row++) {
+                for (int col = 0; col < srcH; col++) {
+                    res.getRaster().setDataElements(row, col,
+                            dstCM.getDataElements(tmpData[dataPos++], 0, null));
+                }
+            }
+        }
+
+        if (isDstIndex) { // Convert image into indexed color
+            Graphics2D g2d = dst.createGraphics();
+            g2d.drawImage(res, 0, 0, null);
+            g2d.dispose();
+            return dst;
+        }
+
+        return res;
+    }
+
+    /**
+     * Apply sequence.
+     * 
+     * @param sequence
+     *            the sequence.
+     * @param tmpData
+     *            the tmp data.
+     * @param srcCS
+     *            the src cs.
+     * @param dstCS
+     *            the dst cs.
+     */
+    private void applySequence(Object sequence[], float tmpData[][], ColorSpace srcCS,
+            ColorSpace dstCS) {
+        ColorSpace xyzCS = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
+
+        int numPixels = tmpData.length;
+
+        // First transform...
+        if (sequence[0] instanceof ICC_Transform) { // ICC
+            ICC_Transform t = (ICC_Transform)sequence[0];
+            cc.translateColor(t, tmpData, srcCS, xyzCS, numPixels);
+        } else { // non ICC
+            for (int k = 0; k < numPixels; k++) {
+                tmpData[k] = srcCS.toCIEXYZ(tmpData[k]);
+            }
+            cc.loadScalingData(xyzCS); // prepare for scaling XYZ
+        }
+
+        for (Object element : sequence) {
+            if (element instanceof ICC_Transform) {
+                ICC_Transform t = (ICC_Transform)element;
+                cc.translateColor(t, tmpData, null, null, numPixels);
+            } else {
+                ColorSpace cs = (ColorSpace)element;
+                for (int k = 0; k < numPixels; k++) {
+                    tmpData[k] = cs.fromCIEXYZ(tmpData[k]);
+                    tmpData[k] = cs.toCIEXYZ(tmpData[k]);
+                }
+            }
+        }
+
+        // Last transform...
+        if (sequence[sequence.length - 1] instanceof ICC_Transform) { // ICC
+            ICC_Transform t = (ICC_Transform)sequence[sequence.length - 1];
+            cc.translateColor(t, tmpData, xyzCS, dstCS, numPixels);
+        } else { // non ICC
+            for (int k = 0; k < numPixels; k++) {
+                tmpData[k] = dstCS.fromCIEXYZ(tmpData[k]);
+            }
+        }
+    }
+
+    public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+        if (dstPt != null) {
+            dstPt.setLocation(srcPt);
+            return dstPt;
+        }
+        return new Point2D.Float((float)srcPt.getX(), (float)srcPt.getY());
+    }
+
+    public WritableRaster createCompatibleDestRaster(Raster src) {
+        int nComps = 0;
+        int nSpaces = conversionSequence.length;
+
+        if (nSpaces < 2) {
+            throw new IllegalArgumentException(Messages.getString("awt.261")); //$NON-NLS-1$
+        }
+
+        Object lastCS = conversionSequence[nSpaces - 1];
+        if (lastCS instanceof ColorSpace) {
+            nComps = ((ColorSpace)lastCS).getNumComponents();
+        } else {
+            nComps = ((ICC_Profile)lastCS).getNumComponents();
+        }
+
+        // Calculate correct data type
+        int dstDataType = src.getDataBuffer().getDataType();
+        if (dstDataType != DataBuffer.TYPE_BYTE && dstDataType != DataBuffer.TYPE_SHORT) {
+            dstDataType = DataBuffer.TYPE_SHORT;
+        }
+
+        return Raster.createInterleavedRaster(dstDataType, src.getWidth(), src.getHeight(), nComps,
+                new Point(src.getMinX(), src.getMinY()));
+    }
+
+    public final Rectangle2D getBounds2D(Raster src) {
+        return src.getBounds();
+    }
+
+    public final Rectangle2D getBounds2D(BufferedImage src) {
+        return src.getRaster().getBounds();
+    }
+
+    /**
+     * Gets an array of ICC_Profiles objects which constructs this
+     * ColorConvertOp object or returns null if this ColorConvertOp is not
+     * constructed from array of ICC_Profiles.
+     * 
+     * @return an array of ICC_Profiles objects which constructs this
+     *         ColorConvertOp object or returns null if this ColorConvertOp is
+     *         not constructed from array of ICC_Profiles.
+     */
+    public final ICC_Profile[] getICC_Profiles() {
+        if (midProfiles != null) {
+            return midProfiles;
+        }
+        return null;
+    }
+
+    public final RenderingHints getRenderingHints() {
+        return renderingHints;
+    }
+}
diff --git a/awt/java/awt/image/ColorModel.java b/awt/java/awt/image/ColorModel.java
new file mode 100644
index 0000000..1b084e1
--- /dev/null
+++ b/awt/java/awt/image/ColorModel.java
@@ -0,0 +1,964 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The class ColorModel.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ColorModel implements Transparency {
+
+    /**
+     * The pixel_bits.
+     */
+    protected int pixel_bits; // Pixel length in bits
+
+    /**
+     * The transfer type.
+     */
+    protected int transferType;
+
+    /**
+     * The cs.
+     */
+    ColorSpace cs;
+
+    /**
+     * The has alpha.
+     */
+    boolean hasAlpha;
+
+    /**
+     * The is alpha premultiplied.
+     */
+    boolean isAlphaPremultiplied;
+
+    /**
+     * The transparency.
+     */
+    int transparency;
+
+    /**
+     * The num color components.
+     */
+    int numColorComponents;
+
+    /**
+     * The num components.
+     */
+    int numComponents;
+
+    /**
+     * The bits.
+     */
+    int[] bits; // Array of components masks
+
+    /**
+     * The max values.
+     */
+    int[] maxValues = null; // Max values that may be represent by color
+
+    // components
+
+    /**
+     * The max bit length.
+     */
+    int maxBitLength; // Max length color components in bits
+
+    /**
+     * The RG bdefault.
+     */
+    private static ColorModel RGBdefault;
+
+    /**
+     * Instantiates a new color model with the specified values.
+     * 
+     * @param pixel_bits
+     *            the pixel length in bits.
+     * @param bits
+     *            the array of component masks.
+     * @param cspace
+     *            the color space.
+     * @param hasAlpha
+     *            whether the color model has alpha.
+     * @param isAlphaPremultiplied
+     *            whether the alpha is pre-multiplied.
+     * @param transparency
+     *            the transparency strategy, @see java.awt.Transparency.
+     * @param transferType
+     *            the transfer type (primitive java type to use for the
+     *            components).
+     */
+    protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace, boolean hasAlpha,
+            boolean isAlphaPremultiplied, int transparency, int transferType) {
+
+        if (pixel_bits < 1) {
+            // awt.26B=The number of bits in the pixel values is less than 1
+            throw new IllegalArgumentException(Messages.getString("awt.26B")); //$NON-NLS-1$
+        }
+
+        if (bits == null) {
+            // awt.26C=bits is null
+            throw new NullPointerException(Messages.getString("awt.26C")); //$NON-NLS-1$
+        }
+
+        int sum = 0;
+        for (int element : bits) {
+            if (element < 0) {
+                // awt.26D=The elements in bits is less than 0
+                throw new IllegalArgumentException(Messages.getString("awt.26D")); //$NON-NLS-1$
+            }
+            sum += element;
+        }
+
+        if (sum < 1) {
+            // awt.26E=The sum of the number of bits in bits is less than 1
+            throw new NullPointerException(Messages.getString("awt.26E")); //$NON-NLS-1$
+        }
+
+        if (cspace == null) {
+            // awt.26F=The cspace is null
+            throw new IllegalArgumentException(Messages.getString("awt.26F")); //$NON-NLS-1$
+        }
+
+        if (transparency < Transparency.OPAQUE || transparency > Transparency.TRANSLUCENT) {
+            // awt.270=The transparency is not a valid value
+            throw new IllegalArgumentException(Messages.getString("awt.270")); //$NON-NLS-1$
+        }
+
+        this.pixel_bits = pixel_bits;
+        this.bits = bits.clone();
+
+        maxValues = new int[bits.length];
+        maxBitLength = 0;
+        for (int i = 0; i < maxValues.length; i++) {
+            maxValues[i] = (1 << bits[i]) - 1;
+            if (bits[i] > maxBitLength) {
+                maxBitLength = bits[i];
+            }
+        }
+
+        cs = cspace;
+        this.hasAlpha = hasAlpha;
+        this.isAlphaPremultiplied = isAlphaPremultiplied;
+        numColorComponents = cs.getNumComponents();
+
+        if (hasAlpha) {
+            numComponents = numColorComponents + 1;
+        } else {
+            numComponents = numColorComponents;
+        }
+
+        this.transparency = transparency;
+        this.transferType = transferType;
+
+    }
+
+    /**
+     * Instantiates a new color model with the specified pixel bit depth. The
+     * transferType is chosen based on the pixel bits, and the other data fields
+     * are given default values.
+     * 
+     * @param bits
+     *            the array of component masks.
+     */
+    public ColorModel(int bits) {
+
+        if (bits < 1) {
+            // awt.271=The number of bits in bits is less than 1
+            throw new IllegalArgumentException(Messages.getString("awt.271")); //$NON-NLS-1$
+        }
+
+        pixel_bits = bits;
+        transferType = getTransferType(bits);
+        cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+        hasAlpha = true;
+        isAlphaPremultiplied = false;
+        transparency = Transparency.TRANSLUCENT;
+
+        numColorComponents = 3;
+        numComponents = 4;
+
+        this.bits = null;
+    }
+
+    /**
+     * Gets the data elements from the specified component array, transforming
+     * them according to rules of the color model.
+     * 
+     * @param components
+     *            the components.
+     * @param offset
+     *            the offset in the normComponents array.
+     * @param obj
+     *            the array that the result is written to: an array of values
+     *            whose length must be the number of components used by the
+     *            color model and whose type depends on the transfer type (based
+     *            on the pixel bit depth), or null to have the appropriate array
+     *            created.
+     * @return the array of data elements.
+     */
+    public Object getDataElements(int[] components, int offset, Object obj) {
+        throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+                "supported by this ColorModel"); //$NON-NLS-1$
+    }
+
+    /**
+     * Gets the data elements from the specified array of normalized components.
+     * 
+     * @param normComponents
+     *            the array normalized components.
+     * @param normOffset
+     *            the offset in the normComponents array.
+     * @param obj
+     *            the array that the result is written to: an array of values
+     *            whose length must be the number of components used by the
+     *            color model and whose type depends on the transfer type (based
+     *            on the pixel bit depth), or null to have the appropriate array
+     *            created.
+     * @return the array of data elements.
+     */
+    public Object getDataElements(float[] normComponents, int normOffset, Object obj) {
+        int unnormComponents[] = getUnnormalizedComponents(normComponents, normOffset, null, 0);
+        return getDataElements(unnormComponents, 0, obj);
+    }
+
+    /**
+     * Gets the data elements corresponding to the pixel determined by the RGB
+     * data.
+     * 
+     * @param rgb
+     *            the RGB integer value that defines the pixel.
+     * @param pixel
+     *            the array that the result is written to: an array of values
+     *            whose length must be the number of components used by the
+     *            color model and whose type depends on the transfer type (based
+     *            on the pixel bit depth), or null to have the appropriate array
+     *            created.
+     * @return the array of data elements.
+     */
+    public Object getDataElements(int rgb, Object pixel) {
+        throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+                "supported by this ColorModel"); //$NON-NLS-1$
+    }
+
+    /**
+     * Gets the child raster corresponding to the alpha channel of the specified
+     * writable raster, or null if alpha is not supported.
+     * 
+     * @param raster
+     *            the raster.
+     * @return the alpha raster.
+     */
+    public WritableRaster getAlphaRaster(WritableRaster raster) {
+        return null;
+    }
+
+    /**
+     * Creates a new color model by coercing the data in the writable raster in
+     * accordance with the alpha strategy of this color model.
+     * 
+     * @param raster
+     *            the raster.
+     * @param isAlphaPremultiplied
+     *            whether the alpha is pre-multiplied in this color model
+     * @return the new color model.
+     */
+    public ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) {
+        throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+                "supported by this ColorModel"); //$NON-NLS-1$
+    }
+
+    @Override
+    public String toString() {
+        // The output format based on 1.5 release behavior.
+        // It could be reveled such way:
+        // ColorModel cm = new
+        // ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB,
+        // false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
+        // System.out.println(cm.toString());
+        return "ColorModel: Color Space = " + cs.toString() + "; has alpha = " //$NON-NLS-1$ //$NON-NLS-2$
+                + hasAlpha + "; is alpha premultipied = " //$NON-NLS-1$
+                + isAlphaPremultiplied + "; transparency = " + transparency //$NON-NLS-1$
+                + "; number color components = " + numColorComponents //$NON-NLS-1$
+                + "; pixel bits = " + pixel_bits + "; transfer type = " //$NON-NLS-1$ //$NON-NLS-2$
+                + transferType;
+    }
+
+    /**
+     * Gets the components of the pixel determined by the data array.
+     * 
+     * @param pixel
+     *            the data array that defines the pixel (whose primitive type
+     *            corresponds to the pixel length in bits.
+     * @see ColorModel#getTransferType()
+     * @param components
+     *            the the array where the resulting components are written (or
+     *            null to prompt the method to create the return array).
+     * @param offset
+     *            the offset that tells where the results should be written in
+     *            the return array.
+     * @return the array of components.
+     */
+    public int[] getComponents(Object pixel, int[] components, int offset) {
+        throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+                "supported by this ColorModel"); //$NON-NLS-1$
+    }
+
+    /**
+     * Gets the normalized components of the pixel determined by the data array.
+     * 
+     * @param pixel
+     *            the data array that defines the pixel (whose primitive type
+     *            corresponds to the pixel length in bits.
+     * @see ColorModel#getTransferType()
+     * @param normComponents
+     *            the array where the resulting normalized components are
+     *            written (or null to prompt the method to create the return
+     *            array).
+     * @param normOffset
+     *            the offset that tells where the results should be written in
+     *            the return array.
+     * @return the array of normalized components.
+     */
+    public float[] getNormalizedComponents(Object pixel, float[] normComponents, int normOffset) {
+
+        if (pixel == null) {
+            // awt.294=pixel is null
+            throw new NullPointerException(Messages.getString("awt.294")); //$NON-NLS-1$
+        }
+
+        int unnormComponents[] = getComponents(pixel, null, 0);
+        return getNormalizedComponents(unnormComponents, 0, normComponents, normOffset);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof ColorModel)) {
+            return false;
+        }
+        ColorModel cm = (ColorModel)obj;
+
+        return (pixel_bits == cm.getPixelSize() && transferType == cm.getTransferType()
+                && cs.getType() == cm.getColorSpace().getType() && hasAlpha == cm.hasAlpha()
+                && isAlphaPremultiplied == cm.isAlphaPremultiplied()
+                && transparency == cm.getTransparency()
+                && numColorComponents == cm.getNumColorComponents()
+                && numComponents == cm.getNumComponents() && Arrays.equals(bits, cm
+                .getComponentSize()));
+    }
+
+    /**
+     * Gets the red component of the pixel determined by the data array.
+     * 
+     * @param inData
+     *            the data array that defines the pixel (whose primitive type
+     *            corresponds to the pixel length in bits.
+     * @see ColorModel#getTransferType()
+     * @return the red.
+     */
+    public int getRed(Object inData) {
+        return getRed(constructPixel(inData));
+    }
+
+    /**
+     * Gets the RGB integer value corresponding to the pixel defined by the data
+     * array.
+     * 
+     * @param inData
+     *            the data array that defines the pixel (whose primitive type
+     *            corresponds to the pixel length in bits.
+     * @see ColorModel#getTransferType()
+     * @return the integer value that gives the pixel's colors in RGB format.
+     */
+    public int getRGB(Object inData) {
+        return (getAlpha(inData) << 24 | getRed(inData) << 16 | getGreen(inData) << 8 | getBlue(inData));
+    }
+
+    /**
+     * Gets the green component of the pixel defined by the data array.
+     * 
+     * @param inData
+     *            the data array that defines the pixel (whose primitive type
+     *            corresponds to the pixel length in bits.
+     * @see ColorModel#getTransferType()
+     * @return the green.
+     */
+    public int getGreen(Object inData) {
+        return getGreen(constructPixel(inData));
+    }
+
+    /**
+     * Gets the blue component of the pixel defined by the data array.
+     * 
+     * @param inData
+     *            the data array that defines the pixel (whose primitive type
+     *            corresponds to the pixel length in bits.
+     * @see ColorModel#getTransferType()
+     * @return the blue.
+     */
+    public int getBlue(Object inData) {
+        return getBlue(constructPixel(inData));
+    }
+
+    /**
+     * Gets the alpha component of the pixel defined by the data array.
+     * 
+     * @param inData
+     *            the data array that defines the pixel (whose primitive type
+     *            corresponds to the pixel length in bits.
+     * @see ColorModel#getTransferType()
+     * @return the alpha.
+     */
+    public int getAlpha(Object inData) {
+        return getAlpha(constructPixel(inData));
+    }
+
+    /**
+     * Creates a compatible writable raster.
+     * 
+     * @param w
+     *            the width of the desired writable raster.
+     * @param h
+     *            the height of the desired writable raster.
+     * @return the writable raster.
+     */
+    public WritableRaster createCompatibleWritableRaster(int w, int h) {
+        throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+                "supported by this ColorModel"); //$NON-NLS-1$
+    }
+
+    /**
+     * Checks if the sample model is compatible with this color model.
+     * 
+     * @param sm
+     *            the sample model.
+     * @return true, if the sample model is compatible with this color model.
+     */
+    public boolean isCompatibleSampleModel(SampleModel sm) {
+        throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+                "supported by this ColorModel"); //$NON-NLS-1$
+    }
+
+    /**
+     * Creates the compatible sample model.
+     * 
+     * @param w
+     *            the width of the desired sample model.
+     * @param h
+     *            the height of the desired sample model.
+     * @return the sample model.
+     */
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+        throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+                "supported by this ColorModel"); //$NON-NLS-1$
+    }
+
+    /**
+     * Checks if the specified raster is compatible with this color model.
+     * 
+     * @param raster
+     *            the raster to inspect.
+     * @return true, if the raster is compatible with this color model.
+     */
+    public boolean isCompatibleRaster(Raster raster) {
+        throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+                "supported by this ColorModel"); //$NON-NLS-1$
+    }
+
+    /**
+     * Gets the color space of this color model.
+     * 
+     * @return the color space.
+     */
+    public final ColorSpace getColorSpace() {
+        return cs;
+    }
+
+    /**
+     * Gets the normalized components corresponding to the specified
+     * unnormalized components.
+     * 
+     * @param components
+     *            the array of unnormalized components.
+     * @param offset
+     *            the offset where the components should be read from the array
+     *            of unnormalized components.
+     * @param normComponents
+     *            the array where the resulting normalized components are
+     *            written (or null to prompt the method to create the return
+     *            array).
+     * @param normOffset
+     *            the offset that tells where the results should be written in
+     *            the return array.
+     * @return the normalized components.
+     */
+    public float[] getNormalizedComponents(int[] components, int offset, float normComponents[],
+            int normOffset) {
+        if (bits == null) {
+            // awt.26C=bits is null
+            throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$
+        }
+
+        if (normComponents == null) {
+            normComponents = new float[numComponents + normOffset];
+        }
+
+        if (hasAlpha && isAlphaPremultiplied) {
+            float normAlpha = (float)components[offset + numColorComponents]
+                    / maxValues[numColorComponents];
+            if (normAlpha != 0.0f) {
+                for (int i = 0; i < numColorComponents; i++) {
+                    normComponents[normOffset + i] = components[offset + i]
+                            / (normAlpha * maxValues[i]);
+                }
+                normComponents[normOffset + numColorComponents] = normAlpha;
+            } else {
+                for (int i = 0; i < numComponents; i++) {
+                    normComponents[normOffset + i] = 0.0f;
+                }
+            }
+        } else {
+            for (int i = 0; i < numComponents; i++) {
+                normComponents[normOffset + i] = (float)components[offset + i] / maxValues[i];
+            }
+        }
+
+        return normComponents;
+    }
+
+    /**
+     * Gets the data element corresponding to the unnormalized components.
+     * 
+     * @param components
+     *            the components.
+     * @param offset
+     *            the offset to start reading the components from the array of
+     *            components.
+     * @return the data element.
+     */
+    public int getDataElement(int[] components, int offset) {
+        throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+                "supported by this ColorModel"); //$NON-NLS-1$
+    }
+
+    /**
+     * Gets the unnormalized components corresponding to the specified
+     * normalized components.
+     * 
+     * @param normComponents
+     *            the array of normalized components.
+     * @param normOffset
+     *            the offset where the components should be read from the array
+     *            of normalized components.
+     * @param components
+     *            the array where the resulting unnormalized components are
+     *            written (or null to prompt the method to create the return
+     *            array).
+     * @param offset
+     *            the offset that tells where the results should be written in
+     *            the return array.
+     * @return the unnormalized components.
+     */
+    public int[] getUnnormalizedComponents(float normComponents[], int normOffset,
+            int components[], int offset) {
+
+        if (bits == null) {
+            // awt.26C=bits is null
+            throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$
+        }
+
+        if (normComponents.length - normOffset < numComponents) {
+            // awt.273=The length of normComponents minus normOffset is less
+            // than numComponents
+            throw new IllegalArgumentException(Messages.getString("awt.273")); //$NON-NLS-1$
+        }
+
+        if (components == null) {
+            components = new int[numComponents + offset];
+        } else {
+            if (components.length - offset < numComponents) {
+                // awt.272=The length of components minus offset is less than
+                // numComponents
+                throw new IllegalArgumentException(Messages.getString("awt.272")); //$NON-NLS-1$
+            }
+        }
+
+        if (hasAlpha && isAlphaPremultiplied) {
+            float alpha = normComponents[normOffset + numColorComponents];
+            for (int i = 0; i < numColorComponents; i++) {
+                components[offset + i] = (int)(normComponents[normOffset + i] * maxValues[i]
+                        * alpha + 0.5f);
+            }
+            components[offset + numColorComponents] = (int)(normComponents[normOffset
+                    + numColorComponents]
+                    * maxValues[numColorComponents] + 0.5f);
+        } else {
+            for (int i = 0; i < numComponents; i++) {
+                components[offset + i] = (int)(normComponents[normOffset + i] * maxValues[i] + 0.5f);
+            }
+        }
+
+        return components;
+    }
+
+    /**
+     * Gets the data element corresponding to the normalized components.
+     * 
+     * @param normComponents
+     *            the normalized components.
+     * @param normOffset
+     *            the offset where the normalized components should be read from
+     *            the normalized component array.
+     * @return the data element.
+     */
+    public int getDataElement(float normComponents[], int normOffset) {
+        int unnormComponents[] = getUnnormalizedComponents(normComponents, normOffset, null, 0);
+        return getDataElement(unnormComponents, 0);
+    }
+
+    /**
+     * Takes a pixel whose data is defined by an integer, and writes the
+     * corresponding components into the components array, starting from the
+     * index offset.
+     * 
+     * @param pixel
+     *            the pixel data.
+     * @param components
+     *            the data array to write the components to (or null to have the
+     *            method create the return array).
+     * @param offset
+     *            the offset that determines where the results are written in
+     *            the components array.
+     * @return the array of components corresponding to the pixel.
+     */
+    public int[] getComponents(int pixel, int components[], int offset) {
+        throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+                "supported by this ColorModel"); //$NON-NLS-1$
+    }
+
+    /**
+     * Gets the red component of the pixel determined by the pixel data.
+     * 
+     * @param pixel
+     *            the pixel.
+     * @return the red component of the given pixel.
+     */
+    public abstract int getRed(int pixel);
+
+    /**
+     * Takes the pixel data and returns the integer value corresponding to the
+     * pixel's color in RGB format.
+     * 
+     * @param pixel
+     *            the pixel data.
+     * @return the corresponding RGB integer value.
+     */
+    public int getRGB(int pixel) {
+        return (getAlpha(pixel) << 24 | getRed(pixel) << 16 | getGreen(pixel) << 8 | getBlue(pixel));
+    }
+
+    /**
+     * Gets the green component of the pixel determined by the pixel data.
+     * 
+     * @param pixel
+     *            the pixel.
+     * @return the green component of the given pixel.
+     */
+    public abstract int getGreen(int pixel);
+
+    /**
+     * Gets the size of the desired component of this color model.
+     * 
+     * @param componentIdx
+     *            the index that determines which component size to get.
+     * @return the component size corresponding to the index.
+     * @throws NullPointerException
+     *             if this color model doesn't support an array of separate
+     *             components.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if the index is negative or greater than or equal to the
+     *             number of components.
+     */
+    public int getComponentSize(int componentIdx) {
+        if (bits == null) {
+            // awt.26C=bits is null
+            throw new NullPointerException(Messages.getString("awt.26C")); //$NON-NLS-1$
+        }
+
+        if (componentIdx < 0 || componentIdx >= bits.length) {
+            // awt.274=componentIdx is greater than the number of components or
+            // less than zero
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.274")); //$NON-NLS-1$
+        }
+
+        return bits[componentIdx];
+    }
+
+    /**
+     * Gets the blue component of the pixel determined by the pixel data.
+     * 
+     * @param pixel
+     *            the pixel.
+     * @return the blue component of the given pixel.
+     */
+    public abstract int getBlue(int pixel);
+
+    /**
+     * Gets the alpha component of the pixel determined by the pixel data.
+     * 
+     * @param pixel
+     *            the pixel.
+     * @return the alpha component of the given pixel.
+     */
+    public abstract int getAlpha(int pixel);
+
+    /**
+     * Gets the array of sizes of the different components.
+     * 
+     * @return the array of sizes of the different components.
+     */
+    public int[] getComponentSize() {
+        if (bits != null) {
+            return bits.clone();
+        }
+        return null;
+    }
+
+    /**
+     * Checks if the alpha component is pre-multiplied.
+     * 
+     * @return true, if the alpha component is pre-multiplied.
+     */
+    public final boolean isAlphaPremultiplied() {
+        return isAlphaPremultiplied;
+    }
+
+    /**
+     * Checks whether this color model supports alpha.
+     * 
+     * @return true, if this color model has alpha.
+     */
+    public final boolean hasAlpha() {
+        return hasAlpha;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        int tmp;
+
+        if (hasAlpha) {
+            hash ^= 1;
+            hash <<= 8;
+        }
+        if (isAlphaPremultiplied) {
+            hash ^= 1;
+            hash <<= 8;
+        }
+
+        tmp = hash >>> 24;
+        hash ^= numColorComponents;
+        hash <<= 8;
+        hash |= tmp;
+
+        tmp = hash >>> 24;
+        hash ^= transparency;
+        hash <<= 8;
+        hash |= tmp;
+
+        tmp = hash >>> 24;
+        hash ^= cs.getType();
+        hash <<= 8;
+        hash |= tmp;
+
+        tmp = hash >>> 24;
+        hash ^= pixel_bits;
+        hash <<= 8;
+        hash |= tmp;
+
+        tmp = hash >>> 24;
+        hash ^= transferType;
+        hash <<= 8;
+        hash |= tmp;
+
+        if (bits != null) {
+
+            for (int element : bits) {
+                tmp = hash >>> 24;
+                hash ^= element;
+                hash <<= 8;
+                hash |= tmp;
+            }
+
+        }
+
+        return hash;
+    }
+
+    public int getTransparency() {
+        return transparency;
+    }
+
+    /**
+     * Gets the transfer type, which is the type of Java primitive value that
+     * corresponds to the bit length per pixel: either
+     * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT},
+     * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}.
+     * 
+     * @return the transfer type.
+     */
+    public final int getTransferType() {
+        return transferType;
+    }
+
+    /**
+     * Gets the pixel size in bits.
+     * 
+     * @return the pixel size.
+     */
+    public int getPixelSize() {
+        return pixel_bits;
+    }
+
+    /**
+     * Gets the number of components of this color model.
+     * 
+     * @return the number of components.
+     */
+    public int getNumComponents() {
+        return numComponents;
+    }
+
+    /**
+     * Gets the number of color components of this color model.
+     * 
+     * @return the number color components.
+     */
+    public int getNumColorComponents() {
+        return numColorComponents;
+    }
+
+    /**
+     * Gets the default RGB color model.
+     * 
+     * @return the default RGB color model.
+     */
+    public static ColorModel getRGBdefault() {
+        if (RGBdefault == null) {
+            RGBdefault = new DirectColorModel(32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
+        }
+        return RGBdefault;
+    }
+
+    /*
+     * Construct INT pixel representation from Object
+     * @param obj
+     * @return
+     */
+    /**
+     * Construct pixel.
+     * 
+     * @param obj
+     *            the obj.
+     * @return the int.
+     */
+    private int constructPixel(Object obj) {
+        int pixel = 0;
+
+        switch (getTransferType()) {
+
+            case DataBuffer.TYPE_BYTE:
+                byte[] bPixel = (byte[])obj;
+                if (bPixel.length > 1) {
+                    // awt.275=This pixel representation is not suuported by tis
+                    // Color Model
+                    throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$
+                }
+                pixel = bPixel[0] & 0xff;
+                break;
+
+            case DataBuffer.TYPE_USHORT:
+                short[] sPixel = (short[])obj;
+                if (sPixel.length > 1) {
+                    // awt.275=This pixel representation is not suuported by tis
+                    // Color Model
+                    throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$
+                }
+                pixel = sPixel[0] & 0xffff;
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int[] iPixel = (int[])obj;
+                if (iPixel.length > 1) {
+                    // awt.275=This pixel representation is not suuported by tis
+                    // Color Model
+                    throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$
+                }
+                pixel = iPixel[0];
+                break;
+
+            default:
+                // awt.22D=This transferType ( {0} ) is not supported by this
+                // color model
+                throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$
+                        transferType));
+
+        }
+        return pixel;
+    }
+
+    /**
+     * Gets the transfer type, which is the type of Java primitive value that
+     * corresponds to the bit length per pixel: either
+     * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT},
+     * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}.
+     * 
+     * @param bits
+     *            the array of component masks.
+     * @return the transfer type.
+     */
+    static int getTransferType(int bits) {
+        if (bits <= 8) {
+            return DataBuffer.TYPE_BYTE;
+        } else if (bits <= 16) {
+            return DataBuffer.TYPE_USHORT;
+        } else if (bits <= 32) {
+            return DataBuffer.TYPE_INT;
+        } else {
+            return DataBuffer.TYPE_UNDEFINED;
+        }
+    }
+
+    @Override
+    public void finalize() {
+        // This method is added for the API compatibility
+        // Don't need to call super since Object's finalize is always empty
+    }
+}
diff --git a/awt/java/awt/image/ComponentColorModel.java b/awt/java/awt/image/ComponentColorModel.java
new file mode 100644
index 0000000..4328fd3
--- /dev/null
+++ b/awt/java/awt/image/ComponentColorModel.java
@@ -0,0 +1,1482 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.color.ColorSpace;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class ComponentColorModel represents a color model that is defined in
+ * terms of its components.
+ * 
+ * @since Android 1.0
+ */
+public class ComponentColorModel extends ColorModel {
+
+    /**
+     * The signed.
+     */
+    private boolean signed; // Pixel samples are signed.
+
+    // Samples with TransferType DataBuffer.TYPE_BYTE,
+    // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT -
+    // unsigned. Samples with others TransferType -
+    // signed.
+
+    /**
+     * The integral.
+     */
+    private boolean integral; // Pixel samples are integral.
+
+    // Samples with TransferType DataBuffer.TYPE_BYTE,
+    // DataBuffer.TYPE_USHORT, DataBuffer.Short and
+    // DataBuffer.TYPE_INT - integral.
+
+    /**
+     * The scale factors.
+     */
+    private float scaleFactors[]; // Array of factors for reduction components
+
+    // values into the form scaled from 0 to 255
+
+    /**
+     * The donot support unnormalized.
+     */
+    private boolean donotSupportUnnormalized; // This Color Model don't support
+
+    // unnormolized form
+
+    /**
+     * The need alpha divide.
+     */
+    private boolean needAlphaDivide; // hasAlpha && isAlphaPremultiplied
+
+    /**
+     * The calc value.
+     */
+    private boolean calcValue; // Value was culculated
+
+    /**
+     * The need scale.
+     */
+    private boolean needScale; // Normalized value need to scale
+
+    /**
+     * The min vals.
+     */
+    private float minVals[]; // Array of Min normalized values
+
+    /**
+     * The ranges.
+     */
+    private float ranges[]; // Array of range normalized values
+
+    /**
+     * The alpha lut.
+     */
+    private byte alphaLUT[]; // Lookup table for scale alpha value
+
+    /**
+     * The color lu ts.
+     */
+    private byte colorLUTs[][]; // Lookup tables for scale color values
+
+    /**
+     * The from_ linea r_ rg b_ lut.
+     */
+    private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from
+
+    // Linear RGB Color Space into sRGB
+
+    /**
+     * The to_ linea r_8 rg b_ lut.
+     */
+    private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from
+
+    // sRGB Color Space into Linear RGB
+    // 8 bit
+
+    /**
+     * The to_ linea r_16 rg b_ lut.
+     */
+    private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from
+
+    // sRGB Color Space into Linear RGB
+    // 16 bit
+
+    /**
+     * The LINEA r_ rg b_ length.
+     */
+    private int LINEAR_RGB_Length; // Linear RGB bit length
+
+    /**
+     * The factor.
+     */
+    private float fFactor; // Scale factor
+
+    /**
+     * The is_s rgb.
+     */
+    private boolean is_sRGB; // ColorModel has sRGB ColorSpace
+
+    /**
+     * The is_ linea r_ rgb.
+     */
+    private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color
+
+    // Space
+
+    /**
+     * Instantiates a new component color model.
+     * 
+     * @param colorSpace
+     *            the color space.
+     * @param bits
+     *            the array of component masks.
+     * @param hasAlpha
+     *            whether the color model has alpha.
+     * @param isAlphaPremultiplied
+     *            whether the alpha is pre-multiplied.
+     * @param transparency
+     *            the transparency strategy, @see java.awt.Transparency.
+     * @param transferType
+     *            the transfer type (primitive java type to use for the
+     *            components).
+     */
+    public ComponentColorModel(ColorSpace colorSpace, int bits[], boolean hasAlpha,
+            boolean isAlphaPremultiplied, int transparency, int transferType) {
+        super(createPixelBits(colorSpace, hasAlpha, transferType), validateBits(bits, colorSpace,
+                hasAlpha, transferType), colorSpace, hasAlpha, isAlphaPremultiplied, transparency,
+                transferType);
+
+        needScale = false;
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+            case DataBuffer.TYPE_USHORT:
+            case DataBuffer.TYPE_INT:
+                signed = false;
+                integral = true;
+                donotSupportUnnormalized = false;
+                scaleFactors = new float[numComponents];
+                for (int i = 0; i < numColorComponents; i++) {
+                    scaleFactors[i] = 1.0f / maxValues[i];
+                    if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) {
+                        donotSupportUnnormalized = true;
+                    }
+                }
+                if (hasAlpha) {
+                    maxValues[numColorComponents] = (1 << bits[numColorComponents]) - 1;
+                    scaleFactors[numColorComponents] = 1.0f / maxValues[numColorComponents];
+                }
+                break;
+            case DataBuffer.TYPE_SHORT:
+                signed = true;
+                integral = true;
+                donotSupportUnnormalized = true;
+                scaleFactors = new float[numComponents];
+                for (int i = 0; i < numComponents; i++) {
+                    maxValues[i] = Short.MAX_VALUE;
+                    scaleFactors[i] = 1.0f / maxValues[i];
+                    if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) {
+                        needScale = true;
+                    }
+                }
+                if (needScale) {
+                    minVals = new float[numColorComponents];
+                    ranges = new float[numColorComponents];
+                    for (int i = 0; i < numColorComponents; i++) {
+                        minVals[i] = cs.getMinValue(i);
+                        ranges[i] = cs.getMaxValue(i) - minVals[i];
+                    }
+                }
+                break;
+            case DataBuffer.TYPE_FLOAT:
+            case DataBuffer.TYPE_DOUBLE:
+                signed = true;
+                integral = false;
+                donotSupportUnnormalized = true;
+                break;
+            default:
+                // awt.215=transferType is not one of DataBuffer.TYPE_BYTE,
+                // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT,
+                // DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or
+                // DataBuffer.TYPE_DOUBLE
+                throw new IllegalArgumentException(Messages.getString("awt.215")); //$NON-NLS-1$
+        }
+
+        needAlphaDivide = hasAlpha && isAlphaPremultiplied;
+        initLUTs();
+    }
+
+    /**
+     * Instantiates a new component color model.
+     * 
+     * @param colorSpace
+     *            the color space.
+     * @param hasAlpha
+     *            whether the color model has alpha.
+     * @param isAlphaPremultiplied
+     *            whether the alpha is pre-multiplied.
+     * @param transparency
+     *            the transparency strategy, @see java.awt.Transparency.
+     * @param transferType
+     *            the transfer type (primitive java type to use for the
+     *            components).
+     */
+    public ComponentColorModel(ColorSpace colorSpace, boolean hasAlpha,
+            boolean isAlphaPremultiplied, int transparency, int transferType) {
+
+        this(colorSpace, createPixelBitsArray(colorSpace, hasAlpha, transferType), hasAlpha,
+                isAlphaPremultiplied, transparency, transferType);
+    }
+
+    /**
+     * Validate bits.
+     * 
+     * @param bits
+     *            the bits.
+     * @param colorSpace
+     *            the color space.
+     * @param hasAlpha
+     *            the has alpha.
+     * @param transferType
+     *            the transfer type.
+     * @return the int[].
+     */
+    private static int[] validateBits(int bits[], ColorSpace colorSpace, boolean hasAlpha,
+            int transferType) {
+        if (bits != null) {
+            return bits;
+        }
+
+        int numComponents = colorSpace.getNumComponents();
+        if (hasAlpha) {
+            numComponents++;
+        }
+        bits = new int[numComponents];
+
+        int componentLength = DataBuffer.getDataTypeSize(transferType);
+
+        for (int i = 0; i < numComponents; i++) {
+            bits[i] = componentLength;
+        }
+
+        return bits;
+    }
+
+    /**
+     * Creates the pixel bits.
+     * 
+     * @param colorSpace
+     *            the color space.
+     * @param hasAlpha
+     *            the has alpha.
+     * @param transferType
+     *            the transfer type.
+     * @return the int.
+     */
+    private static int createPixelBits(ColorSpace colorSpace, boolean hasAlpha, int transferType) {
+        int numComponents = colorSpace.getNumComponents();
+        if (hasAlpha) {
+            numComponents++;
+        }
+        int componentLength = DataBuffer.getDataTypeSize(transferType);
+        return numComponents * componentLength;
+    }
+
+    /**
+     * Creates the pixel bits array.
+     * 
+     * @param colorSpace
+     *            the color space.
+     * @param hasAlpha
+     *            the has alpha.
+     * @param transferType
+     *            the transfer type.
+     * @return the int[].
+     */
+    private static int[] createPixelBitsArray(ColorSpace colorSpace, boolean hasAlpha,
+            int transferType) {
+
+        int numComponents = colorSpace.getNumComponents();
+        if (hasAlpha) {
+            numComponents++;
+        }
+
+        int bits[] = new int[numComponents];
+        for (int i = 0; i < numComponents; i++) {
+            bits[i] = DataBuffer.getDataTypeSize(transferType);
+        }
+        return bits;
+    }
+
+    @Override
+    public Object getDataElements(int components[], int offset, Object obj) {
+        if (donotSupportUnnormalized) {
+            // awt.213=This ComponentColorModel does not support the
+            // unnormalized form
+            throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+        }
+
+        if (offset + numComponents > components.length) {
+            // awt.216=The components array is not large enough to hold all the
+            // color and alpha components
+            throw new IllegalArgumentException(Messages.getString("awt.216")); //$NON-NLS-1$
+        }
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[];
+                if (obj == null) {
+                    ba = new byte[numComponents];
+                } else {
+                    ba = (byte[])obj;
+                }
+                for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+                    ba[i] = (byte)components[idx];
+                }
+                return ba;
+            case DataBuffer.TYPE_USHORT:
+                short sa[];
+                if (obj == null) {
+                    sa = new short[numComponents];
+                } else {
+                    sa = (short[])obj;
+                }
+                for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+                    sa[i] = (short)components[idx];
+                }
+                return sa;
+            case DataBuffer.TYPE_INT:
+                int ia[];
+                if (obj == null) {
+                    ia = new int[numComponents];
+                } else {
+                    ia = (int[])obj;
+                }
+                for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+                    ia[i] = components[idx];
+                }
+                return ia;
+            default:
+                // awt.217=The transfer type of this ComponentColorModel is not
+                // one
+                // of the following transfer types: DataBuffer.TYPE_BYTE,
+                // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
+                throw new UnsupportedOperationException(Messages.getString("awt.217")); //$NON-NLS-1$
+        }
+    }
+
+    @Override
+    public Object getDataElements(float normComponents[], int normOffset, Object obj) {
+        if (needScale) {
+            for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+                normComponents[idx] = (normComponents[idx] - minVals[i]) / ranges[i];
+            }
+        }
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[];
+                if (obj == null) {
+                    ba = new byte[numComponents];
+                } else {
+                    ba = (byte[])obj;
+                }
+
+                if (needAlphaDivide) {
+                    float alpha = normComponents[normOffset + numColorComponents];
+                    for (int i = 0, idx = normOffset; i < numColorComponents; i++, idx++) {
+                        ba[i] = (byte)(normComponents[idx] * alpha * maxValues[i] + 0.5f);
+                    }
+                    ba[numColorComponents] = (byte)(normComponents[normOffset + numColorComponents]
+                            * maxValues[numColorComponents] + 0.5f);
+                } else {
+                    for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+                        ba[idx] = (byte)(normComponents[idx] * maxValues[i] + 0.5f);
+                    }
+                }
+                return ba;
+
+            case DataBuffer.TYPE_USHORT:
+                short usa[];
+                if (obj == null) {
+                    usa = new short[numComponents];
+                } else {
+                    usa = (short[])obj;
+                }
+
+                if (needAlphaDivide) {
+                    float alpha = normComponents[normOffset + numColorComponents];
+                    for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+                        usa[i] = (short)(normComponents[idx] * alpha * maxValues[i] + 0.5f);
+                    }
+                    usa[numColorComponents] = (short)(alpha * maxValues[numColorComponents] + 0.5f);
+                } else {
+                    for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+                        usa[i] = (short)(normComponents[idx] * maxValues[i] + 0.5f);
+                    }
+                }
+                return usa;
+
+            case DataBuffer.TYPE_INT:
+                int ia[];
+                if (obj == null) {
+                    ia = new int[numComponents];
+                } else {
+                    ia = (int[])obj;
+                }
+
+                if (needAlphaDivide) {
+                    float alpha = normComponents[normOffset + numColorComponents];
+                    for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+                        ia[i] = (int)(normComponents[idx] * alpha * maxValues[i] + 0.5f);
+                    }
+                    ia[numColorComponents] = (int)(alpha * maxValues[numColorComponents] + 0.5f);
+                } else {
+                    for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+                        ia[i] = (int)(normComponents[idx] * maxValues[i] + 0.5f);
+                    }
+                }
+                return ia;
+
+            case DataBuffer.TYPE_SHORT:
+                short sa[];
+                if (obj == null) {
+                    sa = new short[numComponents];
+                } else {
+                    sa = (short[])obj;
+                }
+
+                if (needAlphaDivide) {
+                    float alpha = normComponents[normOffset + numColorComponents];
+                    for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+                        sa[i] = (short)(normComponents[idx] * alpha * maxValues[i] + 0.5f);
+                    }
+                    sa[numColorComponents] = (short)(alpha * maxValues[numColorComponents] + 0.5f);
+                } else {
+                    for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+                        sa[i] = (short)(normComponents[idx] * maxValues[i] + 0.5f);
+                    }
+                }
+                return sa;
+
+            case DataBuffer.TYPE_FLOAT:
+                float fa[];
+                if (obj == null) {
+                    fa = new float[numComponents];
+                } else {
+                    fa = (float[])obj;
+                }
+
+                if (needAlphaDivide) {
+                    float alpha = normComponents[normOffset + numColorComponents];
+                    for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+                        fa[i] = normComponents[idx] * alpha;
+                    }
+                    fa[numColorComponents] = alpha;
+                } else {
+                    for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+                        fa[i] = normComponents[idx];
+                    }
+                }
+                return fa;
+
+            case DataBuffer.TYPE_DOUBLE:
+                double da[];
+                if (obj == null) {
+                    da = new double[numComponents];
+                } else {
+                    da = (double[])obj;
+                }
+
+                if (needAlphaDivide) {
+                    double alpha = normComponents[normOffset + numColorComponents];
+                    for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+                        da[i] = normComponents[idx] * alpha;
+                    }
+                    da[numColorComponents] = alpha;
+                } else {
+                    for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+                        da[i] = normComponents[idx];
+                    }
+                }
+                return da;
+
+            default:
+                // awt.213=This ComponentColorModel does not support the
+                // unnormalized form
+                throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+        }
+    }
+
+    @Override
+    public Object getDataElements(int rgb, Object pixel) {
+        float normComp[];
+        float comp[];
+
+        int red = (rgb >> 16) & 0xff;
+        int green = (rgb >> 8) & 0xff;
+        int blue = rgb & 0xff;
+        int alpha = (rgb >> 24) & 0xff;
+
+        comp = new float[3];
+        if (is_sRGB || is_LINEAR_RGB) {
+            if (is_LINEAR_RGB) {
+                if (LINEAR_RGB_Length == 8) {
+                    red = to_LINEAR_8RGB_LUT[red] & 0xff;
+                    green = to_LINEAR_8RGB_LUT[green] & 0xff;
+                    blue = to_LINEAR_8RGB_LUT[blue] & 0xff;
+                } else {
+                    red = to_LINEAR_16RGB_LUT[red] & 0xffff;
+                    green = to_LINEAR_16RGB_LUT[green] & 0xffff;
+                    blue = to_LINEAR_16RGB_LUT[blue] & 0xffff;
+                }
+            }
+            comp[0] = red / fFactor;
+            comp[1] = green / fFactor;
+            comp[2] = blue / fFactor;
+            if (!hasAlpha) {
+                normComp = comp;
+            } else {
+                float normAlpha = alpha / 255.0f;
+                normComp = new float[numComponents];
+                for (int i = 0; i < numColorComponents; i++) {
+                    normComp[i] = comp[i];
+                }
+                normComp[numColorComponents] = normAlpha;
+            }
+        } else {
+            comp[0] = red / fFactor;
+            comp[1] = green / fFactor;
+            comp[2] = blue / fFactor;
+            float[] defComp = cs.fromRGB(comp);
+            if (!hasAlpha) {
+                normComp = defComp;
+            } else {
+                float normAlpha = alpha / 255.0f;
+                normComp = new float[numComponents];
+                for (int i = 0; i < numColorComponents; i++) {
+                    normComp[i] = defComp[i];
+                }
+                normComp[numColorComponents] = normAlpha;
+            }
+        }
+        if (hasAlpha && isAlphaPremultiplied) {
+            normComp[0] *= normComp[numColorComponents];
+            normComp[1] *= normComp[numColorComponents];
+            normComp[2] *= normComp[numColorComponents];
+        }
+
+        return getDataElements(normComp, 0, pixel);
+    }
+
+    @Override
+    public WritableRaster getAlphaRaster(WritableRaster raster) {
+        if (!hasAlpha) {
+            return null;
+        }
+
+        int x = raster.getMinX();
+        int y = raster.getMinY();
+        int bandList[] = new int[1];
+        bandList[0] = raster.getNumBands() - 1;
+
+        return raster.createWritableChild(x, y, raster.getWidth(), raster.getHeight(), x, y,
+                bandList);
+    }
+
+    @Override
+    public ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) {
+        if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) {
+            return this;
+        }
+
+        int minX = raster.getMinX();
+        int minY = raster.getMinY();
+        int w = raster.getWidth();
+        int h = raster.getHeight();
+
+        if (isAlphaPremultiplied) {
+            switch (transferType) {
+                case DataBuffer.TYPE_BYTE:
+                case DataBuffer.TYPE_USHORT:
+                case DataBuffer.TYPE_INT:
+                    float alphaFactor = maxValues[numColorComponents];
+                    int iComponents[] = null;
+                    int iTransparentComponents[] = new int[numComponents];
+                    for (int i = 0; i < h; i++, minY++) {
+                        for (int j = 0, x = minX; j < w; j++, x++) {
+                            iComponents = raster.getPixel(x, minY, iComponents);
+                            if (iComponents[numColorComponents] == 0) {
+                                raster.setPixel(x, minY, iTransparentComponents);
+                            } else {
+                                float alpha = iComponents[numColorComponents] / alphaFactor;
+                                for (int n = 0; n < numColorComponents; n++) {
+                                    iComponents[n] = (int)(alpha * iComponents[n] + 0.5f);
+                                }
+                                raster.setPixel(x, minY, iComponents);
+                            }
+                        }
+
+                    }
+                    break;
+
+                case DataBuffer.TYPE_SHORT:
+                    float sAlphaFactor = maxValues[numColorComponents];
+                    short sComponents[] = null;
+                    short sTransparentComponents[] = new short[numComponents];
+                    for (int i = 0; i < h; i++, minY++) {
+                        for (int j = 0, x = minX; j < w; j++, x++) {
+                            sComponents = (short[])raster.getDataElements(x, minY, sComponents);
+                            if (sComponents[numColorComponents] == 0) {
+                                raster.setDataElements(x, minY, sTransparentComponents);
+                            } else {
+                                float alpha = sComponents[numColorComponents] / sAlphaFactor;
+                                for (int n = 0; n < numColorComponents; n++) {
+                                    sComponents[n] = (byte)(alpha * sComponents[n] + 0.5f);
+                                }
+                                raster.setDataElements(x, minY, sComponents);
+                            }
+                        }
+
+                    }
+                    break;
+
+                case DataBuffer.TYPE_FLOAT:
+                    float fComponents[] = null;
+                    float fTransparentComponents[] = new float[numComponents];
+                    for (int i = 0; i < h; i++, minY++) {
+                        for (int j = 0, x = minX; j < w; j++, x++) {
+                            fComponents = raster.getPixel(x, minY, fComponents);
+                            if (fComponents[numColorComponents] == 0.0f) {
+                                raster.setDataElements(x, minY, fTransparentComponents);
+                            } else {
+                                float alpha = fComponents[numColorComponents];
+                                for (int n = 0; n < numColorComponents; n++) {
+                                    fComponents[n] = fComponents[n] * alpha;
+                                }
+                                raster.setPixel(x, minY, fComponents);
+                            }
+                        }
+
+                    }
+                    break;
+
+                case DataBuffer.TYPE_DOUBLE:
+                    double dComponents[] = null;
+                    double dTransparentComponents[] = new double[numComponents];
+                    for (int i = 0; i < h; i++, minY++) {
+                        for (int j = 0, x = minX; j < w; j++, x++) {
+                            dComponents = raster.getPixel(x, minY, dComponents);
+                            if (dComponents[numColorComponents] == 0.0) {
+                                raster.setPixel(x, minY, dTransparentComponents);
+                            } else {
+                                double alpha = dComponents[numColorComponents];
+                                for (int n = 0; n < numColorComponents; n++) {
+                                    dComponents[n] = dComponents[n] * alpha;
+                                }
+                                raster.setPixel(x, minY, dComponents);
+                            }
+                        }
+
+                    }
+                    break;
+
+                default:
+                    // awt.219=This transferType is not supported by this color
+                    // model
+                    throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$
+            }
+        } else {
+            switch (transferType) {
+                case DataBuffer.TYPE_BYTE:
+                case DataBuffer.TYPE_USHORT:
+                case DataBuffer.TYPE_INT:
+                    float alphaFactor = maxValues[numColorComponents];
+                    int iComponents[] = null;
+                    int iTransparentComponents[] = new int[numComponents];
+                    for (int i = 0; i < h; i++, minY++) {
+                        for (int j = 0, x = minX; j < w; j++, x++) {
+                            iComponents = raster.getPixel(x, minY, iComponents);
+                            if (iComponents[numColorComponents] == 0) {
+                                raster.setPixel(x, minY, iTransparentComponents);
+                            } else {
+                                float alpha = iComponents[numColorComponents] / alphaFactor;
+                                for (int n = 0; n < numColorComponents; n++) {
+                                    iComponents[n] = (int)(iComponents[n] / alpha + 0.5f);
+                                }
+                                raster.setPixel(x, minY, iComponents);
+                            }
+                        }
+
+                    }
+                    break;
+
+                case DataBuffer.TYPE_SHORT:
+                    float sAlphaFactor = maxValues[numColorComponents];
+                    short sComponents[] = null;
+                    short sTransparentComponents[] = new short[numComponents];
+                    for (int i = 0; i < h; i++, minY++) {
+                        for (int j = 0, x = minX; j < w; j++, x++) {
+                            sComponents = (short[])raster.getDataElements(x, minY, sComponents);
+                            if (sComponents[numColorComponents] == 0) {
+                                raster.setDataElements(x, minY, sTransparentComponents);
+                            } else {
+                                float alpha = sComponents[numColorComponents] / sAlphaFactor;
+                                for (int n = 0; n < numColorComponents; n++) {
+                                    sComponents[n] = (byte)(sComponents[n] / alpha + 0.5f);
+                                }
+                                raster.setDataElements(x, minY, sComponents);
+                            }
+                        }
+
+                    }
+                    break;
+
+                case DataBuffer.TYPE_FLOAT:
+                    float fComponents[] = null;
+                    float fTransparentComponents[] = new float[numComponents];
+                    for (int i = 0; i < h; i++, minY++) {
+                        for (int j = 0, x = minX; j < w; j++, x++) {
+                            fComponents = raster.getPixel(x, minY, fComponents);
+                            if (fComponents[numColorComponents] == 0.0f) {
+                                raster.setDataElements(x, minY, fTransparentComponents);
+                            } else {
+                                float alpha = fComponents[numColorComponents];
+                                for (int n = 0; n < numColorComponents; n++) {
+                                    fComponents[n] = fComponents[n] / alpha;
+                                }
+                                raster.setPixel(x, minY, fComponents);
+                            }
+                        }
+
+                    }
+                    break;
+
+                case DataBuffer.TYPE_DOUBLE:
+                    double dComponents[] = null;
+                    double dTransparentComponents[] = new double[numComponents];
+                    for (int i = 0; i < h; i++, minY++) {
+                        for (int j = 0, x = minX; j < w; j++, x++) {
+                            dComponents = raster.getPixel(x, minY, dComponents);
+                            if (dComponents[numColorComponents] == 0.0) {
+                                raster.setPixel(x, minY, dTransparentComponents);
+                            } else {
+                                double alpha = dComponents[numColorComponents];
+                                for (int n = 0; n < numColorComponents; n++) {
+                                    dComponents[n] = dComponents[n] / alpha;
+                                }
+                                raster.setPixel(x, minY, dComponents);
+                            }
+                        }
+
+                    }
+                    break;
+                default:
+                    // awt.219=This transferType is not supported by this color
+                    // model
+                    throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$
+            }
+        }
+
+        if (!signed) {
+            return new ComponentColorModel(cs, bits, hasAlpha, isAlphaPremultiplied, transparency,
+                    transferType);
+        }
+
+        return new ComponentColorModel(cs, null, hasAlpha, isAlphaPremultiplied, transparency,
+                transferType);
+    }
+
+    @Override
+    public int[] getComponents(Object pixel, int[] components, int offset) {
+        if (donotSupportUnnormalized) {
+            // awt.213=This ComponentColorModel does not support the
+            // unnormalized form
+            throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+        }
+
+        if (components == null) {
+            components = new int[offset + numComponents];
+        } else if (offset + numComponents > components.length) {
+            // awt.218=The components array is not large enough to hold all the
+            // color and alpha components
+            throw new IllegalArgumentException(Messages.getString("awt.218")); //$NON-NLS-1$
+        }
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[] = (byte[])pixel;
+
+                for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+                    components[idx] = ba[i] & 0xff;
+                }
+                return components;
+
+            case DataBuffer.TYPE_USHORT:
+                short sa[] = (short[])pixel;
+                for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+                    components[idx] = sa[i] & 0xffff;
+                }
+                return components;
+
+            case DataBuffer.TYPE_INT:
+                int ia[] = (int[])pixel;
+                for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+                    components[idx] = ia[i];
+                }
+                return components;
+
+            default:
+                // awt.217=The transfer type of this ComponentColorModel is not
+                // one
+                // of the following transfer types: DataBuffer.TYPE_BYTE,
+                // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
+                throw new UnsupportedOperationException(Messages.getString("awt.217")); //$NON-NLS-1$
+        }
+
+    }
+
+    @Override
+    public float[] getNormalizedComponents(Object pixel, float normComponents[], int normOffset) {
+
+        if (normComponents == null) {
+            normComponents = new float[numComponents + normOffset];
+        }
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[] = (byte[])pixel;
+                for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+                    normComponents[idx] = (ba[i] & 0xff) * scaleFactors[i];
+                }
+                break;
+
+            case DataBuffer.TYPE_USHORT:
+                short usa[] = (short[])pixel;
+                for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+                    normComponents[idx] = (usa[i] & 0xffff) * scaleFactors[i];
+                }
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int ia[] = (int[])pixel;
+                for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+                    normComponents[idx] = ia[i] * scaleFactors[i];
+                }
+                break;
+
+            case DataBuffer.TYPE_SHORT:
+                short sa[] = (short[])pixel;
+                for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+                    normComponents[idx] = sa[i] * scaleFactors[i];
+                }
+                break;
+
+            case DataBuffer.TYPE_FLOAT:
+                float fa[] = (float[])pixel;
+                for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+                    normComponents[idx] = fa[i];
+                }
+                break;
+
+            case DataBuffer.TYPE_DOUBLE:
+                double da[] = (double[])pixel;
+                for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+                    normComponents[idx] = (float)da[i];
+                }
+                break;
+
+            default:
+                // awt.21A=This ComponentColorModel does not support this
+                // transferType
+                throw new IllegalArgumentException(Messages.getString("awt.21A")); //$NON-NLS-1$
+        }
+
+        if (needAlphaDivide) {
+            float alpha = normComponents[normOffset + numColorComponents];
+            for (int i = 0, idx = normOffset; i < numColorComponents; i++, idx++) {
+                normComponents[idx] /= alpha;
+            }
+        }
+
+        if (needScale) {
+            for (int i = 0, idx = normOffset; i < numColorComponents; i++, idx++) {
+                normComponents[idx] = minVals[i] + ranges[i] * normComponents[idx];
+            }
+        }
+        return normComponents;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof ComponentColorModel)) {
+            return false;
+        }
+        return super.equals(obj);
+    }
+
+    @Override
+    public int getRed(Object inData) {
+        return getRGBComponent(inData, 0);
+    }
+
+    @Override
+    public int getRGB(Object inData) {
+        int alpha = getAlpha(inData);
+        if (cs.getType() == ColorSpace.TYPE_GRAY) {
+            int gray = getRed(inData);
+            return (alpha << 24 | gray << 16 | gray << 8 | gray);
+        }
+        return (alpha << 24 | getRed(inData) << 16 | getGreen(inData) << 8 | getBlue(inData));
+    }
+
+    @Override
+    public int getGreen(Object inData) {
+        return getRGBComponent(inData, 1);
+    }
+
+    @Override
+    public int getBlue(Object inData) {
+        return getRGBComponent(inData, 2);
+    }
+
+    @Override
+    public int getAlpha(Object inData) {
+        if (!hasAlpha) {
+            return 255;
+        }
+        int alpha = 0;
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE: {
+                byte ba[] = (byte[])inData;
+                alpha = ba[numColorComponents] & 0xff;
+                if (bits[numColorComponents] != 8) {
+                    return alphaLUT[alpha] & 0xff;
+                }
+                return alpha;
+            }
+            case DataBuffer.TYPE_USHORT: {
+                short usa[] = (short[])inData;
+                alpha = usa[numColorComponents] & 0xffff;
+                if (bits[numColorComponents] != 8) {
+                    return alphaLUT[alpha] & 0xff;
+                }
+                return alpha;
+            }
+            case DataBuffer.TYPE_INT: {
+                int ia[] = (int[])inData;
+                alpha = ia[numColorComponents];
+                if (bits[numColorComponents] != 8) {
+                    return alphaLUT[alpha] & 0xff;
+                }
+                return alpha;
+            }
+            case DataBuffer.TYPE_SHORT: {
+                short sa[] = (short[])inData;
+                alpha = sa[numColorComponents];
+                if (bits[numColorComponents] != 8) {
+                    return alphaLUT[alpha] & 0xff;
+                }
+                return alpha;
+            }
+            case DataBuffer.TYPE_FLOAT: {
+                float fa[] = (float[])inData;
+                return (int)(fa[numColorComponents] * 255.0f + 0.5f);
+            }
+            case DataBuffer.TYPE_DOUBLE: {
+                double da[] = (double[])inData;
+                return (int)(da[numColorComponents] * 255.0 + 0.5);
+            }
+            default: {
+                // awt.214=This Color Model doesn't support this transferType
+                throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+            }
+        }
+    }
+
+    @Override
+    public WritableRaster createCompatibleWritableRaster(int w, int h) {
+        SampleModel sm = createCompatibleSampleModel(w, h);
+        DataBuffer db = sm.createDataBuffer();
+        return Raster.createWritableRaster(sm, db, null);
+    }
+
+    @Override
+    public boolean isCompatibleSampleModel(SampleModel sm) {
+        if (!(sm instanceof ComponentSampleModel)) {
+            return false;
+        }
+        if (numComponents != sm.getNumBands()) {
+            return false;
+        }
+        if (transferType != sm.getTransferType()) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+        int bandOffsets[] = new int[numComponents];
+        for (int i = 0; i < numComponents; i++) {
+            bandOffsets[i] = i;
+        }
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+            case DataBuffer.TYPE_USHORT:
+                return new PixelInterleavedSampleModel(transferType, w, h, numComponents, w
+                        * numComponents, bandOffsets);
+
+            default:
+                return new ComponentSampleModel(transferType, w, h, numComponents, w
+                        * numComponents, bandOffsets);
+        }
+    }
+
+    @Override
+    public boolean isCompatibleRaster(Raster raster) {
+        SampleModel sm = raster.getSampleModel();
+        if (!(sm instanceof ComponentSampleModel)) {
+            return false;
+        }
+
+        if (sm.getNumBands() != numComponents) {
+            return false;
+        }
+        if (raster.getTransferType() != transferType) {
+            return false;
+        }
+
+        int sampleSizes[] = sm.getSampleSize();
+        for (int i = 0; i < numComponents; i++) {
+            if (bits[i] != sampleSizes[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public float[] getNormalizedComponents(int components[], int offset, float normComponents[],
+            int normOffset) {
+        if (donotSupportUnnormalized) {
+            // awt.213=This ComponentColorModel does not support the
+            // unnormalized form
+            throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+        }
+
+        return super.getNormalizedComponents(components, offset, normComponents, normOffset);
+    }
+
+    @Override
+    public int getDataElement(int[] components, int offset) {
+        if (numComponents > 1) {
+            // awt.212=There is more than one component in this ColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+        }
+        if (donotSupportUnnormalized) {
+            // awt.213=This ComponentColorModel does not support the
+            // unnormalized form
+            throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+        }
+        return components[offset];
+    }
+
+    @Override
+    public int[] getUnnormalizedComponents(float[] normComponents, int normOffset,
+            int[] components, int offset) {
+
+        if (donotSupportUnnormalized) {
+            // awt.213=This ComponentColorModel does not support the
+            // unnormalized form
+            throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+        }
+
+        if (normComponents.length - normOffset < numComponents) {
+            // awt.21B=The length of normComponents minus normOffset is less
+            // than numComponents
+            throw new IllegalArgumentException(Messages.getString("awt.21B")); //$NON-NLS-1$
+        }
+
+        return super.getUnnormalizedComponents(normComponents, normOffset, components, offset);
+    }
+
+    @Override
+    public int getDataElement(float normComponents[], int normOffset) {
+        if (numComponents > 1) {
+            // awt.212=There is more than one component in this ColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+        }
+        if (signed) {
+            // awt.210=The component value for this ColorModel is signed
+            throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$
+        }
+
+        Object pixel = getDataElements(normComponents, normOffset, null);
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[] = (byte[])pixel;
+                return ba[0] & 0xff;
+            case DataBuffer.TYPE_USHORT:
+                short sa[] = (short[])pixel;
+                return sa[0] & 0xffff;
+            case DataBuffer.TYPE_INT:
+                int ia[] = (int[])pixel;
+                return ia[0];
+            default:
+                // awt.211=Pixel values for this ColorModel are not conveniently
+                // representable as a single int
+                throw new IllegalArgumentException(Messages.getString("awt.211")); //$NON-NLS-1$
+        }
+    }
+
+    @Override
+    public int[] getComponents(int pixel, int components[], int offset) {
+        if (numComponents > 1) {
+            // awt.212=There is more than one component in this ColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+        }
+        if (donotSupportUnnormalized) {
+            // awt.213=This ComponentColorModel does not support the
+            // unnormalized form
+            throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+        }
+
+        if (components == null) {
+            components = new int[offset + 1];
+        }
+
+        components[offset] = pixel & maxValues[0];
+        return components;
+    }
+
+    @Override
+    public int getRed(int pixel) {
+        float rgb[] = toRGB(pixel);
+        return (int)(rgb[0] * 255.0f + 0.5f);
+    }
+
+    @Override
+    public int getRGB(int pixel) {
+        return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | (getGreen(pixel) << 8)
+                | getBlue(pixel);
+    }
+
+    @Override
+    public int getGreen(int pixel) {
+        float rgb[] = toRGB(pixel);
+        return (int)(rgb[1] * 255.0f + 0.5f);
+    }
+
+    @Override
+    public int getBlue(int pixel) {
+        float rgb[] = toRGB(pixel);
+        return (int)(rgb[2] * 255.0f + 0.5f);
+    }
+
+    @Override
+    public int getAlpha(int pixel) {
+
+        // This method throw IllegalArgumentException according to
+        // Java API Spacification
+        if (signed) {
+            // awt.210=The component value for this ColorModel is signed
+            throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$
+        }
+
+        if (numComponents > 1) {
+            // awt.212=There is more than one component in this ColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+        }
+
+        return 255;
+    }
+
+    /**
+     * Initialization of Lookup tables.
+     */
+    private void initLUTs() {
+        is_sRGB = cs.isCS_sRGB();
+        is_LINEAR_RGB = (cs == LUTColorConverter.LINEAR_RGB_CS);
+
+        if (hasAlpha && bits[numColorComponents] != 8 && integral) {
+            alphaLUT = new byte[maxValues[numColorComponents] + 1];
+            for (int i = 0; i <= maxValues[numColorComponents]; i++) {
+                alphaLUT[i] = (byte)(scaleFactors[numColorComponents] * i + 0.5f);
+            }
+        }
+
+        if (is_LINEAR_RGB) {
+            if (maxBitLength > 8) {
+                LINEAR_RGB_Length = 16;
+                from_LINEAR_RGB_LUT = LUTColorConverter.getFrom16lRGBtosRGB_LUT();
+                to_LINEAR_16RGB_LUT = LUTColorConverter.getFromsRGBto16lRGB_LUT();
+            } else {
+                LINEAR_RGB_Length = 8;
+                from_LINEAR_RGB_LUT = LUTColorConverter.getFrom8lRGBtosRGB_LUT();
+                to_LINEAR_8RGB_LUT = LUTColorConverter.getFromsRGBto8lRGB_LUT();
+            }
+            fFactor = ((1 << LINEAR_RGB_Length) - 1);
+        } else {
+            fFactor = 255.0f;
+        }
+
+        if (!isAlphaPremultiplied && integral) {
+            colorLUTs = new byte[3][];
+
+            if (is_sRGB) {
+                for (int i = 0; i < numColorComponents; i++) {
+                    if (bits[i] != 8) {
+                        for (int j = 0; j < i; j++) {
+                            if (bits[i] == bits[j]) {
+                                colorLUTs[i] = colorLUTs[j];
+                                break;
+                            }
+                        }
+                        colorLUTs[i] = new byte[maxValues[i] + 1];
+                        for (int j = 0; j <= maxValues[0]; j++) {
+                            colorLUTs[i][j] = (byte)(scaleFactors[i] * j + 0.5f);
+                        }
+                    }
+                }
+            }
+
+            if (is_LINEAR_RGB) {
+
+                for (int i = 0; i < numColorComponents; i++) {
+                    if (bits[i] != LINEAR_RGB_Length) {
+                        for (int j = 0; j < i; j++) {
+                            if (bits[i] == bits[j]) {
+                                colorLUTs[i] = colorLUTs[j];
+                                break;
+                            }
+                        }
+                        colorLUTs[i] = new byte[maxValues[i] + 1];
+                        for (int j = 0; j <= maxValues[0]; j++) {
+                            int idx;
+                            if (LINEAR_RGB_Length == 8) {
+                                idx = (int)(scaleFactors[i] * j + 0.5f);
+                            } else {
+                                idx = (int)(scaleFactors[i] * j * 257.0f + 0.5f);
+                            }
+                            colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx];
+                        }
+                    }
+                }
+            }
+
+        }
+    }
+
+    /**
+     * To rgb.
+     * 
+     * @param pixel
+     *            the integer representation of the pixel.
+     * @return the array of normalized sRGB components.
+     */
+    private float[] toRGB(int pixel) {
+
+        // This method throw IllegalArgumentException according to
+        // Java API Spacification
+        if (signed) {
+            // awt.210=The component value for this ColorModel is signed
+            throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$
+        }
+
+        if (numComponents > 1) {
+            // awt.212=There is more than one component in this ColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+        }
+
+        Object obj = null;
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[] = new byte[1];
+                ba[0] = (byte)pixel;
+                obj = ba;
+                break;
+
+            case DataBuffer.TYPE_USHORT:
+                short sa[] = new short[1];
+                sa[0] = (short)pixel;
+                obj = sa;
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int ia[] = new int[1];
+                ia[0] = pixel;
+                obj = ia;
+                break;
+
+        }
+
+        return cs.toRGB(getNormalizedComponents(obj, null, 0));
+    }
+
+    /**
+     * Gets the RGB component.
+     * 
+     * @param pixel
+     *            the pixel.
+     * @param idx
+     *            the index of component.
+     * @return the RGB value from 0 to 255 pixel's component.
+     */
+    private int getRGBComponent(Object pixel, int idx) {
+        if (is_sRGB) {
+            int comp = getDefComponent(pixel, idx);
+            if (calcValue || bits[idx] == 8) {
+                return comp;
+            }
+            return colorLUTs[idx][comp] & 0xff;
+        } else if (is_LINEAR_RGB) {
+            int comp = getDefComponent(pixel, idx);
+            if (calcValue || bits[idx] == LINEAR_RGB_Length) {
+                return from_LINEAR_RGB_LUT[comp] & 0xff;
+            }
+            return colorLUTs[idx][comp] & 0xff;
+        }
+
+        float normComp[] = getNormalizedComponents(pixel, null, 0);
+        float rgbComp[] = cs.toRGB(normComp);
+        return (int)(rgbComp[idx] * 255.0f + 0.5f);
+    }
+
+    /**
+     * Gets the def component.
+     * 
+     * @param pixel
+     *            the pixel.
+     * @param idx
+     *            the index of component.
+     * @return the tentative value of the pixel component.
+     */
+    private int getDefComponent(Object pixel, int idx) {
+        int comp = 0;
+        calcValue = false;
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[] = (byte[])pixel;
+                comp = ba[idx] & 0xff;
+                if (needAlphaDivide) {
+                    int alpha = ba[numColorComponents] & 0xff;
+                    if (alpha == 0) {
+                        comp = 0;
+                    } else {
+                        float normAlpha = scaleFactors[numColorComponents] * alpha;
+                        comp = (int)(comp * fFactor / normAlpha + 0.5f);
+                    }
+                    calcValue = true;
+                }
+                return comp;
+
+            case DataBuffer.TYPE_USHORT:
+                short usa[] = (short[])pixel;
+                comp = usa[idx] & 0xffff;
+                if (needAlphaDivide) {
+                    int alpha = usa[numColorComponents] & 0xffff;
+                    if (alpha == 0) {
+                        comp = 0;
+                    } else {
+                        float normAlpha = scaleFactors[numColorComponents] * alpha;
+                        comp = (int)(comp * fFactor / normAlpha + 0.5f);
+                    }
+                    calcValue = true;
+                }
+                return comp;
+
+            case DataBuffer.TYPE_INT:
+                int ia[] = (int[])pixel;
+                comp = ia[idx];
+                if (needAlphaDivide) {
+                    int alpha = ia[numColorComponents];
+                    if (alpha == 0) {
+                        comp = 0;
+                    } else {
+                        float normAlpha = scaleFactors[numColorComponents] * alpha;
+                        comp = (int)(comp * fFactor / normAlpha + 0.5f);
+                    }
+                    calcValue = true;
+                }
+                return comp;
+
+            case DataBuffer.TYPE_SHORT:
+                short sa[] = (short[])pixel;
+                comp = sa[idx];
+                if (needAlphaDivide) {
+                    int alpha = sa[numColorComponents];
+                    if (alpha == 0) {
+                        comp = 0;
+                    } else {
+                        float normAlpha = scaleFactors[numColorComponents] * alpha;
+                        comp = (int)(comp * fFactor / normAlpha + 0.5f);
+                    }
+                    calcValue = true;
+                }
+                return comp;
+
+            case DataBuffer.TYPE_FLOAT:
+                float fa[] = (float[])pixel;
+                if (needAlphaDivide) {
+                    float alpha = fa[numColorComponents];
+                    if (fa[numColorComponents] == 0.0f) {
+                        comp = 0;
+                    } else {
+                        comp = (int)(fa[idx] * fFactor / alpha + 0.5f);
+                    }
+                } else {
+                    comp = (int)(fa[idx] * fFactor + 0.5f);
+                }
+                calcValue = true;
+                return comp;
+
+            case DataBuffer.TYPE_DOUBLE:
+                double da[] = (double[])pixel;
+                if (needAlphaDivide) {
+                    if (da[numColorComponents] == 0.0) {
+                        comp = 0;
+                    } else {
+                        comp = (int)(da[idx] * fFactor / da[numColorComponents] + 0.5);
+                    }
+                } else {
+                    comp = (int)(da[idx] * fFactor + 0.5);
+                }
+                calcValue = true;
+                return comp;
+
+            default:
+                // awt.214=This Color Model doesn't support this transferType
+                throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+        }
+    }
+
+}
diff --git a/awt/java/awt/image/ComponentSampleModel.java b/awt/java/awt/image/ComponentSampleModel.java
new file mode 100644
index 0000000..7f81409
--- /dev/null
+++ b/awt/java/awt/image/ComponentSampleModel.java
@@ -0,0 +1,705 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ComponentSampleModel class represents a set of image data whose each
+ * element - the sample of a pixel - takes one data element of the DataBuffer.
+ * <p>
+ * The Bank indices denote the correspondence between the bank of data buffers
+ * and a band of image data. The Pixel stride is the number of data array
+ * elements between two samples for the same band on the same scanline. The
+ * pixel stride for a BandedSampleModel is one. The scanline stride represents
+ * the number of data array elements between a specified sample and the
+ * corresponding sample in the same column in the next scanline. The array of
+ * band offsets gives the starting offsets within each data banks of the in the
+ * DataBuffer. The bank indices represents the indices within each bank of the
+ * DataBuffer corresponding to a band of image data.
+ * 
+ * @since Android 1.0
+ */
+public class ComponentSampleModel extends SampleModel {
+
+    /**
+     * The band offsets array of this ComponentSampleModel.
+     */
+    protected int bandOffsets[];
+
+    /**
+     * The bank indices array of this ComponentSampleModel.
+     */
+    protected int bankIndices[];
+
+    /**
+     * The number of bands in this ComponentSampleModel.
+     */
+    protected int numBands;
+
+    /**
+     * The number banks of this ComponentSampleModel.
+     */
+    protected int numBanks;
+
+    /**
+     * The scanline stride of this ComponentSampleModel.
+     */
+    protected int scanlineStride;
+
+    /**
+     * The pixel stride of this ComponentSampleModel.
+     */
+    protected int pixelStride;
+
+    /**
+     * Instantiates a new ComponentSampleModel with the specified properties.
+     * 
+     * @param dataType
+     *            the data type of samples.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param pixelStride
+     *            the pixel stride of the image data.
+     * @param scanlineStride
+     *            the scanline stride of the image data.
+     * @param bankIndices
+     *            the array of the bank indices.
+     * @param bandOffsets
+     *            the array of the band offsets.
+     */
+    public ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride,
+            int bankIndices[], int bandOffsets[]) {
+
+        super(dataType, w, h, bandOffsets.length);
+
+        if (pixelStride < 0) {
+            // awt.24B=Pixel stride must be >= 0
+            throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$
+        }
+
+        if (scanlineStride < 0) {
+            // awt.24C=Scanline stride must be >= 0
+            throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$
+        }
+
+        if (bankIndices.length != bandOffsets.length) {
+            // awt.24D=Bank Indices length must be equal Bank Offsets length
+            throw new IllegalArgumentException(Messages.getString("awt.24D")); //$NON-NLS-1$
+        }
+
+        this.pixelStride = pixelStride;
+        this.scanlineStride = scanlineStride;
+        this.bandOffsets = bandOffsets.clone();
+        this.bankIndices = bankIndices.clone();
+        this.numBands = bandOffsets.length;
+
+        int maxBank = 0;
+        for (int i = 0; i < bankIndices.length; i++) {
+            if (bankIndices[i] < 0) {
+                // awt.24E=Index of {0} bank must be >= 0
+                throw new IllegalArgumentException(Messages.getString("awt.24E", i)); //$NON-NLS-1$
+            }
+            if (bankIndices[i] > maxBank) {
+                maxBank = bankIndices[i];
+            }
+        }
+        this.numBanks = maxBank + 1;
+
+    }
+
+    /**
+     * Instantiates a new ComponentSampleModel with the specified properties.
+     * 
+     * @param dataType
+     *            the data type of the samples.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param pixelStride
+     *            the pixel stride of the image data.
+     * @param scanlineStride
+     *            the scanline stride of the image data.
+     * @param bandOffsets
+     *            the band offsets.
+     */
+    public ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride,
+            int bandOffsets[]) {
+
+        super(dataType, w, h, bandOffsets.length);
+        if (pixelStride < 0) {
+            // awt.24B=Pixel stride must be >= 0
+            throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$
+        }
+
+        if (scanlineStride < 0) {
+            // awt.24C=Scanline stride must be >= 0
+            throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$
+        }
+
+        this.pixelStride = pixelStride;
+        this.scanlineStride = scanlineStride;
+        this.bandOffsets = bandOffsets.clone();
+        this.numBands = bandOffsets.length;
+        this.numBanks = 1;
+
+        this.bankIndices = new int[numBands];
+        for (int i = 0; i < numBands; i++) {
+            bankIndices[i] = 0;
+        }
+    }
+
+    @Override
+    public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        switch (dataType) {
+            case DataBuffer.TYPE_BYTE:
+                byte bdata[];
+                if (obj == null) {
+                    bdata = new byte[numBands];
+                } else {
+                    bdata = (byte[])obj;
+                }
+
+                for (int i = 0; i < numBands; i++) {
+                    bdata[i] = (byte)getSample(x, y, i, data);
+                }
+
+                obj = bdata;
+                break;
+
+            case DataBuffer.TYPE_SHORT:
+            case DataBuffer.TYPE_USHORT:
+                short sdata[];
+                if (obj == null) {
+                    sdata = new short[numBands];
+                } else {
+                    sdata = (short[])obj;
+                }
+
+                for (int i = 0; i < numBands; i++) {
+                    sdata[i] = (short)getSample(x, y, i, data);
+                }
+
+                obj = sdata;
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int idata[];
+                if (obj == null) {
+                    idata = new int[numBands];
+                } else {
+                    idata = (int[])obj;
+                }
+
+                for (int i = 0; i < numBands; i++) {
+                    idata[i] = getSample(x, y, i, data);
+                }
+
+                obj = idata;
+                break;
+
+            case DataBuffer.TYPE_FLOAT:
+                float fdata[];
+                if (obj == null) {
+                    fdata = new float[numBands];
+                } else {
+                    fdata = (float[])obj;
+                }
+
+                for (int i = 0; i < numBands; i++) {
+                    fdata[i] = getSampleFloat(x, y, i, data);
+                }
+
+                obj = fdata;
+                break;
+
+            case DataBuffer.TYPE_DOUBLE:
+                double ddata[];
+                if (obj == null) {
+                    ddata = new double[numBands];
+                } else {
+                    ddata = (double[])obj;
+                }
+
+                for (int i = 0; i < numBands; i++) {
+                    ddata[i] = getSampleDouble(x, y, i, data);
+                }
+
+                obj = ddata;
+                break;
+        }
+
+        return obj;
+    }
+
+    @Override
+    public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        switch (dataType) {
+            case DataBuffer.TYPE_BYTE:
+                byte barr[] = (byte[])obj;
+                for (int i = 0; i < numBands; i++) {
+                    setSample(x, y, i, barr[i] & 0xff, data);
+                }
+                break;
+
+            case DataBuffer.TYPE_SHORT:
+            case DataBuffer.TYPE_USHORT:
+                short sarr[] = (short[])obj;
+                for (int i = 0; i < numBands; i++) {
+                    setSample(x, y, i, sarr[i] & 0xffff, data);
+                }
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int iarr[] = (int[])obj;
+                for (int i = 0; i < numBands; i++) {
+                    setSample(x, y, i, iarr[i], data);
+                }
+                break;
+
+            case DataBuffer.TYPE_FLOAT:
+                float farr[] = (float[])obj;
+                for (int i = 0; i < numBands; i++) {
+                    setSample(x, y, i, farr[i], data);
+                }
+                break;
+
+            case DataBuffer.TYPE_DOUBLE:
+                double darr[] = (double[])obj;
+                for (int i = 0; i < numBands; i++) {
+                    setSample(x, y, i, darr[i], data);
+                }
+                break;
+        }
+    }
+
+    /**
+     * Compares this ComponentSampleModel with the specified Object.
+     * 
+     * @param o
+     *            the Object.
+     * @return true, if the object is a ComponentSampleModel with identical data
+     *         values to this ComponentSampleModel, false otherwise.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if ((o == null) || !(o instanceof ComponentSampleModel)) {
+            return false;
+        }
+        ComponentSampleModel model = (ComponentSampleModel)o;
+        return this.width == model.width && this.height == model.height
+                && this.numBands == model.numBands && this.dataType == model.dataType
+                && Arrays.equals(this.bandOffsets, model.bandOffsets)
+                && Arrays.equals(this.bankIndices, model.bankIndices)
+                && this.numBands == model.numBands && this.numBanks == model.numBanks
+                && this.scanlineStride == model.scanlineStride
+                && this.pixelStride == model.pixelStride;
+    }
+
+    /**
+     * @see java.awt.image.SampleModel#createSubsetSampleModel(int[])
+     */
+    @Override
+    public SampleModel createSubsetSampleModel(int bands[]) {
+        if (bands.length > this.numBands) {
+            // awt.64=The number of the bands in the subset is greater than the
+            // number of bands in the sample model
+            throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$
+        }
+
+        int indices[] = new int[bands.length];
+        int offsets[] = new int[bands.length];
+
+        for (int i = 0; i < bands.length; i++) {
+            indices[i] = bankIndices[bands[i]];
+            offsets[i] = bandOffsets[bands[i]];
+        }
+
+        return new ComponentSampleModel(dataType, width, height, pixelStride, scanlineStride,
+                indices, offsets);
+
+    }
+
+    @Override
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+        return new ComponentSampleModel(dataType, w, h, pixelStride, pixelStride * w, bankIndices,
+                bandOffsets);
+    }
+
+    @Override
+    public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+        int pixel[];
+
+        if (iArray == null) {
+            pixel = new int[numBands];
+        } else {
+            pixel = iArray;
+        }
+
+        for (int i = 0; i < numBands; i++) {
+            pixel[i] = getSample(x, y, i, data);
+        }
+
+        return pixel;
+    }
+
+    @Override
+    public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+        for (int i = 0; i < numBands; i++) {
+            setSample(x, y, i, iArray[i], data);
+        }
+    }
+
+    @Override
+    public int getSample(int x, int y, int b, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        return data.getElem(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b]);
+    }
+
+    @Override
+    public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        return data.getElemFloat(bankIndices[b], y * scanlineStride + x * pixelStride
+                + bandOffsets[b]);
+    }
+
+    @Override
+    public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        return data.getElemDouble(bankIndices[b], y * scanlineStride + x * pixelStride
+                + bandOffsets[b]);
+    }
+
+    @Override
+    public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x > this.width || x + w > this.width || y > this.height
+                || y + h > this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int pixels[] = null;
+        int idx = 0;
+
+        if (iArray == null) {
+            pixels = new int[w * h * numBands];
+        } else {
+            pixels = iArray;
+        }
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                for (int n = 0; n < numBands; n++) {
+                    pixels[idx++] = getSample(j, i, n, data);
+                }
+            }
+        }
+
+        return pixels;
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int idx = 0;
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                for (int n = 0; n < numBands; n++) {
+                    setSample(j, i, n, iArray[idx++], data);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setSample(int x, int y, int b, int s, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        data.setElem(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b], s);
+    }
+
+    @Override
+    public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int samples[];
+        int idx = 0;
+
+        if (iArray == null) {
+            samples = new int[w * h];
+        } else {
+            samples = iArray;
+        }
+
+        if (data == null) {
+            // awt.295=data is null
+            throw new NullPointerException(Messages.getString("awt.295")); //$NON-NLS-1$
+        }
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                samples[idx++] = getSample(j, i, b, data);
+            }
+        }
+
+        return samples;
+    }
+
+    @Override
+    public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int idx = 0;
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                setSample(j, i, b, iArray[idx++], data);
+            }
+        }
+    }
+
+    @Override
+    public void setSample(int x, int y, int b, float s, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        data.setElemFloat(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b], s);
+    }
+
+    @Override
+    public void setSample(int x, int y, int b, double s, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        data
+                .setElemDouble(bankIndices[b], y * scanlineStride + x * pixelStride
+                        + bandOffsets[b], s);
+    }
+
+    @Override
+    public DataBuffer createDataBuffer() {
+        DataBuffer data = null;
+
+        int maxOffset = bandOffsets[0];
+        for (int i = 1; i < bandOffsets.length; i++) {
+            if (bandOffsets[i] > maxOffset) {
+                maxOffset = bandOffsets[i];
+            }
+        }
+        int size = (height - 1) * scanlineStride + (width - 1) * pixelStride + maxOffset + 1;
+
+        switch (dataType) {
+            case DataBuffer.TYPE_BYTE:
+                data = new DataBufferByte(size, numBanks);
+                break;
+            case DataBuffer.TYPE_SHORT:
+                data = new DataBufferShort(size, numBanks);
+                break;
+            case DataBuffer.TYPE_USHORT:
+                data = new DataBufferUShort(size, numBanks);
+                break;
+            case DataBuffer.TYPE_INT:
+                data = new DataBufferInt(size, numBanks);
+                break;
+            case DataBuffer.TYPE_FLOAT:
+                data = new DataBufferFloat(size, numBanks);
+                break;
+            case DataBuffer.TYPE_DOUBLE:
+                data = new DataBufferDouble(size, numBanks);
+                break;
+        }
+
+        return data;
+
+    }
+
+    /**
+     * Gets the offset of the specified band of the specified pixel.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param b
+     *            the band.
+     * @return the offset of the specified band of the specified pixel.
+     */
+    public int getOffset(int x, int y, int b) {
+        return y * scanlineStride + x * pixelStride + bandOffsets[b];
+    }
+
+    /**
+     * Gets the offset of the first band of the specified pixel.
+     * 
+     * @param x
+     *            the X coordinate of pixel.
+     * @param y
+     *            the Y coordinate of pixel.
+     * @return the offset of the first band of the specified pixel.
+     */
+    public int getOffset(int x, int y) {
+        return y * scanlineStride + x * pixelStride + bandOffsets[0];
+    }
+
+    @Override
+    public final int getSampleSize(int band) {
+        return DataBuffer.getDataTypeSize(dataType);
+    }
+
+    @Override
+    public final int[] getSampleSize() {
+        int sampleSizes[] = new int[numBands];
+        int size = DataBuffer.getDataTypeSize(dataType);
+
+        for (int i = 0; i < numBands; i++) {
+            sampleSizes[i] = size;
+        }
+        return sampleSizes;
+    }
+
+    /**
+     * Gets an array of bank indices corresponding to this ComponentSampleModel.
+     * 
+     * @return the array of bank indices.
+     */
+    public final int[] getBankIndices() {
+        return bankIndices.clone();
+    }
+
+    /**
+     * Gets an array of the band offsets corresponding to this
+     * ComponentSampleModel.
+     * 
+     * @return the array of band offsets.
+     */
+    public final int[] getBandOffsets() {
+        return bandOffsets.clone();
+    }
+
+    /**
+     * Gets a hash code of this ComponentSampleModel object.
+     * 
+     * @return a hash code of this ComponentSampleModel object.
+     */
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        int tmp = 0;
+
+        hash = width;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= height;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= numBands;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= dataType;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        for (int element : bandOffsets) {
+            hash ^= element;
+            tmp = hash >>> 24;
+            hash <<= 8;
+            hash |= tmp;
+        }
+        for (int element : bankIndices) {
+            hash ^= element;
+            tmp = hash >>> 24;
+            hash <<= 8;
+            hash |= tmp;
+        }
+        hash ^= pixelStride;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+
+        hash ^= scanlineStride;
+        return hash;
+    }
+
+    /**
+     * Gets the scanline stride of this ComponentSampleModel.
+     * 
+     * @return the scanline stride of this ComponentSampleModel.
+     */
+    public final int getScanlineStride() {
+        return scanlineStride;
+    }
+
+    /**
+     * Gets the pixel stride.
+     * 
+     * @return the pixel stride.
+     */
+    public final int getPixelStride() {
+        return pixelStride;
+    }
+
+    @Override
+    public final int getNumDataElements() {
+        return numBands;
+    }
+
+}
diff --git a/awt/java/awt/image/ConvolveOp.java b/awt/java/awt/image/ConvolveOp.java
new file mode 100644
index 0000000..6eb8909
--- /dev/null
+++ b/awt/java/awt/image/ConvolveOp.java
@@ -0,0 +1,545 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Sep 29, 2005
+ */
+
+package java.awt.image;
+
+import java.awt.*;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ConvolveOp class convolves from the source data to the destination using
+ * a convolution kernel. Each output pixel is represented as the result of
+ * multiplying the kernel and the surround of the input pixel.
+ * 
+ * @since Android 1.0
+ */
+public class ConvolveOp implements BufferedImageOp, RasterOp {
+
+    /**
+     * The Constant EDGE_ZERO_FILL indicates that pixels at the edge of the
+     * destination image are set to zero.
+     */
+    public static final int EDGE_ZERO_FILL = 0;
+
+    /**
+     * The Constant EDGE_NO_OP indicates that pixels at the edge of the source
+     * image are converted to the edge pixels in the destination without
+     * modification.
+     */
+    public static final int EDGE_NO_OP = 1;
+
+    /**
+     * The kernel.
+     */
+    private Kernel kernel;
+
+    /**
+     * The edge cond.
+     */
+    private int edgeCond;
+
+    /**
+     * The rhs.
+     */
+    private RenderingHints rhs = null;
+
+    static {
+        // TODO
+        // System.loadLibrary("imageops");
+    }
+
+    /**
+     * Instantiates a new ConvolveOp object with the specified Kernel and
+     * specified edges condition.
+     * 
+     * @param kernel
+     *            the specified Kernel.
+     * @param edgeCondition
+     *            the specified edge condition.
+     * @param hints
+     *            the RenderingHints object, or null.
+     */
+    public ConvolveOp(Kernel kernel, int edgeCondition, RenderingHints hints) {
+        this.kernel = kernel;
+        this.edgeCond = edgeCondition;
+        this.rhs = hints;
+    }
+
+    /**
+     * Instantiates a new ConvolveOp object with the specified Kernel and
+     * EDGE_ZERO_FILL edge condition.
+     * 
+     * @param kernel
+     *            the specified Kernel.
+     */
+    public ConvolveOp(Kernel kernel) {
+        this.kernel = kernel;
+        this.edgeCond = EDGE_ZERO_FILL;
+    }
+
+    /**
+     * Gets the Kernel object of this ConvolveOp.
+     * 
+     * @return the Kernel object of this ConvolveOp.
+     */
+    public final Kernel getKernel() {
+        return (Kernel)kernel.clone();
+    }
+
+    public final RenderingHints getRenderingHints() {
+        return rhs;
+    }
+
+    /**
+     * Gets the edge condition of this ConvolveOp.
+     * 
+     * @return the edge condition: EDGE_NO_OP or EDGE_ZERO_FILL.
+     */
+    public int getEdgeCondition() {
+        return edgeCond;
+    }
+
+    public final Rectangle2D getBounds2D(Raster src) {
+        return src.getBounds();
+    }
+
+    public final Rectangle2D getBounds2D(BufferedImage src) {
+        return getBounds2D(src.getRaster());
+    }
+
+    public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+        if (dstPt == null) {
+            dstPt = new Point2D.Float();
+        }
+
+        dstPt.setLocation(srcPt);
+        return dstPt;
+    }
+
+    public WritableRaster createCompatibleDestRaster(Raster src) {
+        return src.createCompatibleWritableRaster();
+    }
+
+    public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
+        if (dstCM == null) {
+            dstCM = src.getColorModel();
+        }
+
+        if (dstCM instanceof IndexColorModel) {
+            dstCM = ColorModel.getRGBdefault();
+        }
+
+        WritableRaster r = dstCM.isCompatibleSampleModel(src.getSampleModel()) ? src.getRaster()
+                .createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : dstCM
+                .createCompatibleWritableRaster(src.getWidth(), src.getHeight());
+
+        return new BufferedImage(dstCM, r, dstCM.isAlphaPremultiplied(), null);
+    }
+
+    public final WritableRaster filter(Raster src, WritableRaster dst) {
+        if (src == null) { // Should throw according to spec
+            // awt.256=Source raster is null
+            throw new NullPointerException(Messages.getString("awt.256")); //$NON-NLS-1$
+        }
+
+        if (src == dst) {
+            // awt.257=Source raster is equal to destination
+            throw new IllegalArgumentException(Messages.getString("awt.257")); //$NON-NLS-1$
+        }
+
+        if (dst == null) {
+            dst = createCompatibleDestRaster(src);
+        } else if (src.getNumBands() != dst.getNumBands()) {
+            // awt.258=Number of source bands ({0}) is not equal to number of
+            // destination bands ({1})
+            throw new IllegalArgumentException(Messages.getString(
+                    "awt.258", src.getNumBands(), dst.getNumBands())); //$NON-NLS-1$
+        }
+
+        // TODO
+        // if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0)
+        if (slowFilter(src, dst) != 0) {
+            // awt.21F=Unable to transform source
+            throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$
+        }
+
+        return dst;
+    }
+
+    /**
+     * Slow filter.
+     * 
+     * @param src
+     *            the src.
+     * @param dst
+     *            the dst.
+     * @return the int.
+     */
+    private int slowFilter(Raster src, WritableRaster dst) {
+        try {
+            SampleModel sm = src.getSampleModel();
+
+            int numBands = src.getNumBands();
+            int srcHeight = src.getHeight();
+            int srcWidth = src.getWidth();
+
+            int xOrigin = kernel.getXOrigin();
+            int yOrigin = kernel.getYOrigin();
+            int kWidth = kernel.getWidth();
+            int kHeight = kernel.getHeight();
+            float[] data = kernel.getKernelData(null);
+
+            int srcMinX = src.getMinX();
+            int srcMinY = src.getMinY();
+            int dstMinX = dst.getMinX();
+            int dstMinY = dst.getMinY();
+
+            int srcConvMaxX = srcWidth - (kWidth - xOrigin - 1);
+            int srcConvMaxY = srcHeight - (kHeight - yOrigin - 1);
+
+            int[] maxValues = new int[numBands];
+            int[] masks = new int[numBands];
+            int[] sampleSizes = sm.getSampleSize();
+
+            for (int i = 0; i < numBands; i++) {
+                maxValues[i] = (1 << sampleSizes[i]) - 1;
+                masks[i] = ~(maxValues[i]);
+            }
+
+            // Processing bounds
+            float[] pixels = null;
+            pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels);
+            float[] newPixels = new float[pixels.length];
+            int rowLength = srcWidth * numBands;
+            if (this.edgeCond == ConvolveOp.EDGE_NO_OP) {
+                // top
+                int start = 0;
+                int length = yOrigin * rowLength;
+                System.arraycopy(pixels, start, newPixels, start, length);
+                // bottom
+                start = (srcHeight - (kHeight - yOrigin - 1)) * rowLength;
+                length = (kHeight - yOrigin - 1) * rowLength;
+                System.arraycopy(pixels, start, newPixels, start, length);
+                // middle
+                length = xOrigin * numBands;
+                int length1 = (kWidth - xOrigin - 1) * numBands;
+                start = yOrigin * rowLength;
+                int start1 = (yOrigin + 1) * rowLength - length1;
+                for (int i = yOrigin; i < (srcHeight - (kHeight - yOrigin - 1)); i++) {
+                    System.arraycopy(pixels, start, newPixels, start, length);
+                    System.arraycopy(pixels, start1, newPixels, start1, length1);
+                    start += rowLength;
+                    start1 += rowLength;
+                }
+
+            }
+
+            // Cycle over pixels to be calculated
+            for (int i = yOrigin; i < srcConvMaxY; i++) {
+                for (int j = xOrigin; j < srcConvMaxX; j++) {
+
+                    // Take kernel data in backward direction, convolution
+                    int kernelIdx = data.length - 1;
+
+                    int pixelIndex = i * rowLength + j * numBands;
+                    for (int hIdx = 0, rasterHIdx = i - yOrigin; hIdx < kHeight; hIdx++, rasterHIdx++) {
+                        for (int wIdx = 0, rasterWIdx = j - xOrigin; wIdx < kWidth; wIdx++, rasterWIdx++) {
+                            int curIndex = rasterHIdx * rowLength + rasterWIdx * numBands;
+                            for (int idx = 0; idx < numBands; idx++) {
+                                newPixels[pixelIndex + idx] += data[kernelIdx]
+                                        * pixels[curIndex + idx];
+                            }
+                            kernelIdx--;
+                        }
+                    }
+
+                    // Check for overflow now
+                    for (int idx = 0; idx < numBands; idx++) {
+                        if (((int)newPixels[pixelIndex + idx] & masks[idx]) != 0) {
+                            if (newPixels[pixelIndex + idx] < 0) {
+                                newPixels[pixelIndex + idx] = 0;
+                            } else {
+                                newPixels[pixelIndex + idx] = maxValues[idx];
+                            }
+                        }
+                    }
+                }
+            }
+
+            dst.setPixels(dstMinX, dstMinY, srcWidth, srcHeight, newPixels);
+        } catch (Exception e) { // Something goes wrong, signal error
+            return 1;
+        }
+        return 0;
+    }
+
+    public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+        if (src == null) {
+            // awt.259=Source image is null
+            throw new NullPointerException(Messages.getString("awt.259")); //$NON-NLS-1$
+        }
+
+        if (src == dst) {
+            // awt.25A=Source equals to destination
+            throw new IllegalArgumentException(Messages.getString("awt.25A")); //$NON-NLS-1$
+        }
+
+        ColorModel srcCM = src.getColorModel();
+        BufferedImage finalDst = null;
+
+        if (srcCM instanceof IndexColorModel) {
+            src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true);
+            srcCM = src.getColorModel();
+        }
+
+        if (dst == null) {
+            dst = createCompatibleDestImage(src, srcCM);
+        } else {
+            if (!srcCM.equals(dst.getColorModel())) {
+                // Treat BufferedImage.TYPE_INT_RGB and
+                // BufferedImage.TYPE_INT_ARGB as same
+                if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst
+                        .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) {
+                    finalDst = dst;
+                    dst = createCompatibleDestImage(src, srcCM);
+                }
+            }
+        }
+
+        // Skip alpha channel for TYPE_INT_RGB images
+        // TODO
+        // if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != 0)
+        if (slowFilter(src.getRaster(), dst.getRaster()) != 0) {
+            // awt.21F=Unable to transform source
+            throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$
+        }
+
+        if (finalDst != null) {
+            Graphics2D g = finalDst.createGraphics();
+            g.setComposite(AlphaComposite.Src);
+            g.drawImage(dst, 0, 0, null);
+        } else {
+            finalDst = dst;
+        }
+
+        return finalDst;
+    }
+
+    // TODO remove when this method is used
+    /**
+     * Ipp filter.
+     * 
+     * @param src
+     *            the src.
+     * @param dst
+     *            the dst.
+     * @param imageType
+     *            the image type.
+     * @return the int.
+     */
+    @SuppressWarnings("unused")
+    private int ippFilter(Raster src, WritableRaster dst, int imageType) {
+        int srcStride, dstStride;
+        boolean skipChannel = false;
+        int channels;
+        int offsets[] = null;
+
+        switch (imageType) {
+            case BufferedImage.TYPE_INT_RGB:
+            case BufferedImage.TYPE_INT_BGR: {
+                channels = 4;
+                srcStride = src.getWidth() * 4;
+                dstStride = dst.getWidth() * 4;
+                skipChannel = true;
+                break;
+            }
+
+            case BufferedImage.TYPE_INT_ARGB:
+            case BufferedImage.TYPE_INT_ARGB_PRE:
+            case BufferedImage.TYPE_4BYTE_ABGR:
+            case BufferedImage.TYPE_4BYTE_ABGR_PRE: {
+                channels = 4;
+                srcStride = src.getWidth() * 4;
+                dstStride = dst.getWidth() * 4;
+                break;
+            }
+
+            case BufferedImage.TYPE_BYTE_GRAY: {
+                channels = 1;
+                srcStride = src.getWidth();
+                dstStride = dst.getWidth();
+                break;
+            }
+
+            case BufferedImage.TYPE_3BYTE_BGR: {
+                channels = 3;
+                srcStride = src.getWidth() * 3;
+                dstStride = dst.getWidth() * 3;
+                break;
+            }
+
+            case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in
+                // native code?
+            case BufferedImage.TYPE_USHORT_565_RGB:
+            case BufferedImage.TYPE_USHORT_555_RGB:
+            case BufferedImage.TYPE_BYTE_BINARY: {
+                return slowFilter(src, dst);
+            }
+
+            default: {
+                SampleModel srcSM = src.getSampleModel();
+                SampleModel dstSM = dst.getSampleModel();
+
+                if (srcSM instanceof PixelInterleavedSampleModel
+                        && dstSM instanceof PixelInterleavedSampleModel) {
+                    // Check PixelInterleavedSampleModel
+                    if (srcSM.getDataType() != DataBuffer.TYPE_BYTE
+                            || dstSM.getDataType() != DataBuffer.TYPE_BYTE) {
+                        return slowFilter(src, dst);
+                    }
+
+                    channels = srcSM.getNumBands(); // Have IPP functions for 1,
+                    // 3 and 4 channels
+                    if (!(channels == 1 || channels == 3 || channels == 4)) {
+                        return slowFilter(src, dst);
+                    }
+
+                    srcStride = ((ComponentSampleModel)srcSM).getScanlineStride();
+                    dstStride = ((ComponentSampleModel)dstSM).getScanlineStride();
+                } else if (srcSM instanceof SinglePixelPackedSampleModel
+                        && dstSM instanceof SinglePixelPackedSampleModel) {
+                    // Check SinglePixelPackedSampleModel
+                    SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM;
+                    SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM;
+
+                    channels = sppsm1.getNumBands();
+
+                    // TYPE_INT_RGB, TYPE_INT_ARGB...
+                    if (sppsm1.getDataType() != DataBuffer.TYPE_INT
+                            || sppsm2.getDataType() != DataBuffer.TYPE_INT
+                            || !(channels == 3 || channels == 4)) {
+                        return slowFilter(src, dst);
+                    }
+
+                    // Check compatibility of sample models
+                    if (!Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets())
+                            || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) {
+                        return slowFilter(src, dst);
+                    }
+
+                    for (int i = 0; i < channels; i++) {
+                        if (sppsm1.getSampleSize(i) != 8) {
+                            return slowFilter(src, dst);
+                        }
+                    }
+
+                    if (channels == 3) { // Cannot skip channel, don't know
+                        // which is alpha...
+                        channels = 4;
+                    }
+
+                    srcStride = sppsm1.getScanlineStride() * 4;
+                    dstStride = sppsm2.getScanlineStride() * 4;
+                } else {
+                    return slowFilter(src, dst);
+                }
+
+                // Fill offsets if there's a child raster
+                if (src.getParent() != null || dst.getParent() != null) {
+                    if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0
+                            || dst.getSampleModelTranslateX() != 0
+                            || dst.getSampleModelTranslateY() != 0) {
+                        offsets = new int[4];
+                        offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+                        offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+                        offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+                        offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+                    }
+                }
+            }
+        }
+
+        Object srcData, dstData;
+        AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+        try {
+            srcData = dbAccess.getData(src.getDataBuffer());
+            dstData = dbAccess.getData(dst.getDataBuffer());
+        } catch (IllegalArgumentException e) {
+            return -1; // Unknown data buffer type
+        }
+
+        return ippFilter32f(kernel.data, kernel.getWidth(), kernel.getHeight(),
+                kernel.getXOrigin(), kernel.getYOrigin(), edgeCond, srcData, src.getWidth(), src
+                        .getHeight(), srcStride, dstData, dst.getWidth(), dst.getHeight(),
+                dstStride, channels, skipChannel, offsets);
+    }
+
+    /**
+     * Ipp filter32f.
+     * 
+     * @param kernel
+     *            the kernel.
+     * @param kWidth
+     *            the k width.
+     * @param kHeight
+     *            the k height.
+     * @param anchorX
+     *            the anchor x.
+     * @param anchorY
+     *            the anchor y.
+     * @param borderType
+     *            the border type.
+     * @param src
+     *            the src.
+     * @param srcWidth
+     *            the src width.
+     * @param srcHeight
+     *            the src height.
+     * @param srcStride
+     *            the src stride.
+     * @param dst
+     *            the dst.
+     * @param dstWidth
+     *            the dst width.
+     * @param dstHeight
+     *            the dst height.
+     * @param dstStride
+     *            the dst stride.
+     * @param channels
+     *            the channels.
+     * @param skipChannel
+     *            the skip channel.
+     * @param offsets
+     *            the offsets.
+     * @return the int.
+     */
+    private native int ippFilter32f(float kernel[], int kWidth, int kHeight, int anchorX,
+            int anchorY, int borderType, Object src, int srcWidth, int srcHeight, int srcStride,
+            Object dst, int dstWidth, int dstHeight, int dstStride, int channels,
+            boolean skipChannel, int offsets[]);
+}
diff --git a/awt/java/awt/image/CropImageFilter.java b/awt/java/awt/image/CropImageFilter.java
new file mode 100644
index 0000000..2f4ca78
--- /dev/null
+++ b/awt/java/awt/image/CropImageFilter.java
@@ -0,0 +1,196 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.util.Hashtable;
+
+/**
+ * The CropImageFilter class crops a rectangular region of an source Image and
+ * provides a source for a new image containing the extracted region.
+ * 
+ * @since Android 1.0
+ */
+public class CropImageFilter extends ImageFilter {
+
+    /**
+     * The HEIGHT.
+     */
+    private final int X, Y, WIDTH, HEIGHT;
+
+    /**
+     * Instantiates a new CropImageFilter object with the specified rectangular
+     * area.
+     * 
+     * @param x
+     *            the X coordinate of rectangular area.
+     * @param y
+     *            the Y coordinate of rectangular area.
+     * @param w
+     *            the width of rectangular area.
+     * @param h
+     *            the height of rectangular area.
+     */
+    public CropImageFilter(int x, int y, int w, int h) {
+        X = x;
+        Y = y;
+        WIDTH = w;
+        HEIGHT = h;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void setProperties(Hashtable<?, ?> props) {
+        Hashtable<Object, Object> fprops;
+        if (props == null) {
+            fprops = new Hashtable<Object, Object>();
+        } else {
+            fprops = (Hashtable<Object, Object>)props.clone();
+        }
+        String propName = "Crop Filters"; //$NON-NLS-1$
+        String prop = "x=" + X + "; y=" + Y + "; width=" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                WIDTH + "; height=" + HEIGHT; //$NON-NLS-1$
+        Object o = fprops.get(propName);
+        if (o != null) {
+            if (o instanceof String) {
+                prop = (String)o + "; " + prop; //$NON-NLS-1$
+            } else {
+                prop = o.toString() + "; " + prop; //$NON-NLS-1$
+            }
+        }
+        fprops.put(propName, prop);
+        consumer.setProperties(fprops);
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off,
+            int scansize) {
+
+        if (x + w < X || X + WIDTH < x || y + h < Y || Y + HEIGHT < y) {
+            return;
+        }
+
+        int destX, destY, destWidth, destHeight, endX, endY, srcEndX, srcEndY;
+
+        int newOffset = off;
+
+        endX = X + WIDTH;
+        endY = Y + HEIGHT;
+
+        srcEndX = x + w;
+        srcEndY = y + h;
+
+        if (x <= X) {
+            destX = 0;
+            newOffset += X;
+            if (endX >= srcEndX) {
+                destWidth = srcEndX - X;
+            } else {
+                destWidth = WIDTH;
+            }
+        } else {
+            destX = x - X;
+            if (endX >= srcEndX) {
+                destWidth = w;
+            } else {
+                destWidth = endX - x;
+            }
+        }
+
+        if (y <= Y) {
+            newOffset += scansize * (Y - y);
+            destY = 0;
+            if (endY >= srcEndY) {
+                destHeight = srcEndY - Y;
+            } else {
+                destHeight = HEIGHT;
+            }
+        } else {
+            destY = y - Y;
+            if (endY >= srcEndY) {
+                destHeight = h;
+            } else {
+                destHeight = endY - y;
+            }
+        }
+        consumer.setPixels(destX, destY, destWidth, destHeight, model, pixels, newOffset, scansize);
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off,
+            int scansize) {
+
+        if (x + w < X || X + WIDTH < x || y + h < Y || Y + HEIGHT < y) {
+            return;
+        }
+
+        int destX, destY, destWidth, destHeight, endX, endY, srcEndX, srcEndY;
+
+        int newOffset = off;
+
+        endX = X + WIDTH;
+        endY = Y + HEIGHT;
+
+        srcEndX = x + w;
+        srcEndY = y + h;
+
+        if (x <= X) {
+            destX = 0;
+            newOffset += X;
+            if (endX >= srcEndX) {
+                destWidth = srcEndX - X;
+            } else {
+                destWidth = WIDTH;
+            }
+        } else {
+            destX = x - X;
+            if (endX >= srcEndX) {
+                destWidth = w;
+            } else {
+                destWidth = endX - x;
+            }
+        }
+
+        if (y <= Y) {
+            newOffset += scansize * (Y - y);
+            destY = 0;
+            if (endY >= srcEndY) {
+                destHeight = srcEndY - Y;
+            } else {
+                destHeight = HEIGHT;
+            }
+        } else {
+            destY = y - Y;
+            if (endY >= srcEndY) {
+                destHeight = h;
+            } else {
+                destHeight = endY - y;
+            }
+        }
+        consumer.setPixels(destX, destY, destWidth, destHeight, model, pixels, newOffset, scansize);
+    }
+
+    @Override
+    public void setDimensions(int w, int h) {
+        consumer.setDimensions(WIDTH, HEIGHT);
+    }
+
+}
diff --git a/awt/java/awt/image/DataBuffer.java b/awt/java/awt/image/DataBuffer.java
new file mode 100644
index 0000000..92f900f
--- /dev/null
+++ b/awt/java/awt/image/DataBuffer.java
@@ -0,0 +1,481 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.gl.image.DataBufferListener;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class DataBuffer is a wrapper class for a data array to be used for the
+ * situation where a suite of functionality acts on a set of data in a
+ * consistent way even though the primitive type of the data may vary from one
+ * use to the next.
+ * 
+ * @since Android 1.0
+ */
+public abstract class DataBuffer {
+
+    /**
+     * The Constant TYPE_BYTE.
+     */
+    public static final int TYPE_BYTE = 0;
+
+    /**
+     * The Constant TYPE_USHORT.
+     */
+    public static final int TYPE_USHORT = 1;
+
+    /**
+     * The Constant TYPE_SHORT.
+     */
+    public static final int TYPE_SHORT = 2;
+
+    /**
+     * The Constant TYPE_INT.
+     */
+    public static final int TYPE_INT = 3;
+
+    /**
+     * The Constant TYPE_FLOAT.
+     */
+    public static final int TYPE_FLOAT = 4;
+
+    /**
+     * The Constant TYPE_DOUBLE.
+     */
+    public static final int TYPE_DOUBLE = 5;
+
+    /**
+     * The Constant TYPE_UNDEFINED.
+     */
+    public static final int TYPE_UNDEFINED = 32;
+
+    /**
+     * The data type indicates the primitive type of the data in this
+     * DataBuffer.
+     */
+    protected int dataType;
+
+    /**
+     * The number of data arrays in this DataBuffer.
+     */
+    protected int banks;
+
+    /**
+     * The starting index for reading the data from the first (or only) internal
+     * data array.
+     */
+    protected int offset;
+
+    /**
+     * The length (number of elements) of the data arrays.
+     */
+    protected int size;
+
+    /**
+     * The starting indices for reading the data from the internal data arrays.
+     */
+    protected int offsets[];
+
+    /**
+     * The data changed.
+     */
+    boolean dataChanged = true;
+
+    /**
+     * The data taken.
+     */
+    boolean dataTaken = false;
+
+    /**
+     * The listener.
+     */
+    DataBufferListener listener;
+
+    static {
+        AwtImageBackdoorAccessorImpl.init();
+    }
+
+    /**
+     * Instantiates a new data buffer.
+     * 
+     * @param dataType
+     *            the data type.
+     * @param size
+     *            the length (number of elements) of the data arrays.
+     * @param numBanks
+     *            the number of data arrays to create.
+     * @param offsets
+     *            the starting indices for reading the data from the internal
+     *            data arrays.
+     */
+    protected DataBuffer(int dataType, int size, int numBanks, int[] offsets) {
+        this.dataType = dataType;
+        this.size = size;
+        this.banks = numBanks;
+        this.offsets = offsets.clone();
+        this.offset = offsets[0];
+    }
+
+    /**
+     * Instantiates a new data buffer with all of the data arrays starting at
+     * the same index.
+     * 
+     * @param dataType
+     *            the data type.
+     * @param size
+     *            the length (number of elements) of the data arrays.
+     * @param numBanks
+     *            the number of data arrays to create.
+     * @param offset
+     *            the offset to use for all of the data arrays.
+     */
+    protected DataBuffer(int dataType, int size, int numBanks, int offset) {
+        this.dataType = dataType;
+        this.size = size;
+        this.banks = numBanks;
+        this.offset = offset;
+        this.offsets = new int[numBanks];
+        int i = 0;
+        while (i < numBanks) {
+            offsets[i++] = offset;
+        }
+    }
+
+    /**
+     * Instantiates a new data buffer with all of the data arrays read from the
+     * beginning (at offset zero).
+     * 
+     * @param dataType
+     *            the data type.
+     * @param size
+     *            the length (number of elements) of the data arrays.
+     * @param numBanks
+     *            the number of data arrays to create.
+     */
+    protected DataBuffer(int dataType, int size, int numBanks) {
+        this.dataType = dataType;
+        this.size = size;
+        this.banks = numBanks;
+        this.offset = 0;
+        this.offsets = new int[numBanks];
+    }
+
+    /**
+     * Instantiates a new data buffer with one internal data array read from the
+     * beginning (at offset zero).
+     * 
+     * @param dataType
+     *            the data type.
+     * @param size
+     *            the length (number of elements) of the data arrays.
+     */
+    protected DataBuffer(int dataType, int size) {
+        this.dataType = dataType;
+        this.size = size;
+        this.banks = 1;
+        this.offset = 0;
+        this.offsets = new int[1];
+    }
+
+    /**
+     * Sets the data value in the specified array at the specified index.
+     * 
+     * @param bank
+     *            the internal array to the data to.
+     * @param i
+     *            the index within the array where the data should be written.
+     * @param val
+     *            the value to write into the array.
+     */
+    public abstract void setElem(int bank, int i, int val);
+
+    /**
+     * Sets the float data value in the specified array at the specified index.
+     * 
+     * @param bank
+     *            the internal array to the data to.
+     * @param i
+     *            the index within the array where the data should be written.
+     * @param val
+     *            the value to write into the array.
+     */
+    public void setElemFloat(int bank, int i, float val) {
+        setElem(bank, i, (int)val);
+    }
+
+    /**
+     * Sets the double data value in the specified array at the specified index.
+     * 
+     * @param bank
+     *            the internal array to the data to.
+     * @param i
+     *            the index within the array where the data should be written.
+     * @param val
+     *            the value to write into the array.
+     */
+    public void setElemDouble(int bank, int i, double val) {
+        setElem(bank, i, (int)val);
+    }
+
+    /**
+     * Sets the data value in the first array at the specified index.
+     * 
+     * @param i
+     *            the index within the array where the data should be written.
+     * @param val
+     *            the value to write into the array.
+     */
+    public void setElem(int i, int val) {
+        setElem(0, i, val);
+    }
+
+    /**
+     * Gets the data value from the specified data array at the specified index.
+     * 
+     * @param bank
+     *            the data array to read from.
+     * @param i
+     *            the index within the array where the data should be read.
+     * @return the data element.
+     */
+    public abstract int getElem(int bank, int i);
+
+    /**
+     * Gets the float-type data value from the specified data array at the
+     * specified index.
+     * 
+     * @param bank
+     *            the data array to read from.
+     * @param i
+     *            the index within the array where the data should be read.
+     * @return the data element.
+     */
+    public float getElemFloat(int bank, int i) {
+        return getElem(bank, i);
+    }
+
+    /**
+     * Gets the double-type data value from the specified data array at the
+     * specified index.
+     * 
+     * @param bank
+     *            the data array to read from.
+     * @param i
+     *            the index within the array where the data should be read.
+     * @return the data element.
+     */
+    public double getElemDouble(int bank, int i) {
+        return getElem(bank, i);
+    }
+
+    /**
+     * Sets the float data value in the first array at the specified index.
+     * 
+     * @param i
+     *            the index within the array where the data should be written.
+     * @param val
+     *            the value to write into the array.
+     */
+    public void setElemFloat(int i, float val) {
+        setElemFloat(0, i, val);
+    }
+
+    /**
+     * Sets the double data value in the first array at the specified index.
+     * 
+     * @param i
+     *            the index within the array where the data should be written.
+     * @param val
+     *            the value to write into the array.
+     */
+    public void setElemDouble(int i, double val) {
+        setElemDouble(0, i, val);
+    }
+
+    /**
+     * Gets the data value from the first data array at the specified index and
+     * returns it as an integer.
+     * 
+     * @param i
+     *            the index within the array where the data should be read.
+     * @return the data element.
+     */
+    public int getElem(int i) {
+        return getElem(0, i);
+    }
+
+    /**
+     * Gets the data value from the first data array at the specified index and
+     * returns it as a float.
+     * 
+     * @param i
+     *            the index within the array where the data should be read.
+     * @return the data element.
+     */
+    public float getElemFloat(int i) {
+        return getElem(0, i);
+    }
+
+    /**
+     * Gets the data value from the first data array at the specified index and
+     * returns it as a double.
+     * 
+     * @param i
+     *            the index within the array where the data should be read.
+     * @return the data element.
+     */
+    public double getElemDouble(int i) {
+        return getElem(i);
+    }
+
+    /**
+     * Gets the array giving the offsets corresponding to the internal data
+     * arrays.
+     * 
+     * @return the array of offsets.
+     */
+    public int[] getOffsets() {
+        return offsets;
+    }
+
+    /**
+     * Gets the size in bits of the primitive data type.
+     * 
+     * @return the size in bits of the primitive data type.
+     */
+    public int getSize() {
+        return size;
+    }
+
+    /**
+     * Gets the offset corresponding to the first internal data array.
+     * 
+     * @return the offset.
+     */
+    public int getOffset() {
+        return offset;
+    }
+
+    /**
+     * Gets the number of data arrays in this DataBuffer.
+     * 
+     * @return the number of data arrays.
+     */
+    public int getNumBanks() {
+        return banks;
+    }
+
+    /**
+     * Gets the primitive type of this buffer's data.
+     * 
+     * @return the data type.
+     */
+    public int getDataType() {
+        return this.dataType;
+    }
+
+    /**
+     * Gets the size in bits of the primitive data type.
+     * 
+     * @param type
+     *            the primitive type.
+     * @return the size in bits of the primitive data type.
+     */
+    public static int getDataTypeSize(int type) {
+        switch (type) {
+
+            case TYPE_BYTE:
+                return 8;
+
+            case TYPE_USHORT:
+            case TYPE_SHORT:
+                return 16;
+
+            case TYPE_INT:
+            case TYPE_FLOAT:
+                return 32;
+
+            case TYPE_DOUBLE:
+                return 64;
+
+            default:
+                // awt.22C=Unknown data type {0}
+                throw new IllegalArgumentException(Messages.getString("awt.22C", type)); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that the data has changed.
+     */
+    void notifyChanged() {
+        if (listener != null && !dataChanged) {
+            dataChanged = true;
+            listener.dataChanged();
+        }
+    }
+
+    /**
+     * Notifies the listener that the data has been released.
+     */
+    void notifyTaken() {
+        if (listener != null && !dataTaken) {
+            dataTaken = true;
+            listener.dataTaken();
+        }
+    }
+
+    /**
+     * Release the data.
+     */
+    void releaseData() {
+        if (listener != null && dataTaken) {
+            dataTaken = false;
+            listener.dataReleased();
+        }
+    }
+
+    /**
+     * Adds the data buffer listener.
+     * 
+     * @param listener
+     *            the listener.
+     */
+    void addDataBufferListener(DataBufferListener listener) {
+        this.listener = listener;
+    }
+
+    /**
+     * Removes the data buffer listener.
+     */
+    void removeDataBufferListener() {
+        listener = null;
+    }
+
+    /**
+     * Validate.
+     */
+    void validate() {
+        dataChanged = false;
+    }
+
+}
diff --git a/awt/java/awt/image/DataBufferByte.java b/awt/java/awt/image/DataBufferByte.java
new file mode 100644
index 0000000..3407de8
--- /dev/null
+++ b/awt/java/awt/image/DataBufferByte.java
@@ -0,0 +1,183 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+/**
+ * The Class DataBufferByte is the subclass of DataBuffer for the case where the
+ * underlying data is of type byte.
+ * 
+ * @since Android 1.0
+ */
+public final class DataBufferByte extends DataBuffer {
+
+    /**
+     * The data.
+     */
+    byte data[][];
+
+    /**
+     * Instantiates a new data buffer of type unsigned short.
+     * 
+     * @param dataArrays
+     *            the data arrays to copy the data from.
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     * @param offsets
+     *            the starting indices for reading the data from the internal
+     *            data arrays.
+     */
+    public DataBufferByte(byte dataArrays[][], int size, int offsets[]) {
+        super(TYPE_BYTE, size, dataArrays.length, offsets);
+        data = dataArrays.clone();
+    }
+
+    /**
+     * Instantiates a new data buffer of type unsigned short.
+     * 
+     * @param dataArrays
+     *            the data arrays to copy the data from.
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     */
+    public DataBufferByte(byte dataArrays[][], int size) {
+        super(TYPE_BYTE, size, dataArrays.length);
+        data = dataArrays.clone();
+    }
+
+    /**
+     * Instantiates a new data buffer of type unsigned short with a single
+     * underlying array of data.
+     * 
+     * @param dataArray
+     *            the data array to copy the data from.
+     * @param size
+     *            the length (number of elements) to use.
+     * @param offset
+     *            the starting index to use when reading the data.
+     */
+    public DataBufferByte(byte dataArray[], int size, int offset) {
+        super(TYPE_BYTE, size, 1, offset);
+        data = new byte[1][];
+        data[0] = dataArray;
+    }
+
+    /**
+     * Instantiates a new data buffer of type unsigned short with a single
+     * underlying array of data starting at index 0.
+     * 
+     * @param dataArray
+     *            the data array to copy the data from.
+     * @param size
+     *            the length (number of elements) to use.
+     */
+    public DataBufferByte(byte dataArray[], int size) {
+        super(TYPE_BYTE, size);
+        data = new byte[1][];
+        data[0] = dataArray;
+    }
+
+    /**
+     * Instantiates a new empty data buffer of type unsigned short with offsets
+     * equal to zero.
+     * 
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     * @param numBanks
+     *            the number of data arrays to create.
+     */
+    public DataBufferByte(int size, int numBanks) {
+        super(TYPE_BYTE, size, numBanks);
+        data = new byte[numBanks][];
+        int i = 0;
+        while (i < numBanks) {
+            data[i++] = new byte[size];
+        }
+    }
+
+    /**
+     * Instantiates a new empty data buffer of type unsigned short with a single
+     * underlying array of data starting at index 0.
+     * 
+     * @param size
+     *            the length (number of elements) to use.
+     */
+    public DataBufferByte(int size) {
+        super(TYPE_BYTE, size);
+        data = new byte[1][];
+        data[0] = new byte[size];
+    }
+
+    @Override
+    public void setElem(int bank, int i, int val) {
+        data[bank][offsets[bank] + i] = (byte)val;
+        notifyChanged();
+    }
+
+    @Override
+    public void setElem(int i, int val) {
+        data[0][offset + i] = (byte)val;
+        notifyChanged();
+    }
+
+    @Override
+    public int getElem(int bank, int i) {
+        return (data[bank][offsets[bank] + i]) & 0xff;
+    }
+
+    /**
+     * Gets the data of the specified internal data array.
+     * 
+     * @param bank
+     *            the index of the desired data array.
+     * @return the data.
+     */
+    public byte[] getData(int bank) {
+        notifyTaken();
+        return data[bank];
+    }
+
+    @Override
+    public int getElem(int i) {
+        return (data[0][offset + i]) & 0xff;
+    }
+
+    /**
+     * Gets the bank data.
+     * 
+     * @return the bank data.
+     */
+    public byte[][] getBankData() {
+        notifyTaken();
+        return data.clone();
+    }
+
+    /**
+     * Gets the data of the first data array.
+     * 
+     * @return the data.
+     */
+    public byte[] getData() {
+        notifyTaken();
+        return data[0];
+    }
+
+}
diff --git a/awt/java/awt/image/DataBufferDouble.java b/awt/java/awt/image/DataBufferDouble.java
new file mode 100644
index 0000000..5d0a516
--- /dev/null
+++ b/awt/java/awt/image/DataBufferDouble.java
@@ -0,0 +1,226 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+/**
+ * The Class DataBufferDouble is the subclass of DataBuffer for the case where
+ * the underlying data is of type double.
+ * 
+ * @since Android 1.0
+ */
+public final class DataBufferDouble extends DataBuffer {
+
+    /**
+     * The data.
+     */
+    double data[][];
+
+    /**
+     * Instantiates a new data buffer of type double.
+     * 
+     * @param dataArrays
+     *            the data arrays to copy the data from.
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     * @param offsets
+     *            the starting indices for reading the data from the internal
+     *            data arrays.
+     */
+    public DataBufferDouble(double dataArrays[][], int size, int offsets[]) {
+        super(TYPE_DOUBLE, size, dataArrays.length, offsets);
+        data = dataArrays.clone();
+    }
+
+    /**
+     * Instantiates a new data buffer of type double.
+     * 
+     * @param dataArrays
+     *            the data arrays to copy the data from.
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     */
+    public DataBufferDouble(double dataArrays[][], int size) {
+        super(TYPE_DOUBLE, size, dataArrays.length);
+        data = dataArrays.clone();
+    }
+
+    /**
+     * Instantiates a new data buffer of type double with a single underlying
+     * array of data.
+     * 
+     * @param dataArray
+     *            the data array to copy the data from.
+     * @param size
+     *            the length (number of elements) to use.
+     * @param offset
+     *            the starting index to use when reading the data.
+     */
+    public DataBufferDouble(double dataArray[], int size, int offset) {
+        super(TYPE_DOUBLE, size, 1, offset);
+        data = new double[1][];
+        data[0] = dataArray;
+    }
+
+    /**
+     * Instantiates a new data buffer of type double with a single underlying
+     * array of data starting at index 0.
+     * 
+     * @param dataArray
+     *            the data array to copy the data from.
+     * @param size
+     *            the length (number of elements) to use.
+     */
+    public DataBufferDouble(double dataArray[], int size) {
+        super(TYPE_DOUBLE, size);
+        data = new double[1][];
+        data[0] = dataArray;
+    }
+
+    /**
+     * Instantiates a new empty data buffer of type double with offsets equal to
+     * zero.
+     * 
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     * @param numBanks
+     *            the number of data arrays to create.
+     */
+    public DataBufferDouble(int size, int numBanks) {
+        super(TYPE_DOUBLE, size, numBanks);
+        data = new double[numBanks][];
+        int i = 0;
+        while (i < numBanks) {
+            data[i++] = new double[size];
+        }
+    }
+
+    /**
+     * Instantiates a new empty data buffer of type double with a single
+     * underlying array of data starting at index 0.
+     * 
+     * @param size
+     *            the length (number of elements) to use.
+     */
+    public DataBufferDouble(int size) {
+        super(TYPE_DOUBLE, size);
+        data = new double[1][];
+        data[0] = new double[size];
+    }
+
+    @Override
+    public void setElem(int bank, int i, int val) {
+        data[bank][offsets[bank] + i] = val;
+        notifyChanged();
+    }
+
+    @Override
+    public void setElemFloat(int bank, int i, float val) {
+        data[bank][offsets[bank] + i] = val;
+        notifyChanged();
+    }
+
+    @Override
+    public void setElemDouble(int bank, int i, double val) {
+        data[bank][offsets[bank] + i] = val;
+        notifyChanged();
+    }
+
+    @Override
+    public void setElem(int i, int val) {
+        data[0][offset + i] = val;
+        notifyChanged();
+    }
+
+    @Override
+    public int getElem(int bank, int i) {
+        return (int)(data[bank][offsets[bank] + i]);
+    }
+
+    @Override
+    public float getElemFloat(int bank, int i) {
+        return (float)(data[bank][offsets[bank] + i]);
+    }
+
+    @Override
+    public double getElemDouble(int bank, int i) {
+        return data[bank][offsets[bank] + i];
+    }
+
+    @Override
+    public void setElemFloat(int i, float val) {
+        data[0][offset + i] = val;
+        notifyChanged();
+    }
+
+    @Override
+    public void setElemDouble(int i, double val) {
+        data[0][offset + i] = val;
+        notifyChanged();
+    }
+
+    /**
+     * Gets the data of the specified internal data array.
+     * 
+     * @param bank
+     *            the index of the desired data array.
+     * @return the data.
+     */
+    public double[] getData(int bank) {
+        notifyTaken();
+        return data[bank];
+    }
+
+    @Override
+    public int getElem(int i) {
+        return (int)(data[0][offset + i]);
+    }
+
+    @Override
+    public float getElemFloat(int i) {
+        return (float)(data[0][offset + i]);
+    }
+
+    @Override
+    public double getElemDouble(int i) {
+        return data[0][offset + i];
+    }
+
+    /**
+     * Gets the bank data.
+     * 
+     * @return the bank data.
+     */
+    public double[][] getBankData() {
+        notifyTaken();
+        return data.clone();
+    }
+
+    /**
+     * Gets the data of the first data array.
+     * 
+     * @return the data.
+     */
+    public double[] getData() {
+        notifyTaken();
+        return data[0];
+    }
+}
diff --git a/awt/java/awt/image/DataBufferFloat.java b/awt/java/awt/image/DataBufferFloat.java
new file mode 100644
index 0000000..9a4a6bf
--- /dev/null
+++ b/awt/java/awt/image/DataBufferFloat.java
@@ -0,0 +1,226 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+/**
+ * The Class DataBufferFloat is the subclass of DataBuffer for the case where
+ * the underlying data is float.
+ * 
+ * @since Android 1.0
+ */
+public final class DataBufferFloat extends DataBuffer {
+
+    /**
+     * The data.
+     */
+    float data[][];
+
+    /**
+     * Instantiates a new data buffer of type float.
+     * 
+     * @param dataArrays
+     *            the data arrays to copy the data from.
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     * @param offsets
+     *            the starting indices for reading the data from the internal
+     *            data arrays.
+     */
+    public DataBufferFloat(float dataArrays[][], int size, int offsets[]) {
+        super(TYPE_FLOAT, size, dataArrays.length, offsets);
+        data = dataArrays.clone();
+    }
+
+    /**
+     * Instantiates a new data buffer of type float.
+     * 
+     * @param dataArrays
+     *            the data arrays to copy the data from.
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     */
+    public DataBufferFloat(float dataArrays[][], int size) {
+        super(TYPE_FLOAT, size, dataArrays.length);
+        data = dataArrays.clone();
+    }
+
+    /**
+     * Instantiates a new data buffer of type float with a single underlying
+     * array of data.
+     * 
+     * @param dataArray
+     *            the data array to copy the data from.
+     * @param size
+     *            the length (number of elements) to use.
+     * @param offset
+     *            the starting index to use when reading the data.
+     */
+    public DataBufferFloat(float dataArray[], int size, int offset) {
+        super(TYPE_FLOAT, size, 1, offset);
+        data = new float[1][];
+        data[0] = dataArray;
+    }
+
+    /**
+     * Instantiates a new data buffer of type float with a single underlying
+     * array of data starting at index 0.
+     * 
+     * @param dataArray
+     *            the data array to copy the data from.
+     * @param size
+     *            the length (number of elements) to use.
+     */
+    public DataBufferFloat(float dataArray[], int size) {
+        super(TYPE_FLOAT, size);
+        data = new float[1][];
+        data[0] = dataArray;
+    }
+
+    /**
+     * Instantiates a new empty data buffer of type float with offsets equal to
+     * zero.
+     * 
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     * @param numBanks
+     *            the number of data arrays to create.
+     */
+    public DataBufferFloat(int size, int numBanks) {
+        super(TYPE_FLOAT, size, numBanks);
+        data = new float[numBanks][];
+        int i = 0;
+        while (i < numBanks) {
+            data[i++] = new float[size];
+        }
+    }
+
+    /**
+     * Instantiates a new empty data buffer of type float with a single
+     * underlying array of data starting at index 0.
+     * 
+     * @param size
+     *            the length (number of elements) to use.
+     */
+    public DataBufferFloat(int size) {
+        super(TYPE_FLOAT, size);
+        data = new float[1][];
+        data[0] = new float[size];
+    }
+
+    @Override
+    public void setElem(int bank, int i, int val) {
+        data[bank][offsets[bank] + i] = val;
+        notifyChanged();
+    }
+
+    @Override
+    public void setElemFloat(int bank, int i, float val) {
+        data[bank][offsets[bank] + i] = val;
+        notifyChanged();
+    }
+
+    @Override
+    public void setElemDouble(int bank, int i, double val) {
+        data[bank][offsets[bank] + i] = (float)val;
+        notifyChanged();
+    }
+
+    @Override
+    public void setElem(int i, int val) {
+        data[0][offset + i] = val;
+        notifyChanged();
+    }
+
+    @Override
+    public int getElem(int bank, int i) {
+        return (int)(data[bank][offsets[bank] + i]);
+    }
+
+    @Override
+    public float getElemFloat(int bank, int i) {
+        return data[bank][offsets[bank] + i];
+    }
+
+    @Override
+    public double getElemDouble(int bank, int i) {
+        return data[bank][offsets[bank] + i];
+    }
+
+    @Override
+    public void setElemFloat(int i, float val) {
+        data[0][offset + i] = val;
+        notifyChanged();
+    }
+
+    @Override
+    public void setElemDouble(int i, double val) {
+        data[0][offset + i] = (float)val;
+        notifyChanged();
+    }
+
+    /**
+     * Gets the data of the specified internal data array.
+     * 
+     * @param bank
+     *            the index of the desired array.
+     * @return the data.
+     */
+    public float[] getData(int bank) {
+        notifyTaken();
+        return data[bank];
+    }
+
+    @Override
+    public int getElem(int i) {
+        return (int)(data[0][offset + i]);
+    }
+
+    @Override
+    public float getElemFloat(int i) {
+        return data[0][offset + i];
+    }
+
+    @Override
+    public double getElemDouble(int i) {
+        return data[0][offset + i];
+    }
+
+    /**
+     * Gets the bank data.
+     * 
+     * @return the bank data.
+     */
+    public float[][] getBankData() {
+        notifyTaken();
+        return data.clone();
+    }
+
+    /**
+     * Gets the data of the first data array.
+     * 
+     * @return the data.
+     */
+    public float[] getData() {
+        notifyTaken();
+        return data[0];
+    }
+}
diff --git a/awt/java/awt/image/DataBufferInt.java b/awt/java/awt/image/DataBufferInt.java
new file mode 100644
index 0000000..380a127
--- /dev/null
+++ b/awt/java/awt/image/DataBufferInt.java
@@ -0,0 +1,182 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+/**
+ * The Class DataBufferInt is the subclass of DataBuffer for the case where the
+ * underlying data is of type integer.
+ * 
+ * @since Android 1.0
+ */
+public final class DataBufferInt extends DataBuffer {
+
+    /**
+     * The data.
+     */
+    int data[][];
+
+    /**
+     * Instantiates a new data buffer of type integer.
+     * 
+     * @param dataArrays
+     *            the data arrays to copy the data from.
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     * @param offsets
+     *            the starting indices for reading the data from the internal
+     *            data arrays.
+     */
+    public DataBufferInt(int dataArrays[][], int size, int offsets[]) {
+        super(TYPE_INT, size, dataArrays.length, offsets);
+        data = dataArrays.clone();
+    }
+
+    /**
+     * Instantiates a new data buffer of type integer.
+     * 
+     * @param dataArrays
+     *            the data arrays to copy the data from.
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     */
+    public DataBufferInt(int dataArrays[][], int size) {
+        super(TYPE_INT, size, dataArrays.length);
+        data = dataArrays.clone();
+    }
+
+    /**
+     * Instantiates a new data buffer of type integer with a single underlying
+     * array of data.
+     * 
+     * @param dataArray
+     *            the data array to copy the data from.
+     * @param size
+     *            the length (number of elements) to use.
+     * @param offset
+     *            the starting index to use when reading the data.
+     */
+    public DataBufferInt(int dataArray[], int size, int offset) {
+        super(TYPE_INT, size, 1, offset);
+        data = new int[1][];
+        data[0] = dataArray;
+    }
+
+    /**
+     * Instantiates a new data buffer of type integer with a single underlying
+     * array of data starting at index 0.
+     * 
+     * @param dataArray
+     *            the data array to copy the data from.
+     * @param size
+     *            the length (number of elements) to use.
+     */
+    public DataBufferInt(int dataArray[], int size) {
+        super(TYPE_INT, size);
+        data = new int[1][];
+        data[0] = dataArray;
+    }
+
+    /**
+     * Instantiates a new empty data buffer of type integer with offsets equal
+     * to zero.
+     * 
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     * @param numBanks
+     *            the number of data arrays to create.
+     */
+    public DataBufferInt(int size, int numBanks) {
+        super(TYPE_INT, size, numBanks);
+        data = new int[numBanks][];
+        int i = 0;
+        while (i < numBanks) {
+            data[i++] = new int[size];
+        }
+    }
+
+    /**
+     * Instantiates a new empty data buffer of type integer with a single
+     * underlying array of data starting at index 0.
+     * 
+     * @param size
+     *            the length (number of elements) to use.
+     */
+    public DataBufferInt(int size) {
+        super(TYPE_INT, size);
+        data = new int[1][];
+        data[0] = new int[size];
+    }
+
+    @Override
+    public void setElem(int bank, int i, int val) {
+        data[bank][offsets[bank] + i] = val;
+        notifyChanged();
+    }
+
+    @Override
+    public void setElem(int i, int val) {
+        data[0][offset + i] = val;
+        notifyChanged();
+    }
+
+    @Override
+    public int getElem(int bank, int i) {
+        return data[bank][offsets[bank] + i];
+    }
+
+    /**
+     * Gets the data of the specified internal data array.
+     * 
+     * @param bank
+     *            the index of the desired data array.
+     * @return the data.
+     */
+    public int[] getData(int bank) {
+        notifyTaken();
+        return data[bank];
+    }
+
+    @Override
+    public int getElem(int i) {
+        return data[0][offset + i];
+    }
+
+    /**
+     * Gets the bank data.
+     * 
+     * @return the bank data.
+     */
+    public int[][] getBankData() {
+        notifyTaken();
+        return data.clone();
+    }
+
+    /**
+     * Gets the data of the first data array.
+     * 
+     * @return the data.
+     */
+    public int[] getData() {
+        notifyTaken();
+        return data[0];
+    }
+}
diff --git a/awt/java/awt/image/DataBufferShort.java b/awt/java/awt/image/DataBufferShort.java
new file mode 100644
index 0000000..1b11b29
--- /dev/null
+++ b/awt/java/awt/image/DataBufferShort.java
@@ -0,0 +1,181 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+/**
+ * The Class DataBufferShort is the subclass of DataBuffer for the case where
+ * the underlying data is short.
+ * 
+ * @since Android 1.0
+ */
+public final class DataBufferShort extends DataBuffer {
+
+    /**
+     * The data.
+     */
+    short data[][];
+
+    /**
+     * Instantiates a new data buffer of type short.
+     * 
+     * @param dataArrays
+     *            the data arrays to copy the data from.
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     * @param offsets
+     *            the starting indices for reading the data from the internal
+     *            data arrays.
+     */
+    public DataBufferShort(short dataArrays[][], int size, int offsets[]) {
+        super(TYPE_SHORT, size, dataArrays.length, offsets);
+        data = dataArrays.clone();
+    }
+
+    /**
+     * Instantiates a new data buffer of type short.
+     * 
+     * @param dataArrays
+     *            the data arrays to copy the data from.
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     */
+    public DataBufferShort(short dataArrays[][], int size) {
+        super(TYPE_SHORT, size, dataArrays.length);
+        data = dataArrays.clone();
+    }
+
+    /**
+     * Instantiates a new data buffer of type short with a single underlying
+     * array of data.
+     * 
+     * @param dataArray
+     *            the data array to copy the data from.
+     * @param size
+     *            the length (number of elements) to use.
+     * @param offset
+     *            the starting index to use when reading the data.
+     */
+    public DataBufferShort(short dataArray[], int size, int offset) {
+        super(TYPE_SHORT, size, 1, offset);
+        data = new short[1][];
+        data[0] = dataArray;
+    }
+
+    /**
+     * Instantiates a new data buffer of type short with a single underlying
+     * array of data starting at index 0.
+     * 
+     * @param dataArray
+     *            the data array to copy the data from.
+     * @param size
+     *            the length (number of elements) to use.
+     */
+    public DataBufferShort(short dataArray[], int size) {
+        super(TYPE_SHORT, size);
+        data = new short[1][];
+        data[0] = dataArray;
+    }
+
+    /**
+     * Instantiates a new data buffer of type short with offsets equal to zero.
+     * 
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     * @param numBanks
+     *            the number of data arrays to create.
+     */
+    public DataBufferShort(int size, int numBanks) {
+        super(TYPE_SHORT, size, numBanks);
+        data = new short[numBanks][];
+        int i = 0;
+        while (i < numBanks) {
+            data[i++] = new short[size];
+        }
+    }
+
+    /**
+     * Instantiates a new empty data buffer of type short with a single
+     * underlying array of data starting at index 0.
+     * 
+     * @param size
+     *            the length (number of elements) to use.
+     */
+    public DataBufferShort(int size) {
+        super(TYPE_SHORT, size);
+        data = new short[1][];
+        data[0] = new short[size];
+    }
+
+    @Override
+    public void setElem(int bank, int i, int val) {
+        data[bank][offsets[bank] + i] = (short)val;
+        notifyChanged();
+    }
+
+    @Override
+    public void setElem(int i, int val) {
+        data[0][offset + i] = (short)val;
+        notifyChanged();
+    }
+
+    @Override
+    public int getElem(int bank, int i) {
+        return (data[bank][offsets[bank] + i]);
+    }
+
+    /**
+     * Gets the data of the specified internal data array.
+     * 
+     * @param bank
+     *            the index of the desired data array.
+     * @return the data.
+     */
+    public short[] getData(int bank) {
+        notifyTaken();
+        return data[bank];
+    }
+
+    @Override
+    public int getElem(int i) {
+        return (data[0][offset + i]);
+    }
+
+    /**
+     * Gets the bank data.
+     * 
+     * @return the bank data.
+     */
+    public short[][] getBankData() {
+        notifyTaken();
+        return data.clone();
+    }
+
+    /**
+     * Gets the data of the first data array.
+     * 
+     * @return the data.
+     */
+    public short[] getData() {
+        notifyTaken();
+        return data[0];
+    }
+}
diff --git a/awt/java/awt/image/DataBufferUShort.java b/awt/java/awt/image/DataBufferUShort.java
new file mode 100644
index 0000000..58d9d83
--- /dev/null
+++ b/awt/java/awt/image/DataBufferUShort.java
@@ -0,0 +1,195 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class DataBufferUShort is the subclass of DataBuffer for the case where
+ * the underlying data is unsigned short.
+ * 
+ * @since Android 1.0
+ */
+public final class DataBufferUShort extends DataBuffer {
+
+    /**
+     * The data.
+     */
+    short data[][];
+
+    /**
+     * Instantiates a new data buffer of type unsigned short.
+     * 
+     * @param dataArrays
+     *            the data arrays to copy the data from.
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     * @param offsets
+     *            the starting indices for reading the data from the internal
+     *            data arrays.
+     */
+    public DataBufferUShort(short dataArrays[][], int size, int offsets[]) {
+        super(TYPE_USHORT, size, dataArrays.length, offsets);
+        for (int i = 0; i < dataArrays.length; i++) {
+            if (dataArrays[i].length < offsets[i] + size) {
+                // awt.28d=Length of dataArray[{0}] is less than size +
+                // offset[{1}]
+                throw new IllegalArgumentException(Messages.getString("awt.28D", i, i)); //$NON-NLS-1$
+            }
+        }
+        data = dataArrays.clone();
+    }
+
+    /**
+     * Instantiates a new data buffer of type unsigned short.
+     * 
+     * @param dataArrays
+     *            the data arrays to copy the data from.
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     */
+    public DataBufferUShort(short dataArrays[][], int size) {
+        super(TYPE_USHORT, size, dataArrays.length);
+        data = dataArrays.clone();
+    }
+
+    /**
+     * Instantiates a new data buffer of type unsigned short with a single
+     * underlying array of data.
+     * 
+     * @param dataArray
+     *            the data array to copy the data from.
+     * @param size
+     *            the length (number of elements) to use.
+     * @param offset
+     *            the starting index to use when reading the data.
+     */
+    public DataBufferUShort(short dataArray[], int size, int offset) {
+        super(TYPE_USHORT, size, 1, offset);
+        if (dataArray.length < size + offset) {
+            // awt.28E=Length of dataArray is less than size + offset
+            throw new IllegalArgumentException(Messages.getString("awt.28E")); //$NON-NLS-1$
+        }
+        data = new short[1][];
+        data[0] = dataArray;
+    }
+
+    /**
+     * Instantiates a new data buffer of type unsigned short with a single
+     * underlying array of data starting at index 0.
+     * 
+     * @param dataArray
+     *            the data array to copy the data from.
+     * @param size
+     *            the length (number of elements) to use.
+     */
+    public DataBufferUShort(short dataArray[], int size) {
+        super(TYPE_USHORT, size);
+        data = new short[1][];
+        data[0] = dataArray;
+    }
+
+    /**
+     * Instantiates a new empty data buffer of type unsigned short with offsets
+     * equal to zero.
+     * 
+     * @param size
+     *            the length (number of elements) to use from the data arrays.
+     * @param numBanks
+     *            the number of data arrays to create.
+     */
+    public DataBufferUShort(int size, int numBanks) {
+        super(TYPE_USHORT, size, numBanks);
+        data = new short[numBanks][];
+        int i = 0;
+        while (i < numBanks) {
+            data[i++] = new short[size];
+        }
+    }
+
+    /**
+     * Instantiates a new empty data buffer of type unsigned short with a single
+     * underlying array of data starting at index 0.
+     * 
+     * @param size
+     *            the length (number of elements) to use.
+     */
+    public DataBufferUShort(int size) {
+        super(TYPE_USHORT, size);
+        data = new short[1][];
+        data[0] = new short[size];
+    }
+
+    @Override
+    public void setElem(int bank, int i, int val) {
+        data[bank][offsets[bank] + i] = (short)val;
+        notifyChanged();
+    }
+
+    @Override
+    public void setElem(int i, int val) {
+        data[0][offset + i] = (short)val;
+        notifyChanged();
+    }
+
+    @Override
+    public int getElem(int bank, int i) {
+        return (data[bank][offsets[bank] + i]) & 0xffff;
+    }
+
+    /**
+     * Gets the data of the specified internal data array.
+     * 
+     * @param bank
+     *            the index of the desired data array.
+     * @return the data.
+     */
+    public short[] getData(int bank) {
+        notifyTaken();
+        return data[bank];
+    }
+
+    @Override
+    public int getElem(int i) {
+        return (data[0][offset + i]) & 0xffff;
+    }
+
+    /**
+     * Gets the bank data.
+     * 
+     * @return the bank data.
+     */
+    public short[][] getBankData() {
+        notifyTaken();
+        return data.clone();
+    }
+
+    /**
+     * Gets the data of the first data array.
+     * 
+     * @return the data.
+     */
+    public short[] getData() {
+        notifyTaken();
+        return data[0];
+    }
+}
diff --git a/awt/java/awt/image/DirectColorModel.java b/awt/java/awt/image/DirectColorModel.java
new file mode 100644
index 0000000..700eb7a
--- /dev/null
+++ b/awt/java/awt/image/DirectColorModel.java
@@ -0,0 +1,889 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.color.ColorSpace;
+import java.awt.Transparency;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class DirectColorModel represents a standard (packed) RGB color model
+ * with additional support for converting between sRGB color space and 8 or 16
+ * bit linear RGB color space using lookup tables.
+ * 
+ * @since Android 1.0
+ */
+public class DirectColorModel extends PackedColorModel {
+
+    /**
+     * The from_ linea r_ rg b_ lut.
+     */
+    private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from
+
+    // Linear RGB Color Space into sRGB
+
+    /**
+     * The to_ linea r_8 rg b_ lut.
+     */
+    private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from
+
+    // sRGB Color Space into Linear RGB
+    // 8 bit
+
+    /**
+     * The to_ linea r_16 rg b_ lut.
+     */
+    private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from
+
+    // sRGB Color Space into Linear RGB
+    // 16 bit
+
+    /**
+     * The alpha lut.
+     */
+    private byte alphaLUT[]; // Lookup table for scale alpha value
+
+    /**
+     * The color lu ts.
+     */
+    private byte colorLUTs[][]; // Lookup tables for scale color values
+
+    /**
+     * The is_s rgb.
+     */
+    private boolean is_sRGB; // ColorModel has sRGB ColorSpace
+
+    /**
+     * The is_ linea r_ rgb.
+     */
+    private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color
+
+    // Space
+
+    /**
+     * The LINEA r_ rg b_ length.
+     */
+    private int LINEAR_RGB_Length; // Linear RGB bit length
+
+    /**
+     * The factor.
+     */
+    private float fFactor; // Scale factor
+
+    /**
+     * Instantiates a new direct color model.
+     * 
+     * @param space
+     *            the color space.
+     * @param bits
+     *            the array of component masks.
+     * @param rmask
+     *            the bitmask corresponding to the red band.
+     * @param gmask
+     *            the bitmask corresponding to the green band.
+     * @param bmask
+     *            the bitmask corresponding to the blue band.
+     * @param amask
+     *            the bitmask corresponding to the alpha band.
+     * @param isAlphaPremultiplied
+     *            whether the alpha is pre-multiplied in this color model.
+     * @param transferType
+     *            the transfer type (primitive java type to use for the
+     *            components).
+     * @throws IllegalArgumentException
+     *             if the number of bits in the combined bitmasks for the color
+     *             bands is less than one or greater than 32.
+     */
+    public DirectColorModel(ColorSpace space, int bits, int rmask, int gmask, int bmask, int amask,
+            boolean isAlphaPremultiplied, int transferType) {
+
+        super(space, bits, rmask, gmask, bmask, amask, isAlphaPremultiplied,
+                (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT), transferType);
+
+        initLUTs();
+    }
+
+    /**
+     * Instantiates a new direct color model, determining the transfer type from
+     * the bits array, the transparency from the alpha mask, and the default
+     * color space {@link ColorSpace#CS_sRGB}.
+     * 
+     * @param bits
+     *            the array of component masks.
+     * @param rmask
+     *            the bitmask corresponding to the red band.
+     * @param gmask
+     *            the bitmask corresponding to the green band.
+     * @param bmask
+     *            the bitmask corresponding to the blue band.
+     * @param amask
+     *            the bitmask corresponding to the alpha band.
+     */
+    public DirectColorModel(int bits, int rmask, int gmask, int bmask, int amask) {
+
+        super(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, rmask, gmask, bmask, amask, false,
+                (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT), ColorModel
+                        .getTransferType(bits));
+
+        initLUTs();
+    }
+
+    /**
+     * Instantiates a new direct color model with no alpha channel, determining
+     * the transfer type from the bits array, the default color space
+     * {@link ColorSpace#CS_sRGB}, and with the transparency set to
+     * {@link Transparency#OPAQUE}.
+     * 
+     * @param bits
+     *            the array of component masks.
+     * @param rmask
+     *            the bitmask corresponding to the red band.
+     * @param gmask
+     *            the bitmask corresponding to the green band.
+     * @param bmask
+     *            the bitmask corresponding to the blue band.
+     */
+    public DirectColorModel(int bits, int rmask, int gmask, int bmask) {
+        this(bits, rmask, gmask, bmask, 0);
+    }
+
+    @Override
+    public Object getDataElements(int components[], int offset, Object obj) {
+        int pixel = 0;
+        for (int i = 0; i < numComponents; i++) {
+            pixel |= (components[offset + i] << offsets[i]) & componentMasks[i];
+        }
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[];
+                if (obj == null) {
+                    ba = new byte[1];
+                } else {
+                    ba = (byte[])obj;
+                }
+                ba[0] = (byte)pixel;
+                obj = ba;
+                break;
+
+            case DataBuffer.TYPE_USHORT:
+                short sa[];
+                if (obj == null) {
+                    sa = new short[1];
+                } else {
+                    sa = (short[])obj;
+                }
+                sa[0] = (short)pixel;
+                obj = sa;
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int ia[];
+                if (obj == null) {
+                    ia = new int[1];
+                } else {
+                    ia = (int[])obj;
+                }
+                ia[0] = pixel;
+                obj = ia;
+                break;
+
+            default:
+                // awt.214=This Color Model doesn't support this transferType
+                throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+        }
+
+        return obj;
+    }
+
+    @Override
+    public Object getDataElements(int rgb, Object pixel) {
+        if (equals(ColorModel.getRGBdefault())) {
+            int ia[];
+            if (pixel == null) {
+                ia = new int[1];
+            } else {
+                ia = (int[])pixel;
+            }
+            ia[0] = rgb;
+            return ia;
+        }
+
+        int alpha = (rgb >> 24) & 0xff;
+        int red = (rgb >> 16) & 0xff;
+        int green = (rgb >> 8) & 0xff;
+        int blue = rgb & 0xff;
+
+        float comp[] = new float[numColorComponents];
+        float normComp[] = null;
+
+        if (is_sRGB || is_LINEAR_RGB) {
+            if (is_LINEAR_RGB) {
+                if (LINEAR_RGB_Length == 8) {
+                    red = to_LINEAR_8RGB_LUT[red] & 0xff;
+                    green = to_LINEAR_8RGB_LUT[green] & 0xff;
+                    blue = to_LINEAR_8RGB_LUT[blue] & 0xff;
+                } else {
+                    red = to_LINEAR_16RGB_LUT[red] & 0xffff;
+                    green = to_LINEAR_16RGB_LUT[green] & 0xffff;
+                    blue = to_LINEAR_16RGB_LUT[blue] & 0xffff;
+                }
+            }
+            comp[0] = red / fFactor;
+            comp[1] = green / fFactor;
+            comp[2] = blue / fFactor;
+            if (!hasAlpha) {
+                normComp = comp;
+            } else {
+                float normAlpha = alpha / 255.0f;
+                normComp = new float[numComponents];
+                for (int i = 0; i < numColorComponents; i++) {
+                    normComp[i] = comp[i];
+                }
+                normComp[numColorComponents] = normAlpha;
+            }
+        } else {
+            comp[0] = red / fFactor;
+            comp[1] = green / fFactor;
+            comp[2] = blue / fFactor;
+            float rgbComp[] = cs.fromRGB(comp);
+            if (!hasAlpha) {
+                normComp = rgbComp;
+            } else {
+                float normAlpha = alpha / 255.0f;
+                normComp = new float[numComponents];
+                for (int i = 0; i < numColorComponents; i++) {
+                    normComp[i] = rgbComp[i];
+                }
+                normComp[numColorComponents] = normAlpha;
+            }
+        }
+
+        int pxl = 0;
+        if (hasAlpha) {
+            float normAlpha = normComp[numColorComponents];
+            alpha = (int)(normAlpha * maxValues[numColorComponents] + 0.5f);
+            if (isAlphaPremultiplied) {
+                red = (int)(normComp[0] * normAlpha * maxValues[0] + 0.5f);
+                green = (int)(normComp[1] * normAlpha * maxValues[1] + 0.5f);
+                blue = (int)(normComp[2] * normAlpha * maxValues[2] + 0.5f);
+            } else {
+                red = (int)(normComp[0] * maxValues[0] + 0.5f);
+                green = (int)(normComp[1] * maxValues[1] + 0.5f);
+                blue = (int)(normComp[2] * maxValues[2] + 0.5f);
+            }
+            pxl = (alpha << offsets[3]) & componentMasks[3];
+        } else {
+            red = (int)(normComp[0] * maxValues[0] + 0.5f);
+            green = (int)(normComp[1] * maxValues[1] + 0.5f);
+            blue = (int)(normComp[2] * maxValues[2] + 0.5f);
+        }
+
+        pxl |= ((red << offsets[0]) & componentMasks[0])
+                | ((green << offsets[1]) & componentMasks[1])
+                | ((blue << offsets[2]) & componentMasks[2]);
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[];
+                if (pixel == null) {
+                    ba = new byte[1];
+                } else {
+                    ba = (byte[])pixel;
+                }
+                ba[0] = (byte)pxl;
+                return ba;
+
+            case DataBuffer.TYPE_USHORT:
+                short sa[];
+                if (pixel == null) {
+                    sa = new short[1];
+                } else {
+                    sa = (short[])pixel;
+                }
+                sa[0] = (short)pxl;
+                return sa;
+
+            case DataBuffer.TYPE_INT:
+                int ia[];
+                if (pixel == null) {
+                    ia = new int[1];
+                } else {
+                    ia = (int[])pixel;
+                }
+                ia[0] = pxl;
+                return ia;
+
+            default:
+                // awt.214=This Color Model doesn't support this transferType
+                throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+        }
+    }
+
+    @Override
+    public final ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) {
+
+        if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) {
+            return this;
+        }
+
+        int minX = raster.getMinX();
+        int minY = raster.getMinY();
+        int w = raster.getWidth();
+        int h = raster.getHeight();
+
+        int components[] = null;
+        int transparentComponents[] = new int[numComponents];
+
+        float alphaFactor = maxValues[numColorComponents];
+
+        if (isAlphaPremultiplied) {
+            switch (transferType) {
+                case DataBuffer.TYPE_BYTE:
+                case DataBuffer.TYPE_USHORT:
+                case DataBuffer.TYPE_INT:
+                    for (int i = 0; i < h; i++, minY++) {
+                        for (int j = 0, x = minX; j < w; j++, x++) {
+                            components = raster.getPixel(x, minY, components);
+                            if (components[numColorComponents] == 0) {
+                                raster.setPixel(x, minY, transparentComponents);
+                            } else {
+                                float alpha = components[numColorComponents] / alphaFactor;
+                                for (int n = 0; n < numColorComponents; n++) {
+                                    components[n] = (int)(alpha * components[n] + 0.5f);
+                                }
+                                raster.setPixel(x, minY, components);
+                            }
+                        }
+
+                    }
+                    break;
+
+                default:
+                    // awt.214=This Color Model doesn't support this
+                    // transferType
+                    throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+            }
+        } else {
+            switch (transferType) {
+                case DataBuffer.TYPE_BYTE:
+                case DataBuffer.TYPE_USHORT:
+                case DataBuffer.TYPE_INT:
+                    for (int i = 0; i < h; i++, minY++) {
+                        for (int j = 0, x = minX; j < w; j++, x++) {
+                            components = raster.getPixel(x, minY, components);
+                            if (components[numColorComponents] != 0) {
+                                float alpha = alphaFactor / components[numColorComponents];
+                                for (int n = 0; n < numColorComponents; n++) {
+                                    components[n] = (int)(alpha * components[n] + 0.5f);
+                                }
+                                raster.setPixel(x, minY, components);
+                            }
+                        }
+
+                    }
+                    break;
+
+                default:
+                    // awt.214=This Color Model doesn't support this
+                    // transferType
+                    throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+            }
+
+        }
+
+        return new DirectColorModel(cs, pixel_bits, componentMasks[0], componentMasks[1],
+                componentMasks[2], componentMasks[3], isAlphaPremultiplied, transferType);
+    }
+
+    @Override
+    public String toString() {
+        // The output format based on 1.5 release behaviour.
+        // It could be reveled such way:
+        // BufferedImage bi = new BufferedImage(1, 1,
+        // BufferedImage.TYPE_INT_ARGB);
+        // ColorModel cm = bi.getColorModel();
+        // System.out.println(cm.toString());
+        String str = "DirectColorModel:" + " rmask = " + //$NON-NLS-1$ //$NON-NLS-2$
+                Integer.toHexString(componentMasks[0]) + " gmask = " + //$NON-NLS-1$
+                Integer.toHexString(componentMasks[1]) + " bmask = " + //$NON-NLS-1$
+                Integer.toHexString(componentMasks[2]) + " amask = " + //$NON-NLS-1$
+                (!hasAlpha ? "0" : Integer.toHexString(componentMasks[3])); //$NON-NLS-1$
+
+        return str;
+    }
+
+    @Override
+    public final int[] getComponents(Object pixel, int components[], int offset) {
+
+        if (components == null) {
+            components = new int[numComponents + offset];
+        }
+
+        int intPixel = 0;
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[] = (byte[])pixel;
+                intPixel = ba[0] & 0xff;
+                break;
+
+            case DataBuffer.TYPE_USHORT:
+                short sa[] = (short[])pixel;
+                intPixel = sa[0] & 0xffff;
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int ia[] = (int[])pixel;
+                intPixel = ia[0];
+                break;
+
+            default:
+                // awt.22D=This transferType ( {0} ) is not supported by this
+                // color model
+                throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$
+                        transferType));
+        }
+
+        return getComponents(intPixel, components, offset);
+    }
+
+    @Override
+    public int getRed(Object inData) {
+        int pixel = 0;
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[] = (byte[])inData;
+                pixel = ba[0] & 0xff;
+                break;
+
+            case DataBuffer.TYPE_USHORT:
+                short sa[] = (short[])inData;
+                pixel = sa[0] & 0xffff;
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int ia[] = (int[])inData;
+                pixel = ia[0];
+                break;
+
+            default:
+                // awt.214=This Color Model doesn't support this transferType
+                throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+        }
+        return getRed(pixel);
+    }
+
+    @Override
+    public int getRGB(Object inData) {
+        int pixel = 0;
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[] = (byte[])inData;
+                pixel = ba[0] & 0xff;
+                break;
+
+            case DataBuffer.TYPE_USHORT:
+                short sa[] = (short[])inData;
+                pixel = sa[0] & 0xffff;
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int ia[] = (int[])inData;
+                pixel = ia[0];
+                break;
+
+            default:
+                // awt.214=This Color Model doesn't support this transferType
+                throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+        }
+        return getRGB(pixel);
+    }
+
+    @Override
+    public int getGreen(Object inData) {
+        int pixel = 0;
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[] = (byte[])inData;
+                pixel = ba[0] & 0xff;
+                break;
+
+            case DataBuffer.TYPE_USHORT:
+                short sa[] = (short[])inData;
+                pixel = sa[0] & 0xffff;
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int ia[] = (int[])inData;
+                pixel = ia[0];
+                break;
+
+            default:
+                // awt.214=This Color Model doesn't support this transferType
+                throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+        }
+        return getGreen(pixel);
+    }
+
+    @Override
+    public int getBlue(Object inData) {
+        int pixel = 0;
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[] = (byte[])inData;
+                pixel = ba[0] & 0xff;
+                break;
+
+            case DataBuffer.TYPE_USHORT:
+                short sa[] = (short[])inData;
+                pixel = sa[0] & 0xffff;
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int ia[] = (int[])inData;
+                pixel = ia[0];
+                break;
+
+            default:
+                // awt.214=This Color Model doesn't support this transferType
+                throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+        }
+        return getBlue(pixel);
+    }
+
+    @Override
+    public int getAlpha(Object inData) {
+        int pixel = 0;
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[] = (byte[])inData;
+                pixel = ba[0] & 0xff;
+                break;
+
+            case DataBuffer.TYPE_USHORT:
+                short sa[] = (short[])inData;
+                pixel = sa[0] & 0xffff;
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int ia[] = (int[])inData;
+                pixel = ia[0];
+                break;
+
+            default:
+                // awt.214=This Color Model doesn't support this transferType
+                throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+        }
+        return getAlpha(pixel);
+    }
+
+    @Override
+    public final WritableRaster createCompatibleWritableRaster(int w, int h) {
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        int bandMasks[] = componentMasks.clone();
+
+        if (pixel_bits > 16) {
+            return Raster.createPackedRaster(DataBuffer.TYPE_INT, w, h, bandMasks, null);
+        } else if (pixel_bits > 8) {
+            return Raster.createPackedRaster(DataBuffer.TYPE_USHORT, w, h, bandMasks, null);
+        } else {
+            return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, bandMasks, null);
+        }
+    }
+
+    @Override
+    public boolean isCompatibleRaster(Raster raster) {
+        SampleModel sm = raster.getSampleModel();
+        if (!(sm instanceof SinglePixelPackedSampleModel)) {
+            return false;
+        }
+
+        SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel)sm;
+
+        if (sppsm.getNumBands() != numComponents) {
+            return false;
+        }
+        if (raster.getTransferType() != transferType) {
+            return false;
+        }
+
+        int maskBands[] = sppsm.getBitMasks();
+        return Arrays.equals(maskBands, componentMasks);
+    }
+
+    @Override
+    public int getDataElement(int components[], int offset) {
+        int pixel = 0;
+        for (int i = 0; i < numComponents; i++) {
+            pixel |= (components[offset + i] << offsets[i]) & componentMasks[i];
+        }
+        return pixel;
+    }
+
+    @Override
+    public final int[] getComponents(int pixel, int components[], int offset) {
+        if (components == null) {
+            components = new int[numComponents + offset];
+        }
+        for (int i = 0; i < numComponents; i++) {
+            components[offset + i] = (pixel & componentMasks[i]) >> offsets[i];
+        }
+        return components;
+    }
+
+    @Override
+    public final int getRed(int pixel) {
+        if (is_sRGB) {
+            return getComponentFrom_sRGB(pixel, 0);
+        }
+        if (is_LINEAR_RGB) {
+            return getComponentFrom_LINEAR_RGB(pixel, 0);
+        }
+        return getComponentFrom_RGB(pixel, 0);
+    }
+
+    @Override
+    public final int getRGB(int pixel) {
+        return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | (getGreen(pixel) << 8)
+                | getBlue(pixel);
+    }
+
+    @Override
+    public final int getGreen(int pixel) {
+        if (is_sRGB) {
+            return getComponentFrom_sRGB(pixel, 1);
+        }
+        if (is_LINEAR_RGB) {
+            return getComponentFrom_LINEAR_RGB(pixel, 1);
+        }
+        return getComponentFrom_RGB(pixel, 1);
+    }
+
+    @Override
+    public final int getBlue(int pixel) {
+        if (is_sRGB) {
+            return getComponentFrom_sRGB(pixel, 2);
+        }
+        if (is_LINEAR_RGB) {
+            return getComponentFrom_LINEAR_RGB(pixel, 2);
+        }
+        return getComponentFrom_RGB(pixel, 2);
+    }
+
+    @Override
+    public final int getAlpha(int pixel) {
+        if (!hasAlpha) {
+            return 255;
+        }
+        int a = (pixel & componentMasks[3]) >>> offsets[3];
+        if (bits[3] == 8) {
+            return a;
+        }
+        return alphaLUT[a] & 0xff;
+    }
+
+    /**
+     * Gets the red mask.
+     * 
+     * @return the red mask.
+     */
+    public final int getRedMask() {
+        return componentMasks[0];
+    }
+
+    /**
+     * Gets the green mask.
+     * 
+     * @return the green mask.
+     */
+    public final int getGreenMask() {
+        return componentMasks[1];
+    }
+
+    /**
+     * Gets the blue mask.
+     * 
+     * @return the blue mask.
+     */
+    public final int getBlueMask() {
+        return componentMasks[2];
+    }
+
+    /**
+     * Gets the alpha mask.
+     * 
+     * @return the alpha mask.
+     */
+    public final int getAlphaMask() {
+        if (hasAlpha) {
+            return componentMasks[3];
+        }
+        return 0;
+    }
+
+    /**
+     * Initialization of Lookup tables.
+     */
+    private void initLUTs() {
+        is_sRGB = cs.isCS_sRGB();
+        is_LINEAR_RGB = (cs == LUTColorConverter.LINEAR_RGB_CS);
+
+        if (is_LINEAR_RGB) {
+            if (maxBitLength > 8) {
+                LINEAR_RGB_Length = 16;
+                from_LINEAR_RGB_LUT = LUTColorConverter.getFrom16lRGBtosRGB_LUT();
+                to_LINEAR_16RGB_LUT = LUTColorConverter.getFromsRGBto16lRGB_LUT();
+            } else {
+                LINEAR_RGB_Length = 8;
+                from_LINEAR_RGB_LUT = LUTColorConverter.getFrom8lRGBtosRGB_LUT();
+                to_LINEAR_8RGB_LUT = LUTColorConverter.getFromsRGBto8lRGB_LUT();
+            }
+            fFactor = ((1 << LINEAR_RGB_Length) - 1);
+        } else {
+            fFactor = 255.0f;
+        }
+
+        if (hasAlpha && bits[3] != 8) {
+            alphaLUT = new byte[maxValues[3] + 1];
+            for (int i = 0; i <= maxValues[3]; i++) {
+                alphaLUT[i] = (byte)(scales[3] * i + 0.5f);
+            }
+
+        }
+
+        if (!isAlphaPremultiplied) {
+            colorLUTs = new byte[3][];
+
+            if (is_sRGB) {
+                for (int i = 0; i < numColorComponents; i++) {
+                    if (bits[i] != 8) {
+                        for (int j = 0; j < i; j++) {
+                            if (bits[i] == bits[j]) {
+                                colorLUTs[i] = colorLUTs[j];
+                                break;
+                            }
+                        }
+                        colorLUTs[i] = new byte[maxValues[i] + 1];
+                        for (int j = 0; j <= maxValues[i]; j++) {
+                            colorLUTs[i][j] = (byte)(scales[i] * j + 0.5f);
+                        }
+                    }
+                }
+            }
+
+            if (is_LINEAR_RGB) {
+                for (int i = 0; i < numColorComponents; i++) {
+                    if (bits[i] != LINEAR_RGB_Length) {
+                        for (int j = 0; j < i; j++) {
+                            if (bits[i] == bits[j]) {
+                                colorLUTs[i] = colorLUTs[j];
+                                break;
+                            }
+                        }
+                        colorLUTs[i] = new byte[maxValues[i] + 1];
+                        for (int j = 0; j <= maxValues[0]; j++) {
+                            int idx;
+                            if (LINEAR_RGB_Length == 8) {
+                                idx = (int)(scales[i] * j + 0.5f);
+                            } else {
+                                idx = (int)(scales[i] * j * 257.0f + 0.5f);
+                            }
+                            colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx];
+                        }
+                    }
+                }
+            }
+
+        }
+    }
+
+    /**
+     * This method return RGB component value if Color Model has sRGB
+     * ColorSpace.
+     * 
+     * @param pixel
+     *            the integer representation of the pixel.
+     * @param idx
+     *            the index of the pixel component.
+     * @return the value of the pixel component scaled from 0 to 255.
+     */
+    private int getComponentFrom_sRGB(int pixel, int idx) {
+        int comp = (pixel & componentMasks[idx]) >> offsets[idx];
+        if (isAlphaPremultiplied) {
+            int alpha = (pixel & componentMasks[3]) >>> offsets[3];
+            comp = alpha == 0 ? 0 : (int)(scales[idx] * comp * 255.0f / (scales[3] * alpha) + 0.5f);
+        } else if (bits[idx] != 8) {
+            comp = colorLUTs[idx][comp] & 0xff;
+        }
+        return comp;
+    }
+
+    /**
+     * This method return RGB component value if Color Model has Linear RGB
+     * ColorSpace.
+     * 
+     * @param pixel
+     *            the integer representation of the pixel.
+     * @param idx
+     *            the index of the pixel component.
+     * @return the value of the pixel component scaled from 0 to 255.
+     */
+    private int getComponentFrom_LINEAR_RGB(int pixel, int idx) {
+        int comp = (pixel & componentMasks[idx]) >> offsets[idx];
+        if (isAlphaPremultiplied) {
+            float factor = ((1 << LINEAR_RGB_Length) - 1);
+            int alpha = (pixel & componentMasks[3]) >> offsets[3];
+            comp = alpha == 0 ? 0 : (int)(scales[idx] * comp * factor / (scales[3] * alpha) + 0.5f);
+        } else if (bits[idx] != LINEAR_RGB_Length) {
+            comp = colorLUTs[idx][comp] & 0xff;
+        } else {
+            comp = from_LINEAR_RGB_LUT[comp] & 0xff;
+        }
+        return comp;
+    }
+
+    /**
+     * This method return RGB component value if Color Model has arbitrary RGB
+     * ColorSapce.
+     * 
+     * @param pixel
+     *            the integer representation of the pixel.
+     * @param idx
+     *            the index of the pixel component.
+     * @return the value of the pixel component scaled from 0 to 255.
+     */
+    private int getComponentFrom_RGB(int pixel, int idx) {
+        int components[] = getComponents(pixel, null, 0);
+        float[] normComponents = getNormalizedComponents(components, 0, null, 0);
+        float[] sRGBcomponents = cs.toRGB(normComponents);
+        return (int)(sRGBcomponents[idx] * 255.0f + 0.5f);
+    }
+
+}
diff --git a/awt/java/awt/image/FilteredImageSource.java b/awt/java/awt/image/FilteredImageSource.java
new file mode 100644
index 0000000..ed8558d
--- /dev/null
+++ b/awt/java/awt/image/FilteredImageSource.java
@@ -0,0 +1,98 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.util.Hashtable;
+
+/**
+ * The FilteredImageSource class is used for producing image data for a new
+ * filtered version of the original image using the specified filter object.
+ * 
+ * @since Android 1.0
+ */
+public class FilteredImageSource implements ImageProducer {
+
+    /**
+     * The source.
+     */
+    private final ImageProducer source;
+
+    /**
+     * The filter.
+     */
+    private final ImageFilter filter;
+
+    /**
+     * The cons table.
+     */
+    private final Hashtable<ImageConsumer, ImageConsumer> consTable = new Hashtable<ImageConsumer, ImageConsumer>();
+
+    /**
+     * Instantiates a new FilteredImageSource object with the specified
+     * ImageProducer and the ImageFilter objects.
+     * 
+     * @param orig
+     *            the specified ImageProducer.
+     * @param imgf
+     *            the specified ImageFilter.
+     */
+    public FilteredImageSource(ImageProducer orig, ImageFilter imgf) {
+        source = orig;
+        filter = imgf;
+    }
+
+    public synchronized boolean isConsumer(ImageConsumer ic) {
+        if (ic != null) {
+            return consTable.containsKey(ic);
+        }
+        return false;
+    }
+
+    public void startProduction(ImageConsumer ic) {
+        addConsumer(ic);
+        ImageConsumer fic = consTable.get(ic);
+        source.startProduction(fic);
+    }
+
+    public void requestTopDownLeftRightResend(ImageConsumer ic) {
+        if (ic != null && isConsumer(ic)) {
+            ImageFilter fic = (ImageFilter)consTable.get(ic);
+            fic.resendTopDownLeftRight(source);
+        }
+    }
+
+    public synchronized void removeConsumer(ImageConsumer ic) {
+        if (ic != null && isConsumer(ic)) {
+            ImageConsumer fic = consTable.get(ic);
+            source.removeConsumer(fic);
+            consTable.remove(ic);
+        }
+    }
+
+    public synchronized void addConsumer(ImageConsumer ic) {
+        if (ic != null && !isConsumer(ic)) {
+            ImageConsumer fic = filter.getFilterInstance(ic);
+            source.addConsumer(fic);
+            consTable.put(ic, fic);
+        }
+    }
+}
diff --git a/awt/java/awt/image/ImageConsumer.java b/awt/java/awt/image/ImageConsumer.java
new file mode 100644
index 0000000..caf87d1
--- /dev/null
+++ b/awt/java/awt/image/ImageConsumer.java
@@ -0,0 +1,185 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.util.Hashtable;
+
+/**
+ * The ImageConsumer interface provides the data about the image and about how
+ * its data is delivered. A ImageProducer provides all of the information about
+ * the image using the methods defined in this interface.
+ * 
+ * @since Android 1.0
+ */
+public interface ImageConsumer {
+
+    /**
+     * The Constant RANDOMPIXELORDER indicates that the pixels are delivered in
+     * a random order.
+     */
+    public static final int RANDOMPIXELORDER = 1;
+
+    /**
+     * The Constant TOPDOWNLEFTRIGHT indicates that the pixels are delivered in
+     * top-down, left-to-right order.
+     */
+    public static final int TOPDOWNLEFTRIGHT = 2;
+
+    /**
+     * The Constant COMPLETESCANLINES indicates that the pixels are delivered in
+     * complete scanline.
+     */
+    public static final int COMPLETESCANLINES = 4;
+
+    /**
+     * The Constant SINGLEPASS indicates that pixels are delivered in a single
+     * pass.
+     */
+    public static final int SINGLEPASS = 8;
+
+    /**
+     * The Constant SINGLEFRAME indicates that image consists of single frame.
+     */
+    public static final int SINGLEFRAME = 16;
+
+    /**
+     * The Constant IMAGEERROR indicates an image error during image producing.
+     */
+    public static final int IMAGEERROR = 1;
+
+    /**
+     * The Constant SINGLEFRAMEDONE indicates that only one of the image's
+     * frames is completed.
+     */
+    public static final int SINGLEFRAMEDONE = 2;
+
+    /**
+     * The Constant STATICIMAGEDONE indicates that the image is completed.
+     */
+    public static final int STATICIMAGEDONE = 3;
+
+    /**
+     * The Constant IMAGEABORTED indicates that the image producing process is
+     * aborted.
+     */
+    public static final int IMAGEABORTED = 4;
+
+    /**
+     * Sets the properties for the image associated with this ImageConsumer.
+     * 
+     * @param props
+     *            the properties for the image associated with this
+     *            ImageConsumer.
+     */
+    public void setProperties(Hashtable<?, ?> props);
+
+    /**
+     * Sets the ColorModel object.
+     * 
+     * @param model
+     *            the new ColorModel.
+     */
+    public void setColorModel(ColorModel model);
+
+    /**
+     * Sets the pixels for the specified rectangular area of the image.
+     * 
+     * @param x
+     *            the X coordinate of rectangular area.
+     * @param y
+     *            the Y coordinate of rectangular area.
+     * @param w
+     *            the width of rectangular area.
+     * @param h
+     *            the height of rectangular area.
+     * @param model
+     *            the specified ColorModel to be used for pixels converting.
+     * @param pixels
+     *            the array of pixels.
+     * @param off
+     *            the offset of pixels array.
+     * @param scansize
+     *            the distance from the one row of pixels to the next row in the
+     *            specified array.
+     */
+    public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off,
+            int scansize);
+
+    /**
+     * Sets the pixels for the specified rectangular area of the image.
+     * 
+     * @param x
+     *            the X coordinate of rectangular area.
+     * @param y
+     *            the Y coordinate of rectangular area.
+     * @param w
+     *            the width of rectangular area.
+     * @param h
+     *            the height of rectangular area.
+     * @param model
+     *            the specified ColorModel to be used for pixels converting.
+     * @param pixels
+     *            the array of pixels.
+     * @param off
+     *            the offset of pixels array.
+     * @param scansize
+     *            the distance from the one row of pixels to the next row in the
+     *            specified array.
+     */
+    public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off,
+            int scansize);
+
+    /**
+     * Sets the dimensions of a source image.
+     * 
+     * @param width
+     *            the width of the image.
+     * @param height
+     *            the height of the image.
+     */
+    public void setDimensions(int width, int height);
+
+    /**
+     * Sets the hint flags of pixels order, which is used by the ImageConsumer
+     * for obtaining pixels from the ImageProducer for which this ImageConsumer
+     * is added.
+     * 
+     * @param hintflags
+     *            the mask of hint flags.
+     */
+    public void setHints(int hintflags);
+
+    /**
+     * THis method is called in the one of the following cases:
+     * <ul>
+     * <li>The ImageProducer (for which this ImageConsumer is added) has been
+     * delivered all pixels of the source image.</li>
+     * <li>A one frame of an animation has been completed.</li>
+     * <li>An error while loading or producing of the image has occurred.
+     * </ul>
+     * 
+     * @param status
+     *            the status of image producing.
+     */
+    public void imageComplete(int status);
+
+}
diff --git a/awt/java/awt/image/ImageFilter.java b/awt/java/awt/image/ImageFilter.java
new file mode 100644
index 0000000..d2c9f50
--- /dev/null
+++ b/awt/java/awt/image/ImageFilter.java
@@ -0,0 +1,134 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.util.Hashtable;
+
+/**
+ * The ImageFilter class provides a filter for delivering image data from an
+ * ImageProducer to an ImageConsumer.
+ * 
+ * @since Android 1.0
+ */
+public class ImageFilter implements ImageConsumer, Cloneable {
+
+    /**
+     * The consumer.
+     */
+    protected ImageConsumer consumer;
+
+    /**
+     * Instantiates a new ImageFilter.
+     */
+    public ImageFilter() {
+        super();
+    }
+
+    /**
+     * Gets an instance of an ImageFilter object which performs the filtering
+     * for the specified ImageConsumer.
+     * 
+     * @param ic
+     *            the specified ImageConsumer.
+     * @return an ImageFilter used to perform the filtering for the specified
+     *         ImageConsumer.
+     */
+    public ImageFilter getFilterInstance(ImageConsumer ic) {
+        ImageFilter filter = (ImageFilter)clone();
+        filter.consumer = ic;
+        return filter;
+    }
+
+    @SuppressWarnings("unchecked")
+    public void setProperties(Hashtable<?, ?> props) {
+        Hashtable<Object, Object> fprops;
+        if (props == null) {
+            fprops = new Hashtable<Object, Object>();
+        } else {
+            fprops = (Hashtable<Object, Object>)props.clone();
+        }
+        String propName = "Filters"; //$NON-NLS-1$
+        String prop = "Null filter"; //$NON-NLS-1$
+        Object o = fprops.get(propName);
+        if (o != null) {
+            if (o instanceof String) {
+                prop = (String)o + "; " + prop; //$NON-NLS-1$
+            } else {
+                prop = o.toString() + "; " + prop; //$NON-NLS-1$
+            }
+        }
+        fprops.put(propName, prop);
+        consumer.setProperties(fprops);
+    }
+
+    /**
+     * Returns a copy of this ImageFilter.
+     * 
+     * @return a copy of this ImageFilter.
+     */
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Responds to a request for a Top-Down-Left-Right ordered resend of the
+     * pixel data from an ImageConsumer.
+     * 
+     * @param ip
+     *            the ImageProducer that provides this instance of the filter.
+     */
+    public void resendTopDownLeftRight(ImageProducer ip) {
+        ip.requestTopDownLeftRightResend(this);
+    }
+
+    public void setColorModel(ColorModel model) {
+        consumer.setColorModel(model);
+    }
+
+    public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off,
+            int scansize) {
+        consumer.setPixels(x, y, w, h, model, pixels, off, scansize);
+    }
+
+    public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off,
+            int scansize) {
+        consumer.setPixels(x, y, w, h, model, pixels, off, scansize);
+    }
+
+    public void setDimensions(int width, int height) {
+        consumer.setDimensions(width, height);
+    }
+
+    public void setHints(int hints) {
+        consumer.setHints(hints);
+    }
+
+    public void imageComplete(int status) {
+        consumer.imageComplete(status);
+    }
+
+}
diff --git a/awt/java/awt/image/ImageObserver.java b/awt/java/awt/image/ImageObserver.java
new file mode 100644
index 0000000..21ec41b
--- /dev/null
+++ b/awt/java/awt/image/ImageObserver.java
@@ -0,0 +1,101 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.Image;
+
+/**
+ * the ImageObserver interface is an asynchronous update interface for receiving
+ * notifications about Image construction status.
+ * 
+ * @since Android 1.0
+ */
+public interface ImageObserver {
+
+    /**
+     * The Constant WIDTH indicates that the width of the image is available.
+     */
+    public static final int WIDTH = 1;
+
+    /**
+     * The Constant HEIGHT indicates that the width of the image is available.
+     */
+    public static final int HEIGHT = 2;
+
+    /**
+     * The Constant PROPERTIES indicates that the properties of the image are
+     * available.
+     */
+    public static final int PROPERTIES = 4;
+
+    /**
+     * The Constant SOMEBITS indicates that more bits needed for drawing a
+     * scaled variation of the image pixels are available.
+     */
+    public static final int SOMEBITS = 8;
+
+    /**
+     * The Constant FRAMEBITS indicates that complete frame of a image which was
+     * previously drawn is now available for drawing again.
+     */
+    public static final int FRAMEBITS = 16;
+
+    /**
+     * The Constant ALLBITS indicates that an image which was previously drawn
+     * is now complete and can be drawn again.
+     */
+    public static final int ALLBITS = 32;
+
+    /**
+     * The Constant ERROR indicates that error occurred.
+     */
+    public static final int ERROR = 64;
+
+    /**
+     * The Constant ABORT indicates that the image producing is aborted.
+     */
+    public static final int ABORT = 128;
+
+    /**
+     * This method is called when information about an Image interface becomes
+     * available. This method returns true if further updates are needed, false
+     * if not.
+     * 
+     * @param img
+     *            the image to be observed.
+     * @param infoflags
+     *            the bitwise OR combination of information flags: ABORT,
+     *            ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS,
+     *            WIDTH.
+     * @param x
+     *            the X coordinate.
+     * @param y
+     *            the Y coordinate.
+     * @param width
+     *            the width.
+     * @param height
+     *            the height.
+     * @return true if further updates are needed, false if not.
+     */
+    public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height);
+
+}
diff --git a/awt/java/awt/image/ImageProducer.java b/awt/java/awt/image/ImageProducer.java
new file mode 100644
index 0000000..9138be2
--- /dev/null
+++ b/awt/java/awt/image/ImageProducer.java
@@ -0,0 +1,79 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+/**
+ * The ImageProducer provides an interface for objects which produce the image
+ * data. ImageProducer is used for reconstructing the image. Each image contains
+ * an ImageProducer.
+ * 
+ * @since Android 1.0
+ */
+public interface ImageProducer {
+
+    /**
+     * Checks if the specified ImageConsumer is registered with this
+     * ImageProvider or not.
+     * 
+     * @param ic
+     *            the ImageConsumer to be checked.
+     * @return true, if the specified ImageConsumer is registered with this
+     *         ImageProvider, false otherwise.
+     */
+    public boolean isConsumer(ImageConsumer ic);
+
+    /**
+     * Starts a reconstruction of the image data which will be delivered to this
+     * consumer. This method adds the specified ImageConsumer before
+     * reconstructing the image.
+     * 
+     * @param ic
+     *            the specified ImageConsumer.
+     */
+    public void startProduction(ImageConsumer ic);
+
+    /**
+     * Requests the ImageProducer to resend the image data in
+     * ImageConsumer.TOPDOWNLEFTRIGHT order.
+     * 
+     * @param ic
+     *            the specified ImageConsumer.
+     */
+    public void requestTopDownLeftRightResend(ImageConsumer ic);
+
+    /**
+     * Deregisters the specified ImageConsumer.
+     * 
+     * @param ic
+     *            the specified ImageConsumer.
+     */
+    public void removeConsumer(ImageConsumer ic);
+
+    /**
+     * Adds the specified ImageConsumer object to this ImageProducer.
+     * 
+     * @param ic
+     *            the specified ImageConsumer.
+     */
+    public void addConsumer(ImageConsumer ic);
+
+}
diff --git a/awt/java/awt/image/ImagingOpException.java b/awt/java/awt/image/ImagingOpException.java
new file mode 100644
index 0000000..e0c0127
--- /dev/null
+++ b/awt/java/awt/image/ImagingOpException.java
@@ -0,0 +1,49 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 5, 2005
+ */
+
+package java.awt.image;
+
+/**
+ * The ImagingOpException class provides error notification when the
+ * BufferedImageOp or RasterOp filter methods can not perform the desired filter
+ * operation.
+ * 
+ * @since Android 1.0
+ */
+public class ImagingOpException extends RuntimeException {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 8026288481846276658L;
+
+    /**
+     * Instantiates a new ImagingOpException with a detail message.
+     * 
+     * @param s
+     *            the detail message.
+     */
+    public ImagingOpException(String s) {
+        super(s);
+    }
+}
diff --git a/awt/java/awt/image/IndexColorModel.java b/awt/java/awt/image/IndexColorModel.java
new file mode 100644
index 0000000..0b06acd
--- /dev/null
+++ b/awt/java/awt/image/IndexColorModel.java
@@ -0,0 +1,1080 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.math.BigInteger;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class IndexColorModel represents a color model in which the color values
+ * of the pixels are read from a palette.
+ * 
+ * @since Android 1.0
+ */
+public class IndexColorModel extends ColorModel {
+
+    /**
+     * The color map.
+     */
+    private int colorMap[]; // Color Map
+
+    /**
+     * The map size.
+     */
+    private int mapSize; // Color Map size
+
+    /**
+     * The transparent index.
+     */
+    private int transparentIndex; // Index of fully transparent pixel
+
+    /**
+     * The gray palette.
+     */
+    private boolean grayPalette; // Color Model has Color Map with Gray Pallete
+
+    /**
+     * The valid bits.
+     */
+    private BigInteger validBits; // Specify valid Color Map values
+
+    /**
+     * The Constant CACHESIZE.
+     */
+    private static final int CACHESIZE = 20; // Cache size. Cache used for
+
+    // improving performace of selection
+    // nearest color in Color Map
+
+    /**
+     * The cachetable.
+     */
+    private final int cachetable[] = new int[CACHESIZE * 2]; // Cache table -
+
+    // used for
+
+    // storing RGB values and that appropriate indices
+    // in the Color Map
+
+    /**
+     * The next insert idx.
+     */
+    private int nextInsertIdx = 0; // Next index for insertion into Cache table
+
+    /**
+     * The total inserted.
+     */
+    private int totalInserted = 0; // Number of inserted values into Cache table
+
+    /**
+     * Instantiates a new index color model.
+     * 
+     * @param bits
+     *            the array of component masks.
+     * @param size
+     *            the size of the color map.
+     * @param cmap
+     *            the array that gives the color mapping.
+     * @param start
+     *            the start index of the color mapping data within the cmap
+     *            array.
+     * @param transferType
+     *            the transfer type (primitive java type to use for the
+     *            components).
+     * @param validBits
+     *            a list of which bits represent valid colormap values, or null
+     *            if all are valid.
+     * @throws IllegalArgumentException
+     *             if the size of the color map is less than one.
+     */
+    public IndexColorModel(int bits, int size, int cmap[], int start, int transferType,
+            BigInteger validBits) {
+
+        super(bits, IndexColorModel.createBits(true), ColorSpace.getInstance(ColorSpace.CS_sRGB),
+                true, false, Transparency.OPAQUE, validateTransferType(transferType));
+
+        if (size < 1) {
+            // awt.264=Size of the color map is less than 1
+            throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
+        }
+
+        mapSize = size;
+        colorMap = new int[mapSize];
+        transparentIndex = -1;
+
+        if (validBits != null) {
+            for (int i = 0; i < mapSize; i++) {
+                if (!validBits.testBit(i)) {
+                    this.validBits = validBits;
+                }
+                break;
+            }
+        }
+
+        transparency = Transparency.OPAQUE;
+        int alphaMask = 0xff000000;
+        int alpha = 0;
+
+        for (int i = 0; i < mapSize; i++, start++) {
+            colorMap[i] = cmap[start];
+            alpha = cmap[start] & alphaMask;
+
+            if (alpha == alphaMask) {
+                continue;
+            }
+            if (alpha == 0) {
+                if (transparentIndex < 0) {
+                    transparentIndex = i;
+                }
+                if (transparency == Transparency.OPAQUE) {
+                    transparency = Transparency.BITMASK;
+                }
+            } else if (alpha != alphaMask && transparency != Transparency.TRANSLUCENT) {
+                transparency = Transparency.TRANSLUCENT;
+            }
+
+        }
+        checkPalette();
+
+    }
+
+    /**
+     * Instantiates a new index color model.
+     * 
+     * @param bits
+     *            the array of component masks.
+     * @param size
+     *            the size of the color map.
+     * @param cmap
+     *            the array that gives the color mapping.
+     * @param start
+     *            the start index of the color mapping data within the cmap
+     *            array.
+     * @param hasalpha
+     *            whether this color model uses alpha.
+     * @param trans
+     *            the transparency supported, @see java.awt.Transparency.
+     * @param transferType
+     *            the transfer type (primitive java type to use for the
+     *            components).
+     * @throws IllegalArgumentException
+     *             if the size of the color map is less than one.
+     */
+    public IndexColorModel(int bits, int size, int cmap[], int start, boolean hasalpha, int trans,
+            int transferType) {
+
+        super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), ColorSpace
+                .getInstance(ColorSpace.CS_sRGB), (hasalpha || (trans >= 0)), false,
+                Transparency.OPAQUE, validateTransferType(transferType));
+
+        if (size < 1) {
+            // awt.264=Size of the color map is less than 1
+            throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
+        }
+
+        mapSize = size;
+        colorMap = new int[mapSize];
+        if (trans >= 0 && trans < mapSize) {
+            transparentIndex = trans;
+            transparency = Transparency.BITMASK;
+        } else {
+            transparentIndex = -1;
+            transparency = Transparency.OPAQUE;
+        }
+
+        int alphaMask = 0xff000000;
+        int alpha = 0;
+
+        for (int i = 0; i < mapSize; i++, start++) {
+            if (transparentIndex == i) {
+                colorMap[i] = cmap[start] & 0x00ffffff;
+                continue;
+            }
+            if (hasalpha) {
+                alpha = cmap[start] & alphaMask;
+                colorMap[i] = cmap[start];
+
+                if (alpha == alphaMask) {
+                    continue;
+                }
+                if (alpha == 0) {
+                    if (trans < 0) {
+                        trans = i;
+                    }
+                    if (transparency == Transparency.OPAQUE) {
+                        transparency = Transparency.BITMASK;
+                    }
+                } else if (alpha != 0 && transparency != Transparency.TRANSLUCENT) {
+                    transparency = Transparency.TRANSLUCENT;
+                }
+            } else {
+                colorMap[i] = alphaMask | cmap[start];
+            }
+        }
+        checkPalette();
+
+    }
+
+    /**
+     * Instantiates a new index color model by building the color map from
+     * arrays of red, green, blue, and alpha values.
+     * 
+     * @param bits
+     *            the array of component masks.
+     * @param size
+     *            the size of the color map.
+     * @param r
+     *            the array giving the red components of the entries in the
+     *            color map.
+     * @param g
+     *            the array giving the green components of the entries in the
+     *            color map.
+     * @param b
+     *            the array giving the blue components of the entries in the
+     *            color map.
+     * @param a
+     *            the array giving the alpha components of the entries in the
+     *            color map.
+     * @throws IllegalArgumentException
+     *             if the size of the color map is less than one.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if the size of one of the component arrays is less than the
+     *             size of the color map.
+     */
+    public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], byte a[]) {
+
+        super(bits, IndexColorModel.createBits(true), ColorSpace.getInstance(ColorSpace.CS_sRGB),
+                true, false, Transparency.OPAQUE, validateTransferType(ColorModel
+                        .getTransferType(bits)));
+
+        createColorMap(size, r, g, b, a, -1);
+        checkPalette();
+    }
+
+    /**
+     * Instantiates a new index color model by building the color map from
+     * arrays of red, green, and blue values.
+     * 
+     * @param bits
+     *            the array of component masks.
+     * @param size
+     *            the size of the color map.
+     * @param r
+     *            the array giving the red components of the entries in the
+     *            color map.
+     * @param g
+     *            the array giving the green components of the entries in the
+     *            color map.
+     * @param b
+     *            the array giving the blue components of the entries in the
+     *            color map.
+     * @param trans
+     *            the transparency supported, @see java.awt.Transparency.
+     * @throws IllegalArgumentException
+     *             if the size of the color map is less than one.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if the size of one of the component arrays is less than the
+     *             size of the color map.
+     */
+    public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], int trans) {
+
+        super(bits, IndexColorModel.createBits((trans >= 0)), ColorSpace
+                .getInstance(ColorSpace.CS_sRGB), (trans >= 0), false, Transparency.OPAQUE,
+                validateTransferType(ColorModel.getTransferType(bits)));
+
+        createColorMap(size, r, g, b, null, trans);
+        checkPalette();
+    }
+
+    /**
+     * Instantiates a new index color model by building the color map from
+     * arrays of red, green, and blue values.
+     * 
+     * @param bits
+     *            the array of component masks.
+     * @param size
+     *            the size of the color map.
+     * @param r
+     *            the array giving the red components of the entries in the
+     *            color map.
+     * @param g
+     *            the array giving the green components of the entries in the
+     *            color map.
+     * @param b
+     *            the array giving the blue components of the entries in the
+     *            color map.
+     * @throws IllegalArgumentException
+     *             if the size of the color map is less than one.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if the size of one of the component arrays is less than the
+     *             size of the color map.
+     */
+    public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[]) {
+        super(bits, IndexColorModel.createBits(false), ColorSpace.getInstance(ColorSpace.CS_sRGB),
+                false, false, Transparency.OPAQUE, validateTransferType(ColorModel
+                        .getTransferType(bits)));
+
+        createColorMap(size, r, g, b, null, -1);
+        checkPalette();
+    }
+
+    /**
+     * Instantiates a new index color model.
+     * 
+     * @param bits
+     *            the array of component masks.
+     * @param size
+     *            the size of the color map.
+     * @param cmap
+     *            the array that gives the color mapping.
+     * @param start
+     *            the start index of the color mapping data within the cmap
+     *            array.
+     * @param hasalpha
+     *            whether this color model uses alpha.
+     * @param trans
+     *            the transparency supported, @see java.awt.Transparency.
+     * @throws IllegalArgumentException
+     *             if the size of the color map is less than one.
+     */
+    public IndexColorModel(int bits, int size, byte cmap[], int start, boolean hasalpha, int trans) {
+
+        super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), ColorSpace
+                .getInstance(ColorSpace.CS_sRGB), (hasalpha || (trans >= 0)), false,
+                Transparency.OPAQUE, validateTransferType(ColorModel.getTransferType(bits)));
+
+        if (size < 1) {
+            // awt.264=Size of the color map is less than 1
+            throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
+        }
+
+        mapSize = size;
+        colorMap = new int[mapSize];
+        transparentIndex = -1;
+
+        transparency = Transparency.OPAQUE;
+        int alpha = 0xff000000;
+
+        for (int i = 0; i < mapSize; i++) {
+            colorMap[i] = (cmap[start++] & 0xff) << 16 | (cmap[start++] & 0xff) << 8
+                    | (cmap[start++] & 0xff);
+            if (trans == i) {
+                if (transparency == Transparency.OPAQUE) {
+                    transparency = Transparency.BITMASK;
+                }
+                if (hasalpha) {
+                    start++;
+                }
+                continue;
+            }
+            if (hasalpha) {
+                alpha = cmap[start++] & 0xff;
+                if (alpha == 0) {
+                    if (transparency == Transparency.OPAQUE) {
+                        transparency = Transparency.BITMASK;
+                        if (trans < 0) {
+                            trans = i;
+                        }
+                    }
+                } else {
+                    if (alpha != 0xff && transparency != Transparency.TRANSLUCENT) {
+                        transparency = Transparency.TRANSLUCENT;
+                    }
+                }
+                alpha <<= 24;
+            }
+            colorMap[i] |= alpha;
+        }
+
+        if (trans >= 0 && trans < mapSize) {
+            transparentIndex = trans;
+        }
+        checkPalette();
+
+    }
+
+    /**
+     * Instantiates a new index color model.
+     * 
+     * @param bits
+     *            the array of component masks.
+     * @param size
+     *            the size of the color map.
+     * @param cmap
+     *            the array that gives the color mapping.
+     * @param start
+     *            the start index of the color mapping data within the cmap
+     *            array.
+     * @param hasalpha
+     *            whether this color model uses alpha.
+     * @throws IllegalArgumentException
+     *             if the size of the color map is less than one.
+     */
+    public IndexColorModel(int bits, int size, byte cmap[], int start, boolean hasalpha) {
+
+        this(bits, size, cmap, start, hasalpha, -1);
+    }
+
+    @Override
+    public Object getDataElements(int[] components, int offset, Object pixel) {
+        int rgb = (components[offset] << 16) | (components[offset + 1]) << 8
+                | components[offset + 2];
+        if (hasAlpha) {
+            rgb |= components[offset + 3] << 24;
+        } else {
+            rgb |= 0xff000000;
+        }
+        return getDataElements(rgb, pixel);
+    }
+
+    @Override
+    public synchronized Object getDataElements(int rgb, Object pixel) {
+        int red = (rgb >> 16) & 0xff;
+        int green = (rgb >> 8) & 0xff;
+        int blue = rgb & 0xff;
+        int alpha = rgb >>> 24;
+        int pixIdx = 0;
+
+        for (int i = 0; i < totalInserted; i++) {
+            int idx = i * 2;
+            if (rgb == cachetable[idx]) {
+                return createDataObject(cachetable[idx + 1], pixel);
+            }
+        }
+
+        if (!hasAlpha && grayPalette) {
+            int grey = (red * 77 + green * 150 + blue * 29 + 128) >>> 8;
+            int minError = 255;
+            int error = 0;
+
+            for (int i = 0; i < mapSize; i++) {
+                error = Math.abs((colorMap[i] & 0xff) - grey);
+                if (error < minError) {
+                    pixIdx = i;
+                    if (error == 0) {
+                        break;
+                    }
+                    minError = error;
+                }
+            }
+        } else if (alpha == 0 && transparentIndex > -1) {
+            pixIdx = transparentIndex;
+        } else {
+            int minAlphaError = 255;
+            int minError = 195075; // 255^2 + 255^2 + 255^2
+            int alphaError;
+            int error = 0;
+
+            for (int i = 0; i < mapSize; i++) {
+                int pix = colorMap[i];
+                if (rgb == pix) {
+                    pixIdx = i;
+                    break;
+                }
+                alphaError = Math.abs(alpha - (pix >>> 24));
+                if (alphaError <= minAlphaError) {
+                    minAlphaError = alphaError;
+
+                    int buf = ((pix >> 16) & 0xff) - red;
+                    error = buf * buf;
+
+                    if (error < minError) {
+                        buf = ((pix >> 8) & 0xff) - green;
+                        error += buf * buf;
+
+                        if (error < minError) {
+                            buf = (pix & 0xff) - blue;
+                            error += buf * buf;
+
+                            if (error < minError) {
+                                pixIdx = i;
+                                minError = error;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        cachetable[nextInsertIdx] = rgb;
+        cachetable[nextInsertIdx + 1] = pixIdx;
+
+        nextInsertIdx = (nextInsertIdx + 2) % (CACHESIZE * 2);
+        if (totalInserted < CACHESIZE) {
+            totalInserted++;
+        }
+
+        return createDataObject(pixIdx, pixel);
+    }
+
+    /**
+     * Converts an image from indexed to RGB format.
+     * 
+     * @param raster
+     *            the raster containing the source image.
+     * @param forceARGB
+     *            whether to use the default RGB color model.
+     * @return the buffered image.
+     * @throws IllegalArgumentException
+     *             if the raster is not compatible with this color model.
+     */
+    public BufferedImage convertToIntDiscrete(Raster raster, boolean forceARGB) {
+
+        if (!isCompatibleRaster(raster)) {
+            // awt.265=The raster argument is not compatible with this
+            // IndexColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.265")); //$NON-NLS-1$
+        }
+
+        ColorModel model;
+        if (forceARGB || transparency == Transparency.TRANSLUCENT) {
+            model = ColorModel.getRGBdefault();
+        } else if (transparency == Transparency.BITMASK) {
+            model = new DirectColorModel(25, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x01000000);
+        } else {
+            model = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff);
+        }
+
+        int w = raster.getWidth();
+        int h = raster.getHeight();
+
+        WritableRaster distRaster = model.createCompatibleWritableRaster(w, h);
+
+        int minX = raster.getMinX();
+        int minY = raster.getMinY();
+
+        Object obj = null;
+        int pixels[] = null;
+
+        for (int i = 0; i < h; i++, minY++) {
+            obj = raster.getDataElements(minX, minY, w, 1, obj);
+            if (obj instanceof byte[]) {
+                byte ba[] = (byte[])obj;
+                if (pixels == null) {
+                    pixels = new int[ba.length];
+                }
+                for (int j = 0; j < ba.length; j++) {
+                    pixels[j] = colorMap[ba[j] & 0xff];
+                }
+            } else if (obj instanceof short[]) {
+                short sa[] = (short[])obj;
+                if (pixels == null) {
+                    pixels = new int[sa.length];
+                }
+                for (int j = 0; j < sa.length; j++) {
+                    pixels[j] = colorMap[sa[j] & 0xffff];
+                }
+            }
+            if (obj instanceof int[]) {
+                int ia[] = (int[])obj;
+                if (pixels == null) {
+                    pixels = new int[ia.length];
+                }
+                for (int j = 0; j < ia.length; j++) {
+                    pixels[j] = colorMap[ia[j]];
+                }
+            }
+
+            distRaster.setDataElements(0, i, w, 1, pixels);
+        }
+
+        return new BufferedImage(model, distRaster, false, null);
+    }
+
+    /**
+     * Gets the valid pixels.
+     * 
+     * @return the valid pixels.
+     */
+    public BigInteger getValidPixels() {
+        return validBits;
+    }
+
+    @Override
+    public String toString() {
+        // The output format based on 1.5 release behaviour.
+        // It could be reveled such way:
+        // BufferedImage bi = new BufferedImage(1, 1,
+        // BufferedImage.TYPE_BYTE_INDEXED);
+        // ColorModel cm = bi.getColorModel();
+        // System.out.println(cm.toString());
+        String str = "IndexColorModel: #pixel_bits = " + pixel_bits + //$NON-NLS-1$
+                " numComponents = " + numComponents + " color space = " + cs + //$NON-NLS-1$ //$NON-NLS-2$
+                " transparency = "; //$NON-NLS-1$
+
+        if (transparency == Transparency.OPAQUE) {
+            str = str + "Transparency.OPAQUE"; //$NON-NLS-1$
+        } else if (transparency == Transparency.BITMASK) {
+            str = str + "Transparency.BITMASK"; //$NON-NLS-1$
+        } else {
+            str = str + "Transparency.TRANSLUCENT"; //$NON-NLS-1$
+        }
+
+        str = str + " transIndex = " + transparentIndex + " has alpha = " + //$NON-NLS-1$ //$NON-NLS-2$
+                hasAlpha + " isAlphaPre = " + isAlphaPremultiplied; //$NON-NLS-1$
+
+        return str;
+    }
+
+    @Override
+    public int[] getComponents(Object pixel, int components[], int offset) {
+        int pixIdx = -1;
+        if (pixel instanceof byte[]) {
+            byte ba[] = (byte[])pixel;
+            pixIdx = ba[0] & 0xff;
+        } else if (pixel instanceof short[]) {
+            short sa[] = (short[])pixel;
+            pixIdx = sa[0] & 0xffff;
+        } else if (pixel instanceof int[]) {
+            int ia[] = (int[])pixel;
+            pixIdx = ia[0];
+        } else {
+            // awt.219=This transferType is not supported by this color model
+            throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$
+        }
+
+        return getComponents(pixIdx, components, offset);
+    }
+
+    @Override
+    public WritableRaster createCompatibleWritableRaster(int w, int h) {
+        WritableRaster raster;
+        if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
+            raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, 1, pixel_bits, null);
+        } else if (pixel_bits <= 8) {
+            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, 1, null);
+        } else if (pixel_bits <= 16) {
+            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, w, h, 1, null);
+        } else {
+            // awt.266=The number of bits in a pixel is greater than 16
+            throw new UnsupportedOperationException(Messages.getString("awt.266")); //$NON-NLS-1$
+        }
+
+        return raster;
+    }
+
+    @Override
+    public boolean isCompatibleSampleModel(SampleModel sm) {
+        if (sm == null) {
+            return false;
+        }
+
+        if (!(sm instanceof MultiPixelPackedSampleModel) && !(sm instanceof ComponentSampleModel)) {
+            return false;
+        }
+
+        if (sm.getTransferType() != transferType) {
+            return false;
+        }
+        if (sm.getNumBands() != 1) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+        if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
+            return new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, w, h, pixel_bits);
+        }
+        int bandOffsets[] = new int[1];
+        bandOffsets[0] = 0;
+        return new ComponentSampleModel(transferType, w, h, 1, w, bandOffsets);
+
+    }
+
+    @Override
+    public boolean isCompatibleRaster(Raster raster) {
+        int sampleSize = raster.getSampleModel().getSampleSize(0);
+        return (raster.getTransferType() == transferType && raster.getNumBands() == 1 && (1 << sampleSize) >= mapSize);
+    }
+
+    @Override
+    public int getDataElement(int components[], int offset) {
+        int rgb = (components[offset] << 16) | (components[offset + 1]) << 8
+                | components[offset + 2];
+
+        if (hasAlpha) {
+            rgb |= components[offset + 3] << 24;
+        } else {
+            rgb |= 0xff000000;
+        }
+
+        int pixel;
+
+        switch (transferType) {
+            case DataBuffer.TYPE_BYTE:
+                byte ba[] = (byte[])getDataElements(rgb, null);
+                pixel = ba[0] & 0xff;
+                break;
+            case DataBuffer.TYPE_USHORT:
+                short sa[] = (short[])getDataElements(rgb, null);
+                pixel = sa[0] & 0xffff;
+                break;
+            default:
+                // awt.267=The transferType is invalid
+                throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$
+        }
+
+        return pixel;
+    }
+
+    /**
+     * Gets the color map.
+     * 
+     * @param rgb
+     *            the destination array where the color map is written.
+     */
+    public final void getRGBs(int rgb[]) {
+        System.arraycopy(colorMap, 0, rgb, 0, mapSize);
+    }
+
+    /**
+     * Gets the red component of the color map.
+     * 
+     * @param r
+     *            the destination array.
+     */
+    public final void getReds(byte r[]) {
+        for (int i = 0; i < mapSize; i++) {
+            r[i] = (byte)(colorMap[i] >> 16);
+        }
+    }
+
+    /**
+     * Gets the green component of the color map.
+     * 
+     * @param g
+     *            the destination array.
+     */
+    public final void getGreens(byte g[]) {
+        for (int i = 0; i < mapSize; i++) {
+            g[i] = (byte)(colorMap[i] >> 8);
+        }
+    }
+
+    /**
+     * Gets the blue component of the color map.
+     * 
+     * @param b
+     *            the destination array.
+     */
+    public final void getBlues(byte b[]) {
+        for (int i = 0; i < mapSize; i++) {
+            b[i] = (byte)colorMap[i];
+        }
+    }
+
+    /**
+     * Gets the alpha component of the color map.
+     * 
+     * @param a
+     *            the destination array.
+     */
+    public final void getAlphas(byte a[]) {
+        for (int i = 0; i < mapSize; i++) {
+            a[i] = (byte)(colorMap[i] >> 24);
+        }
+    }
+
+    @Override
+    public int[] getComponents(int pixel, int components[], int offset) {
+        if (components == null) {
+            components = new int[offset + numComponents];
+        }
+
+        components[offset + 0] = getRed(pixel);
+        components[offset + 1] = getGreen(pixel);
+        components[offset + 2] = getBlue(pixel);
+        if (hasAlpha && (components.length - offset) > 3) {
+            components[offset + 3] = getAlpha(pixel);
+        }
+
+        return components;
+    }
+
+    /**
+     * Checks if the specified pixel is valid for this color model.
+     * 
+     * @param pixel
+     *            the pixel.
+     * @return true, if the pixel is valid.
+     */
+    public boolean isValid(int pixel) {
+        if (validBits == null) {
+            return (pixel >= 0 && pixel < mapSize);
+        }
+        return (pixel < mapSize && validBits.testBit(pixel));
+    }
+
+    @Override
+    public final int getRed(int pixel) {
+        return (colorMap[pixel] >> 16) & 0xff;
+    }
+
+    @Override
+    public final int getRGB(int pixel) {
+        return colorMap[pixel];
+    }
+
+    @Override
+    public final int getGreen(int pixel) {
+        return (colorMap[pixel] >> 8) & 0xff;
+    }
+
+    @Override
+    public final int getBlue(int pixel) {
+        return colorMap[pixel] & 0xff;
+    }
+
+    @Override
+    public final int getAlpha(int pixel) {
+        return (colorMap[pixel] >> 24) & 0xff;
+    }
+
+    @Override
+    public int[] getComponentSize() {
+        return bits.clone();
+    }
+
+    /**
+     * Checks if this color model validates pixels.
+     * 
+     * @return true, if all pixels are valid, otherwise false.
+     */
+    public boolean isValid() {
+        return (validBits == null);
+    }
+
+    @Override
+    public void finalize() {
+        // TODO: implement
+        return;
+    }
+
+    /**
+     * Gets the index that represents the transparent pixel.
+     * 
+     * @return the index that represents the transparent pixel.
+     */
+    public final int getTransparentPixel() {
+        return transparentIndex;
+    }
+
+    @Override
+    public int getTransparency() {
+        return transparency;
+    }
+
+    /**
+     * Gets the size of the color map.
+     * 
+     * @return the map size.
+     */
+    public final int getMapSize() {
+        return mapSize;
+    }
+
+    /**
+     * Creates the color map.
+     * 
+     * @param size
+     *            the size.
+     * @param r
+     *            the r.
+     * @param g
+     *            the g.
+     * @param b
+     *            the b.
+     * @param a
+     *            the a.
+     * @param trans
+     *            the trans.
+     */
+    private void createColorMap(int size, byte r[], byte g[], byte b[], byte a[], int trans) {
+        if (size < 1) {
+            // awt.264=Size of the color map is less than 1
+            throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
+        }
+
+        mapSize = size;
+        colorMap = new int[mapSize];
+        if (trans >= 0 && trans < mapSize) {
+            transparency = Transparency.BITMASK;
+            transparentIndex = trans;
+        } else {
+            transparency = Transparency.OPAQUE;
+            transparentIndex = -1;
+        }
+        int alpha = 0;
+
+        for (int i = 0; i < mapSize; i++) {
+            colorMap[i] = ((r[i] & 0xff) << 16) | ((g[i] & 0xff) << 8) | (b[i] & 0xff);
+
+            if (trans == i) {
+                continue;
+            }
+
+            if (a == null) {
+                colorMap[i] |= 0xff000000;
+            } else {
+                alpha = a[i] & 0xff;
+                if (alpha == 0xff) {
+                    colorMap[i] |= 0xff000000;
+                } else if (alpha == 0) {
+                    if (transparency == Transparency.OPAQUE) {
+                        transparency = Transparency.BITMASK;
+                    }
+                    if (transparentIndex < 0) {
+                        transparentIndex = i;
+                    }
+                } else {
+                    colorMap[i] |= (a[i] & 0xff) << 24;
+                    if (transparency != Transparency.TRANSLUCENT) {
+                        transparency = Transparency.TRANSLUCENT;
+                    }
+                }
+            }
+
+        }
+
+    }
+
+    /**
+     * This method checking, if Color Map has Gray palette.
+     */
+    private void checkPalette() {
+        grayPalette = false;
+        if (transparency > Transparency.OPAQUE) {
+            return;
+        }
+        int rgb = 0;
+
+        for (int i = 0; i < mapSize; i++) {
+            rgb = colorMap[i];
+            if (((rgb >> 16) & 0xff) != ((rgb >> 8) & 0xff) || ((rgb >> 8) & 0xff) != (rgb & 0xff)) {
+                return;
+            }
+        }
+        grayPalette = true;
+    }
+
+    /**
+     * Construction an array pixel representation.
+     * 
+     * @param colorMapIdx
+     *            the index into Color Map.
+     * @param pixel
+     *            the pixel
+     * @return the pixel representation array.
+     */
+    private Object createDataObject(int colorMapIdx, Object pixel) {
+        if (pixel == null) {
+            switch (transferType) {
+                case DataBuffer.TYPE_BYTE:
+                    byte[] ba = new byte[1];
+                    ba[0] = (byte)colorMapIdx;
+                    pixel = ba;
+                    break;
+                case DataBuffer.TYPE_USHORT:
+                    short[] sa = new short[1];
+                    sa[0] = (short)colorMapIdx;
+                    pixel = sa;
+                    break;
+                default:
+                    // awt.267=The transferType is invalid
+                    throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$
+            }
+        } else if (pixel instanceof byte[] && transferType == DataBuffer.TYPE_BYTE) {
+            byte ba[] = (byte[])pixel;
+            ba[0] = (byte)colorMapIdx;
+            pixel = ba;
+        } else if (pixel instanceof short[] && transferType == DataBuffer.TYPE_USHORT) {
+            short[] sa = (short[])pixel;
+            sa[0] = (short)colorMapIdx;
+            pixel = sa;
+        } else if (pixel instanceof int[]) {
+            int ia[] = (int[])pixel;
+            ia[0] = colorMapIdx;
+            pixel = ia;
+        } else {
+            // awt.268=The pixel is not a primitive array of type transferType
+            throw new ClassCastException(Messages.getString("awt.268")); //$NON-NLS-1$
+        }
+        return pixel;
+    }
+
+    /**
+     * Creates the bits.
+     * 
+     * @param hasAlpha
+     *            the has alpha.
+     * @return the int[].
+     */
+    private static int[] createBits(boolean hasAlpha) {
+
+        int numChannels;
+        if (hasAlpha) {
+            numChannels = 4;
+        } else {
+            numChannels = 3;
+        }
+
+        int bits[] = new int[numChannels];
+        for (int i = 0; i < numChannels; i++) {
+            bits[i] = 8;
+        }
+
+        return bits;
+
+    }
+
+    /**
+     * Validate transfer type.
+     * 
+     * @param transferType
+     *            the transfer type.
+     * @return the int.
+     */
+    private static int validateTransferType(int transferType) {
+        if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT) {
+            // awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or
+            // DataBuffer.TYPE_USHORT
+            throw new IllegalArgumentException(Messages.getString("awt.269")); //$NON-NLS-1$
+        }
+        return transferType;
+    }
+
+    /**
+     * Checks if is gray palette.
+     * 
+     * @return true, if is gray palette.
+     */
+    boolean isGrayPallete() {
+        return grayPalette;
+    }
+
+}
diff --git a/awt/java/awt/image/Kernel.java b/awt/java/awt/image/Kernel.java
new file mode 100644
index 0000000..a59d27a
--- /dev/null
+++ b/awt/java/awt/image/Kernel.java
@@ -0,0 +1,153 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Sep 28, 2005
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Kernel class provides a matrix. This matrix is stored as a float array
+ * which describes how a specified pixel affects the value calculated for the
+ * pixel's position in the output image of a filtering operation. The X, Y
+ * origins indicate the kernel matrix element which corresponds to the pixel
+ * position for which an output value is being calculated.
+ * 
+ * @since Android 1.0
+ */
+public class Kernel implements Cloneable {
+
+    /**
+     * The x origin.
+     */
+    private final int xOrigin;
+
+    /**
+     * The y origin.
+     */
+    private final int yOrigin;
+
+    /**
+     * The width.
+     */
+    private int width;
+
+    /**
+     * The height.
+     */
+    private int height;
+
+    /**
+     * The data.
+     */
+    float data[];
+
+    /**
+     * Instantiates a new Kernel with the specified float array. The
+     * width*height elements of the data array are copied.
+     * 
+     * @param width
+     *            the width of the Kernel.
+     * @param height
+     *            the height of the Kernel.
+     * @param data
+     *            the data of Kernel.
+     */
+    public Kernel(int width, int height, float[] data) {
+        int dataLength = width * height;
+        if (data.length < dataLength) {
+            // awt.22B=Length of data should not be less than width*height
+            throw new IllegalArgumentException(Messages.getString("awt.22B")); //$NON-NLS-1$
+        }
+
+        this.width = width;
+        this.height = height;
+
+        this.data = new float[dataLength];
+        System.arraycopy(data, 0, this.data, 0, dataLength);
+
+        xOrigin = (width - 1) / 2;
+        yOrigin = (height - 1) / 2;
+    }
+
+    /**
+     * Gets the width of this Kernel.
+     * 
+     * @return the width of this Kernel.
+     */
+    public final int getWidth() {
+        return width;
+    }
+
+    /**
+     * Gets the height of this Kernel.
+     * 
+     * @return the height of this Kernel.
+     */
+    public final int getHeight() {
+        return height;
+    }
+
+    /**
+     * Gets the float data array of this Kernel.
+     * 
+     * @param data
+     *            the float array where the resulted data will be stored.
+     * @return the float data array of this Kernel.
+     */
+    public final float[] getKernelData(float[] data) {
+        if (data == null) {
+            data = new float[this.data.length];
+        }
+        System.arraycopy(this.data, 0, data, 0, this.data.length);
+
+        return data;
+    }
+
+    /**
+     * Gets the X origin of this Kernel.
+     * 
+     * @return the X origin of this Kernel.
+     */
+    public final int getXOrigin() {
+        return xOrigin;
+    }
+
+    /**
+     * Gets the Y origin of this Kernel.
+     * 
+     * @return the Y origin of this Kernel.
+     */
+    public final int getYOrigin() {
+        return yOrigin;
+    }
+
+    /**
+     * Returns a copy of this Kernel object.
+     * 
+     * @return the copy of this Kernel object.
+     */
+    @Override
+    public Object clone() {
+        return new Kernel(width, height, data);
+    }
+}
diff --git a/awt/java/awt/image/LookupOp.java b/awt/java/awt/image/LookupOp.java
new file mode 100644
index 0000000..3362c5c
--- /dev/null
+++ b/awt/java/awt/image/LookupOp.java
@@ -0,0 +1,661 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 14, 2005
+ */
+
+package java.awt.image;
+
+import java.awt.*;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.Point2D;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The LookupOp class performs a lookup operation which transforms a source
+ * image by filtering each band using a table of data. The table may contain a
+ * single array or it may contain a different data array for each band of the
+ * image.
+ * 
+ * @since Android 1.0
+ */
+public class LookupOp implements BufferedImageOp, RasterOp {
+
+    /**
+     * The lut.
+     */
+    private final LookupTable lut;
+
+    /**
+     * The hints.
+     */
+    private RenderingHints hints;
+
+    // TODO remove when this field is used
+    /**
+     * The can use ipp.
+     */
+    @SuppressWarnings("unused")
+    private final boolean canUseIpp;
+
+    // We don't create levels/values when it is possible to reuse old
+    /**
+     * The cached levels.
+     */
+    private int cachedLevels[];
+
+    /**
+     * The cached values.
+     */
+    private int cachedValues[];
+
+    // Number of channels for which cache is valid.
+    // If negative number of channels is same as positive but skipAlpha was
+    // specified
+    /**
+     * The valid for channels.
+     */
+    private int validForChannels;
+
+    /**
+     * The level initializer.
+     */
+    static int levelInitializer[] = new int[0x10000];
+
+    static {
+        // TODO
+        // System.loadLibrary("imageops");
+
+        for (int i = 1; i <= 0x10000; i++) {
+            levelInitializer[i - 1] = i;
+        }
+    }
+
+    /**
+     * Instantiates a new LookupOp object from the specified LookupTable object
+     * and a RenderingHints object.
+     * 
+     * @param lookup
+     *            the specified LookupTable object.
+     * @param hints
+     *            the RenderingHints object or null.
+     */
+    public LookupOp(LookupTable lookup, RenderingHints hints) {
+        if (lookup == null) {
+            throw new NullPointerException(Messages.getString("awt.01", "lookup")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        lut = lookup;
+        this.hints = hints;
+        canUseIpp = lut instanceof ByteLookupTable || lut instanceof ShortLookupTable;
+    }
+
+    /**
+     * Gets the LookupTable of the specified Object.
+     * 
+     * @return the LookupTable of the specified Object.
+     */
+    public final LookupTable getTable() {
+        return lut;
+    }
+
+    public final RenderingHints getRenderingHints() {
+        return hints;
+    }
+
+    public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+        if (dstPt == null) {
+            dstPt = new Point2D.Float();
+        }
+
+        dstPt.setLocation(srcPt);
+        return dstPt;
+    }
+
+    public final Rectangle2D getBounds2D(Raster src) {
+        return src.getBounds();
+    }
+
+    public final Rectangle2D getBounds2D(BufferedImage src) {
+        return getBounds2D(src.getRaster());
+    }
+
+    public WritableRaster createCompatibleDestRaster(Raster src) {
+        return src.createCompatibleWritableRaster();
+    }
+
+    public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
+        if (dstCM == null) {
+            dstCM = src.getColorModel();
+
+            // Sync transfer type with LUT for component color model
+            if (dstCM instanceof ComponentColorModel) {
+                int transferType = dstCM.getTransferType();
+                if (lut instanceof ByteLookupTable) {
+                    transferType = DataBuffer.TYPE_BYTE;
+                } else if (lut instanceof ShortLookupTable) {
+                    transferType = DataBuffer.TYPE_SHORT;
+                }
+
+                dstCM = new ComponentColorModel(dstCM.cs, dstCM.hasAlpha(),
+                        dstCM.isAlphaPremultiplied, dstCM.transparency, transferType);
+            }
+        }
+
+        WritableRaster r = dstCM.isCompatibleSampleModel(src.getSampleModel()) ? src.getRaster()
+                .createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : dstCM
+                .createCompatibleWritableRaster(src.getWidth(), src.getHeight());
+
+        return new BufferedImage(dstCM, r, dstCM.isAlphaPremultiplied(), null);
+    }
+
+    public final WritableRaster filter(Raster src, WritableRaster dst) {
+        if (dst == null) {
+            dst = createCompatibleDestRaster(src);
+        } else {
+            if (src.getNumBands() != dst.getNumBands()) {
+                throw new IllegalArgumentException(Messages.getString("awt.237")); //$NON-NLS-1$            }
+            }
+            if (src.getWidth() != dst.getWidth()) {
+                throw new IllegalArgumentException(Messages.getString("awt.28F")); //$NON-NLS-1$            }
+            }
+            if (src.getHeight() != dst.getHeight()) {
+                throw new IllegalArgumentException(Messages.getString("awt.290")); //$NON-NLS-1$            }
+            }
+        }
+
+        if (lut.getNumComponents() != 1 && lut.getNumComponents() != src.getNumBands()) {
+            // awt.238=The number of arrays in the LookupTable does not meet the
+            // restrictions
+            throw new IllegalArgumentException(Messages.getString("awt.238")); //$NON-NLS-1$
+        }
+
+        // TODO
+        // if (!canUseIpp || ippFilter(src, dst, BufferedImage.TYPE_CUSTOM,
+        // false) != 0)
+        if (slowFilter(src, dst, false) != 0) {
+            // awt.21F=Unable to transform source
+            throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$
+        }
+
+        return dst;
+    }
+
+    public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+        ColorModel srcCM = src.getColorModel();
+
+        if (srcCM instanceof IndexColorModel) {
+            // awt.220=Source should not have IndexColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.220")); //$NON-NLS-1$
+        }
+
+        // Check if the number of scaling factors matches the number of bands
+        int nComponents = srcCM.getNumComponents();
+        int nLUTComponents = lut.getNumComponents();
+        boolean skipAlpha;
+        if (srcCM.hasAlpha()) {
+            if (nLUTComponents == 1 || nLUTComponents == nComponents - 1) {
+                skipAlpha = true;
+            } else if (nLUTComponents == nComponents) {
+                skipAlpha = false;
+            } else {
+                // awt.229=Number of components in the LUT does not match the
+                // number of bands
+                throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$
+            }
+        } else if (nLUTComponents == 1 || nLUTComponents == nComponents) {
+            skipAlpha = false;
+        } else {
+            // awt.229=Number of components in the LUT does not match the number
+            // of bands
+            throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$
+        }
+
+        BufferedImage finalDst = null;
+        if (dst == null) {
+            finalDst = dst;
+            dst = createCompatibleDestImage(src, null);
+        } else {
+            if (src.getWidth() != dst.getWidth()) {
+                throw new IllegalArgumentException(Messages.getString("awt.291")); //$NON-NLS-1$
+            }
+
+            if (src.getHeight() != dst.getHeight()) {
+                throw new IllegalArgumentException(Messages.getString("awt.292")); //$NON-NLS-1$
+            }
+
+            if (!srcCM.equals(dst.getColorModel())) {
+                // Treat BufferedImage.TYPE_INT_RGB and
+                // BufferedImage.TYPE_INT_ARGB as same
+                if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst
+                        .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) {
+                    finalDst = dst;
+                    dst = createCompatibleDestImage(src, null);
+                }
+            }
+        }
+
+        // TODO
+        // if (!canUseIpp || ippFilter(src.getRaster(), dst.getRaster(),
+        // src.getType(), skipAlpha) != 0)
+        if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) {
+            // awt.21F=Unable to transform source
+            throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$
+        }
+
+        if (finalDst != null) {
+            Graphics2D g = finalDst.createGraphics();
+            g.setComposite(AlphaComposite.Src);
+            g.drawImage(dst, 0, 0, null);
+        } else {
+            finalDst = dst;
+        }
+
+        return dst;
+    }
+
+    /**
+     * Slow filter.
+     * 
+     * @param src
+     *            the src.
+     * @param dst
+     *            the dst.
+     * @param skipAlpha
+     *            the skip alpha.
+     * @return the int.
+     */
+    private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) {
+        int minSrcX = src.getMinX();
+        int minDstX = dst.getMinX();
+        int minSrcY = src.getMinY();
+        int minDstY = dst.getMinY();
+
+        int skippingChannels = skipAlpha ? 1 : 0;
+        int numBands2Process = src.getNumBands() - skippingChannels;
+
+        int numBands = src.getNumBands();
+        int srcHeight = src.getHeight();
+        int srcWidth = src.getWidth();
+
+        int[] pixels = null;
+        int offset = lut.getOffset();
+
+        if (lut instanceof ByteLookupTable) {
+            byte[][] byteData = ((ByteLookupTable)lut).getTable();
+            pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels);
+
+            if (lut.getNumComponents() != 1) {
+                for (int i = 0; i < pixels.length; i += numBands) {
+                    for (int b = 0; b < numBands2Process; b++) {
+                        pixels[i + b] = byteData[b][pixels[i + b] - offset] & 0xFF;
+                    }
+                }
+            } else {
+                for (int i = 0; i < pixels.length; i += numBands) {
+                    for (int b = 0; b < numBands2Process; b++) {
+                        pixels[i + b] = byteData[0][pixels[i + b] - offset] & 0xFF;
+                    }
+                }
+            }
+
+            dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels);
+        } else if (lut instanceof ShortLookupTable) {
+            short[][] shortData = ((ShortLookupTable)lut).getTable();
+            pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels);
+
+            if (lut.getNumComponents() != 1) {
+                for (int i = 0; i < pixels.length; i += numBands) {
+                    for (int b = 0; b < numBands2Process; b++) {
+                        pixels[i + b] = shortData[b][pixels[i + b] - offset] & 0xFFFF;
+                    }
+                }
+            } else {
+                for (int i = 0; i < pixels.length; i += numBands) {
+                    for (int b = 0; b < numBands2Process; b++) {
+                        pixels[i + b] = shortData[0][pixels[i + b] - offset] & 0xFFFF;
+                    }
+                }
+            }
+
+            dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels);
+        } else {
+            int pixel[] = new int[src.getNumBands()];
+            int maxY = minSrcY + srcHeight;
+            int maxX = minSrcX + srcWidth;
+            for (int srcY = minSrcY, dstY = minDstY; srcY < maxY; srcY++, dstY++) {
+                for (int srcX = minSrcX, dstX = minDstX; srcX < maxX; srcX++, dstX++) {
+                    src.getPixel(srcX, srcY, pixel);
+                    lut.lookupPixel(pixel, pixel);
+                    dst.setPixel(dstX, dstY, pixel);
+                }
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     * Creates the byte levels.
+     * 
+     * @param channels
+     *            the channels.
+     * @param skipAlpha
+     *            the skip alpha.
+     * @param levels
+     *            the levels.
+     * @param values
+     *            the values.
+     * @param channelsOrder
+     *            the channels order.
+     */
+    private final void createByteLevels(int channels, boolean skipAlpha, int levels[],
+            int values[], int channelsOrder[]) {
+        byte data[][] = ((ByteLookupTable)lut).getTable();
+        int nLevels = data[0].length;
+        int offset = lut.getOffset();
+
+        // Use one data array for all channels or use several data arrays
+        int dataIncrement = data.length > 1 ? 1 : 0;
+
+        for (int ch = 0, dataIdx = 0; ch < channels; dataIdx += dataIncrement, ch++) {
+            int channelOffset = channelsOrder == null ? ch : channelsOrder[ch];
+            int channelBase = nLevels * channelOffset;
+
+            // Skip last channel if needed, zero values are OK -
+            // no changes to the channel information will be done in IPP
+            if ((channelOffset == channels - 1 && skipAlpha) || (dataIdx >= data.length)) {
+                continue;
+            }
+
+            System.arraycopy(levelInitializer, offset, levels, channelBase, nLevels);
+            for (int from = 0, to = channelBase; from < nLevels; from++, to++) {
+                values[to] = data[dataIdx][from] & 0xFF;
+            }
+        }
+    }
+
+    /**
+     * Creates the short levels.
+     * 
+     * @param channels
+     *            the channels.
+     * @param skipAlpha
+     *            the skip alpha.
+     * @param levels
+     *            the levels.
+     * @param values
+     *            the values.
+     * @param channelsOrder
+     *            the channels order.
+     */
+    private final void createShortLevels(int channels, boolean skipAlpha, int levels[],
+            int values[], int channelsOrder[]) {
+        short data[][] = ((ShortLookupTable)lut).getTable();
+        int nLevels = data[0].length;
+        int offset = lut.getOffset();
+
+        // Use one data array for all channels or use several data arrays
+        int dataIncrement = data.length > 1 ? 1 : 0;
+
+        for (int ch = 0, dataIdx = 0; ch < channels; dataIdx += dataIncrement, ch++) {
+            int channelOffset = channelsOrder == null ? ch : channelsOrder[ch];
+
+            // Skip last channel if needed, zero values are OK -
+            // no changes to the channel information will be done in IPP
+            if ((channelOffset == channels - 1 && skipAlpha) || (dataIdx >= data.length)) {
+                continue;
+            }
+
+            int channelBase = nLevels * channelOffset;
+            System.arraycopy(levelInitializer, offset, levels, channelBase, nLevels);
+            for (int from = 0, to = channelBase; from < nLevels; from++, to++) {
+                values[to] = data[dataIdx][from] & 0xFFFF;
+            }
+        }
+    }
+
+    // TODO remove when this method is used
+    /**
+     * Ipp filter.
+     * 
+     * @param src
+     *            the src.
+     * @param dst
+     *            the dst.
+     * @param imageType
+     *            the image type.
+     * @param skipAlpha
+     *            the skip alpha.
+     * @return the int.
+     */
+    @SuppressWarnings("unused")
+    private final int ippFilter(Raster src, WritableRaster dst, int imageType, boolean skipAlpha) {
+        int res;
+
+        int srcStride, dstStride;
+        int channels;
+        int offsets[] = null;
+        int channelsOrder[] = null;
+
+        switch (imageType) {
+            case BufferedImage.TYPE_INT_ARGB:
+            case BufferedImage.TYPE_INT_ARGB_PRE:
+            case BufferedImage.TYPE_INT_RGB: {
+                channels = 4;
+                srcStride = src.getWidth() * 4;
+                dstStride = dst.getWidth() * 4;
+                channelsOrder = new int[] {
+                        2, 1, 0, 3
+                };
+                break;
+            }
+
+            case BufferedImage.TYPE_4BYTE_ABGR:
+            case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+            case BufferedImage.TYPE_INT_BGR: {
+                channels = 4;
+                srcStride = src.getWidth() * 4;
+                dstStride = dst.getWidth() * 4;
+                break;
+            }
+
+            case BufferedImage.TYPE_BYTE_GRAY: {
+                channels = 1;
+                srcStride = src.getWidth();
+                dstStride = dst.getWidth();
+                break;
+            }
+
+            case BufferedImage.TYPE_3BYTE_BGR: {
+                channels = 3;
+                srcStride = src.getWidth() * 3;
+                dstStride = dst.getWidth() * 3;
+                channelsOrder = new int[] {
+                        2, 1, 0
+                };
+                break;
+            }
+
+            case BufferedImage.TYPE_USHORT_GRAY:
+            case BufferedImage.TYPE_USHORT_565_RGB:
+            case BufferedImage.TYPE_USHORT_555_RGB:
+            case BufferedImage.TYPE_BYTE_BINARY: {
+                return slowFilter(src, dst, skipAlpha);
+            }
+
+            default: {
+                SampleModel srcSM = src.getSampleModel();
+                SampleModel dstSM = dst.getSampleModel();
+
+                if (srcSM instanceof PixelInterleavedSampleModel
+                        && dstSM instanceof PixelInterleavedSampleModel) {
+                    // Check PixelInterleavedSampleModel
+                    if (srcSM.getDataType() != DataBuffer.TYPE_BYTE
+                            || dstSM.getDataType() != DataBuffer.TYPE_BYTE) {
+                        return slowFilter(src, dst, skipAlpha);
+                    }
+
+                    // Have IPP functions for 1, 3 and 4 channels
+                    channels = srcSM.getNumBands();
+                    if (!(channels == 1 || channels == 3 || channels == 4)) {
+                        return slowFilter(src, dst, skipAlpha);
+                    }
+
+                    srcStride = ((ComponentSampleModel)srcSM).getScanlineStride();
+                    dstStride = ((ComponentSampleModel)dstSM).getScanlineStride();
+
+                    channelsOrder = ((ComponentSampleModel)srcSM).getBandOffsets();
+                } else if (srcSM instanceof SinglePixelPackedSampleModel
+                        && dstSM instanceof SinglePixelPackedSampleModel) {
+                    // Check SinglePixelPackedSampleModel
+                    SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM;
+                    SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM;
+
+                    channels = sppsm1.getNumBands();
+
+                    // TYPE_INT_RGB, TYPE_INT_ARGB...
+                    if (sppsm1.getDataType() != DataBuffer.TYPE_INT
+                            || sppsm2.getDataType() != DataBuffer.TYPE_INT
+                            || !(channels == 3 || channels == 4)) {
+                        return slowFilter(src, dst, skipAlpha);
+                    }
+
+                    // Check compatibility of sample models
+                    if (!Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets())
+                            || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) {
+                        return slowFilter(src, dst, skipAlpha);
+                    }
+
+                    for (int i = 0; i < channels; i++) {
+                        if (sppsm1.getSampleSize(i) != 8) {
+                            return slowFilter(src, dst, skipAlpha);
+                        }
+                    }
+
+                    channelsOrder = new int[channels];
+                    int bitOffsets[] = sppsm1.getBitOffsets();
+                    for (int i = 0; i < channels; i++) {
+                        channelsOrder[i] = bitOffsets[i] / 8;
+                    }
+
+                    if (channels == 3) { // Don't skip channel now, could be
+                        // optimized
+                        channels = 4;
+                    }
+
+                    srcStride = sppsm1.getScanlineStride() * 4;
+                    dstStride = sppsm2.getScanlineStride() * 4;
+                } else {
+                    return slowFilter(src, dst, skipAlpha);
+                }
+
+                // Fill offsets if there's a child raster
+                if (src.getParent() != null || dst.getParent() != null) {
+                    if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0
+                            || dst.getSampleModelTranslateX() != 0
+                            || dst.getSampleModelTranslateY() != 0) {
+                        offsets = new int[4];
+                        offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+                        offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+                        offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+                        offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+                    }
+                }
+            }
+        }
+
+        int levels[] = null, values[] = null;
+        int channelMultiplier = skipAlpha ? -1 : 1;
+        if (channelMultiplier * channels == validForChannels) { // use existing
+            // levels/values
+            levels = cachedLevels;
+            values = cachedValues;
+        } else { // create new levels/values
+            if (lut instanceof ByteLookupTable) {
+                byte data[][] = ((ByteLookupTable)lut).getTable();
+                levels = new int[channels * data[0].length];
+                values = new int[channels * data[0].length];
+                createByteLevels(channels, skipAlpha, levels, values, channelsOrder);
+            } else if (lut instanceof ShortLookupTable) {
+                short data[][] = ((ShortLookupTable)lut).getTable();
+                levels = new int[channels * data[0].length];
+                values = new int[channels * data[0].length];
+                createShortLevels(channels, skipAlpha, levels, values, channelsOrder);
+            }
+
+            // cache levels/values
+            validForChannels = channelMultiplier * channels;
+            cachedLevels = levels;
+            cachedValues = values;
+        }
+
+        Object srcData, dstData;
+        AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+        try {
+            srcData = dbAccess.getData(src.getDataBuffer());
+            dstData = dbAccess.getData(dst.getDataBuffer());
+        } catch (IllegalArgumentException e) {
+            return -1; // Unknown data buffer type
+        }
+
+        res = ippLUT(srcData, src.getWidth(), src.getHeight(), srcStride, dstData, dst.getWidth(),
+                dst.getHeight(), dstStride, levels, values, channels, offsets, false);
+
+        return res;
+    }
+
+    /**
+     * Ipp lut.
+     * 
+     * @param src
+     *            the src.
+     * @param srcWidth
+     *            the src width.
+     * @param srcHeight
+     *            the src height.
+     * @param srcStride
+     *            the src stride.
+     * @param dst
+     *            the dst.
+     * @param dstWidth
+     *            the dst width.
+     * @param dstHeight
+     *            the dst height.
+     * @param dstStride
+     *            the dst stride.
+     * @param levels
+     *            the levels.
+     * @param values
+     *            the values.
+     * @param channels
+     *            the channels.
+     * @param offsets
+     *            the offsets.
+     * @param linear
+     *            the linear.
+     * @return the int.
+     */
+    final static native int ippLUT(Object src, int srcWidth, int srcHeight, int srcStride,
+            Object dst, int dstWidth, int dstHeight, int dstStride, int levels[], int values[],
+            int channels, int offsets[], boolean linear);
+}
diff --git a/awt/java/awt/image/LookupTable.java b/awt/java/awt/image/LookupTable.java
new file mode 100644
index 0000000..e465a54
--- /dev/null
+++ b/awt/java/awt/image/LookupTable.java
@@ -0,0 +1,101 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 14, 2005
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This abstract LookupTable class represents lookup table which is defined with
+ * the number of components and offset value. ByteLookupTable and
+ * ShortLookupTable classes are subclasses of LookupTable which contains byte
+ * and short data tables as an input arrays for bands or components of image.
+ * 
+ * @since Android 1.0
+ */
+public abstract class LookupTable {
+
+    /**
+     * The offset.
+     */
+    private int offset;
+
+    /**
+     * The num components.
+     */
+    private int numComponents;
+
+    /**
+     * Instantiates a new LookupTable with the specified offset value and number
+     * of components.
+     * 
+     * @param offset
+     *            the offset value.
+     * @param numComponents
+     *            the number of components.
+     */
+    protected LookupTable(int offset, int numComponents) {
+        if (offset < 0) {
+            // awt.232=Offset should be not less than zero
+            throw new IllegalArgumentException(Messages.getString("awt.232")); //$NON-NLS-1$
+        }
+        if (numComponents < 1) {
+            // awt.233=Number of components should be positive
+            throw new IllegalArgumentException(Messages.getString("awt.233")); //$NON-NLS-1$
+        }
+
+        this.offset = offset;
+        this.numComponents = numComponents;
+    }
+
+    /**
+     * Gets the offset value of this Lookup table.
+     * 
+     * @return the offset value of this Lookup table.
+     */
+    public int getOffset() {
+        return offset;
+    }
+
+    /**
+     * Gets the number of components of this Lookup table.
+     * 
+     * @return the number components of this Lookup table.
+     */
+    public int getNumComponents() {
+        return numComponents;
+    }
+
+    /**
+     * Returns an integer array which contains samples of the specified pixel which
+     * is translated with the lookup table of this LookupTable. The resulted
+     * array is stored to the dst array.
+     * 
+     * @param src
+     *            the source array.
+     * @param dst
+     *            the destination array where the result can be stored.
+     * @return the integer array of translated samples of a pixel.
+     */
+    public abstract int[] lookupPixel(int[] src, int[] dst);
+}
diff --git a/awt/java/awt/image/MemoryImageSource.java b/awt/java/awt/image/MemoryImageSource.java
new file mode 100644
index 0000000..644fd40f
--- /dev/null
+++ b/awt/java/awt/image/MemoryImageSource.java
@@ -0,0 +1,603 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The MemoryImageSource class is used to produces pixels of an image from an
+ * array. This class can manage a memory image which contains an animation or
+ * custom rendering.
+ * 
+ * @since Android 1.0
+ */
+public class MemoryImageSource implements ImageProducer {
+
+    /**
+     * The width.
+     */
+    int width;
+
+    /**
+     * The height.
+     */
+    int height;
+
+    /**
+     * The cm.
+     */
+    ColorModel cm;
+
+    /**
+     * The b data.
+     */
+    byte bData[];
+
+    /**
+     * The i data.
+     */
+    int iData[];
+
+    /**
+     * The offset.
+     */
+    int offset;
+
+    /**
+     * The scanline.
+     */
+    int scanline;
+
+    /**
+     * The properties.
+     */
+    Hashtable<?, ?> properties;
+
+    /**
+     * The consumers.
+     */
+    Vector<ImageConsumer> consumers;
+
+    /**
+     * The animated.
+     */
+    boolean animated;
+
+    /**
+     * The fullbuffers.
+     */
+    boolean fullbuffers;
+
+    /**
+     * The data type.
+     */
+    int dataType;
+
+    /**
+     * The Constant DATA_TYPE_BYTE.
+     */
+    static final int DATA_TYPE_BYTE = 0;
+
+    /**
+     * The Constant DATA_TYPE_INT.
+     */
+    static final int DATA_TYPE_INT = 1;
+
+    /**
+     * Instantiates a new MemoryImageSource with the specified parameters.
+     * 
+     * @param w
+     *            the width of the rectangular area of pixels.
+     * @param h
+     *            the height of the rectangular area of pixels.
+     * @param cm
+     *            the specified ColorModel.
+     * @param pix
+     *            the pixel array.
+     * @param off
+     *            the offset in the pixel array.
+     * @param scan
+     *            the distance from one pixel's row to the next in the pixel
+     *            array.
+     * @param props
+     *            the set of properties to be used for image processing.
+     */
+    public MemoryImageSource(int w, int h, ColorModel cm, int pix[], int off, int scan,
+            Hashtable<?, ?> props) {
+        init(w, h, cm, pix, off, scan, props);
+    }
+
+    /**
+     * Instantiates a new MemoryImageSource with the specified parameters.
+     * 
+     * @param w
+     *            the width of the rectangular area of pixels.
+     * @param h
+     *            the height of the rectangular area of pixels.
+     * @param cm
+     *            the specified ColorModel.
+     * @param pix
+     *            the pixel array.
+     * @param off
+     *            the offset in the pixel array.
+     * @param scan
+     *            the distance from one pixel's row to the next in the pixel
+     *            array.
+     * @param props
+     *            the set of properties to be used for image processing.
+     */
+    public MemoryImageSource(int w, int h, ColorModel cm, byte pix[], int off, int scan,
+            Hashtable<?, ?> props) {
+        init(w, h, cm, pix, off, scan, props);
+    }
+
+    /**
+     * Instantiates a new MemoryImageSource with the specified parameters and
+     * default RGB ColorModel.
+     * 
+     * @param w
+     *            the width of the rectangular area of pixels.
+     * @param h
+     *            the height of the rectangular area of pixels.
+     * @param pix
+     *            the pixel array.
+     * @param off
+     *            the offset in the pixel array.
+     * @param scan
+     *            the distance from one pixel's row to the next in the pixel
+     *            array.
+     * @param props
+     *            the set of properties to be used for image processing.
+     */
+    public MemoryImageSource(int w, int h, int pix[], int off, int scan, Hashtable<?, ?> props) {
+        init(w, h, ColorModel.getRGBdefault(), pix, off, scan, props);
+    }
+
+    /**
+     * Instantiates a new MemoryImageSource with the specified parameters.
+     * 
+     * @param w
+     *            the width of the rectangular area of pixels.
+     * @param h
+     *            the height of the rectangular area of pixels.
+     * @param cm
+     *            the specified ColorModel.
+     * @param pix
+     *            the pixel array.
+     * @param off
+     *            the offset in the pixel array.
+     * @param scan
+     *            the distance from one pixel's row to the next in the pixel
+     *            array.
+     */
+    public MemoryImageSource(int w, int h, ColorModel cm, int pix[], int off, int scan) {
+        init(w, h, cm, pix, off, scan, null);
+    }
+
+    /**
+     * Instantiates a new MemoryImageSource with the specified parameters.
+     * 
+     * @param w
+     *            the width of the rectangular area of pixels.
+     * @param h
+     *            the height of the rectangular area of pixels.
+     * @param cm
+     *            the specified ColorModel.
+     * @param pix
+     *            the pixel array.
+     * @param off
+     *            the offset in the pixel array.
+     * @param scan
+     *            the distance from one pixel's row to the next in the pixel
+     *            array.
+     */
+    public MemoryImageSource(int w, int h, ColorModel cm, byte pix[], int off, int scan) {
+        init(w, h, cm, pix, off, scan, null);
+    }
+
+    /**
+     * Instantiates a new MemoryImageSource with the specified parameters and
+     * default RGB ColorModel.
+     * 
+     * @param w
+     *            the width of the rectangular area of pixels.
+     * @param h
+     *            the height of the rectangular area of pixels.
+     * @param pix
+     *            the pixels array.
+     * @param off
+     *            the offset in the pixel array.
+     * @param scan
+     *            the distance from one pixel's row to the next in the pixel
+     *            array.
+     */
+    public MemoryImageSource(int w, int h, int pix[], int off, int scan) {
+        init(w, h, ColorModel.getRGBdefault(), pix, off, scan, null);
+    }
+
+    public synchronized boolean isConsumer(ImageConsumer ic) {
+        return consumers.contains(ic);
+    }
+
+    public void startProduction(ImageConsumer ic) {
+        if (!isConsumer(ic) && ic != null) {
+            consumers.addElement(ic);
+        }
+        try {
+            setHeader(ic);
+            setPixels(ic, 0, 0, width, height);
+            if (animated) {
+                ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+            } else {
+                ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
+                if (isConsumer(ic)) {
+                    removeConsumer(ic);
+                }
+            }
+        } catch (Exception e) {
+            if (isConsumer(ic)) {
+                ic.imageComplete(ImageConsumer.IMAGEERROR);
+            }
+            if (isConsumer(ic)) {
+                removeConsumer(ic);
+            }
+        }
+    }
+
+    public void requestTopDownLeftRightResend(ImageConsumer ic) {
+    }
+
+    public synchronized void removeConsumer(ImageConsumer ic) {
+        consumers.removeElement(ic);
+    }
+
+    public synchronized void addConsumer(ImageConsumer ic) {
+        if (ic == null || consumers.contains(ic)) {
+            return;
+        }
+        consumers.addElement(ic);
+    }
+
+    /**
+     * Replaces the pixel data with a new pixel array for holding the pixels for
+     * this image. If an animation flag is set to true value by the
+     * setAnimated() method, the new pixels will be immediately delivered to the
+     * ImageConsumers.
+     * 
+     * @param newpix
+     *            the new pixel array.
+     * @param newmodel
+     *            the new ColorModel.
+     * @param offset
+     *            the offset in the array.
+     * @param scansize
+     *            the distance from one row of pixels to the next row in the
+     *            pixel array.
+     */
+    public synchronized void newPixels(int newpix[], ColorModel newmodel, int offset, int scansize) {
+        this.dataType = DATA_TYPE_INT;
+        this.iData = newpix;
+        this.cm = newmodel;
+        this.offset = offset;
+        this.scanline = scansize;
+        newPixels();
+    }
+
+    /**
+     * Replaces the pixel data with a new pixel array for holding the pixels for
+     * this image. If an animation flag is set to true value by the
+     * setAnimated() method, the new pixels will be immediately delivered to the
+     * ImageConsumers.
+     * 
+     * @param newpix
+     *            the new pixel array.
+     * @param newmodel
+     *            the new ColorModel.
+     * @param offset
+     *            the offset in the array.
+     * @param scansize
+     *            the distance from one row of pixels to the next row in the
+     *            pixel array.
+     */
+    public synchronized void newPixels(byte newpix[], ColorModel newmodel, int offset, int scansize) {
+        this.dataType = DATA_TYPE_BYTE;
+        this.bData = newpix;
+        this.cm = newmodel;
+        this.offset = offset;
+        this.scanline = scansize;
+        newPixels();
+    }
+
+    /**
+     * Sets the full buffer updates flag to true. If this is an animated image,
+     * the image consumers hints are updated accordingly.
+     * 
+     * @param fullbuffers
+     *            the true if the pixel buffer should be sent always.
+     */
+    public synchronized void setFullBufferUpdates(boolean fullbuffers) {
+        if (this.fullbuffers == fullbuffers) {
+            return;
+        }
+        this.fullbuffers = fullbuffers;
+        if (animated) {
+            Object consAr[] = consumers.toArray();
+            for (Object element : consAr) {
+                ImageConsumer con = (ImageConsumer)element;
+                try {
+                    if (fullbuffers) {
+                        con.setHints(ImageConsumer.TOPDOWNLEFTRIGHT
+                                | ImageConsumer.COMPLETESCANLINES);
+                    } else {
+                        con.setHints(ImageConsumer.RANDOMPIXELORDER);
+                    }
+                } catch (Exception e) {
+                    if (isConsumer(con)) {
+                        con.imageComplete(ImageConsumer.IMAGEERROR);
+                    }
+                    if (isConsumer(con)) {
+                        removeConsumer(con);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets the flag that tells whether this memory image has more than one
+     * frame (for animation): true for multiple frames, false if this class
+     * represents a single frame image.
+     * 
+     * @param animated
+     *            whether this image represents an animation.
+     */
+    public synchronized void setAnimated(boolean animated) {
+        if (this.animated == animated) {
+            return;
+        }
+        Object consAr[] = consumers.toArray();
+        for (Object element : consAr) {
+            ImageConsumer con = (ImageConsumer)element;
+            try {
+                con.imageComplete(ImageConsumer.STATICIMAGEDONE);
+            } catch (Exception e) {
+                if (isConsumer(con)) {
+                    con.imageComplete(ImageConsumer.IMAGEERROR);
+                }
+            }
+            if (isConsumer(con)) {
+                removeConsumer(con);
+            }
+        }
+        this.animated = animated;
+    }
+
+    /**
+     * Sends the specified rectangular area of the buffer to ImageConsumers and
+     * notifies them that an animation frame is completed only if the {@code
+     * framenotify} parameter is true. That works only if the animated flag has
+     * been set to true by the setAnimated() method. If the full buffer update
+     * flag has been set to true by the setFullBufferUpdates() method, then the
+     * entire buffer will always be sent ignoring parameters.
+     * 
+     * @param x
+     *            the X coordinate of the rectangular area.
+     * @param y
+     *            the Y coordinate of the rectangular area.
+     * @param w
+     *            the width of the rectangular area.
+     * @param h
+     *            the height of the rectangular area.
+     * @param framenotify
+     *            true if a SINGLEFRAMEDONE notification should be sent to the
+     *            registered consumers, false otherwise.
+     */
+    public synchronized void newPixels(int x, int y, int w, int h, boolean framenotify) {
+        if (animated) {
+            if (fullbuffers) {
+                x = 0;
+                y = 0;
+                w = width;
+                h = height;
+            } else {
+                if (x < 0) {
+                    w += x;
+                    x = 0;
+                }
+                if (w > width) {
+                    w = width - x;
+                }
+                if (y < 0) {
+                    h += y;
+                    y = 0;
+                }
+            }
+            if (h > height) {
+                h = height - y;
+            }
+            Object consAr[] = consumers.toArray();
+            for (Object element : consAr) {
+                ImageConsumer con = (ImageConsumer)element;
+                try {
+                    if (w > 0 && h > 0) {
+                        setPixels(con, x, y, w, h);
+                    }
+                    if (framenotify) {
+                        con.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+                    }
+                } catch (Exception ex) {
+                    if (isConsumer(con)) {
+                        con.imageComplete(ImageConsumer.IMAGEERROR);
+                    }
+                    if (isConsumer(con)) {
+                        removeConsumer(con);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Sends the specified rectangular area of the buffer to the ImageConsumers
+     * and notifies them that an animation frame is completed if the animated
+     * flag has been set to true by the setAnimated() method. If the full buffer
+     * update flag has been set to true by the setFullBufferUpdates() method,
+     * then the entire buffer will always be sent ignoring parameters.
+     * 
+     * @param x
+     *            the X coordinate of the rectangular area.
+     * @param y
+     *            the Y coordinate of the rectangular area.
+     * @param w
+     *            the width of the rectangular area.
+     * @param h
+     *            the height of the rectangular area.
+     */
+    public synchronized void newPixels(int x, int y, int w, int h) {
+        newPixels(x, y, w, h, true);
+    }
+
+    /**
+     * Sends a new buffer of pixels to the ImageConsumers and notifies them that
+     * an animation frame is completed if the animated flag has been set to true
+     * by the setAnimated() method.
+     */
+    public void newPixels() {
+        newPixels(0, 0, width, height, true);
+    }
+
+    /**
+     * Inits the.
+     * 
+     * @param width
+     *            the width.
+     * @param height
+     *            the height.
+     * @param model
+     *            the model.
+     * @param pixels
+     *            the pixels.
+     * @param off
+     *            the off.
+     * @param scan
+     *            the scan.
+     * @param prop
+     *            the prop.
+     */
+    private void init(int width, int height, ColorModel model, byte pixels[], int off, int scan,
+            Hashtable<?, ?> prop) {
+
+        this.width = width;
+        this.height = height;
+        this.cm = model;
+        this.bData = pixels;
+        this.offset = off;
+        this.scanline = scan;
+        this.properties = prop;
+        this.dataType = DATA_TYPE_BYTE;
+        this.consumers = new Vector<ImageConsumer>();
+
+    }
+
+    /**
+     * Inits the.
+     * 
+     * @param width
+     *            the width.
+     * @param height
+     *            the height.
+     * @param model
+     *            the model.
+     * @param pixels
+     *            the pixels.
+     * @param off
+     *            the off.
+     * @param scan
+     *            the scan.
+     * @param prop
+     *            the prop.
+     */
+    private void init(int width, int height, ColorModel model, int pixels[], int off, int scan,
+            Hashtable<?, ?> prop) {
+
+        this.width = width;
+        this.height = height;
+        this.cm = model;
+        this.iData = pixels;
+        this.offset = off;
+        this.scanline = scan;
+        this.properties = prop;
+        this.dataType = DATA_TYPE_INT;
+        this.consumers = new Vector<ImageConsumer>();
+    }
+
+    /**
+     * Sets the pixels.
+     * 
+     * @param con
+     *            the con.
+     * @param x
+     *            the x.
+     * @param y
+     *            the y.
+     * @param w
+     *            the w.
+     * @param h
+     *            the h.
+     */
+    private void setPixels(ImageConsumer con, int x, int y, int w, int h) {
+        int pixelOff = scanline * y + offset + x;
+
+        switch (dataType) {
+            case DATA_TYPE_BYTE:
+                con.setPixels(x, y, w, h, cm, bData, pixelOff, scanline);
+                break;
+            case DATA_TYPE_INT:
+                con.setPixels(x, y, w, h, cm, iData, pixelOff, scanline);
+                break;
+            default:
+                // awt.22A=Wrong type of pixels array
+                throw new IllegalArgumentException(Messages.getString("awt.22A")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Sets the header.
+     * 
+     * @param con
+     *            the new header.
+     */
+    private synchronized void setHeader(ImageConsumer con) {
+        con.setDimensions(width, height);
+        con.setProperties(properties);
+        con.setColorModel(cm);
+        con
+                .setHints(animated ? (fullbuffers ? (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES)
+                        : ImageConsumer.RANDOMPIXELORDER)
+                        : (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES
+                                | ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME));
+    }
+
+}
diff --git a/awt/java/awt/image/MultiPixelPackedSampleModel.java b/awt/java/awt/image/MultiPixelPackedSampleModel.java
new file mode 100644
index 0000000..3dc13d8
--- /dev/null
+++ b/awt/java/awt/image/MultiPixelPackedSampleModel.java
@@ -0,0 +1,479 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The MultiPixelPackedSampleModel class represents image data with one band.
+ * This class packs multiple pixels with one sample in one data element and
+ * supports the following data types: DataBuffer.TYPE_BYTE,
+ * DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT.
+ * 
+ * @since Android 1.0
+ */
+public class MultiPixelPackedSampleModel extends SampleModel {
+
+    /**
+     * The pixel bit stride.
+     */
+    private int pixelBitStride;
+
+    /**
+     * The scanline stride.
+     */
+    private int scanlineStride;
+
+    /**
+     * The data bit offset.
+     */
+    private int dataBitOffset;
+
+    /**
+     * The bit mask.
+     */
+    private int bitMask;
+
+    /**
+     * The data element size.
+     */
+    private int dataElementSize;
+
+    /**
+     * The pixels per data element.
+     */
+    private int pixelsPerDataElement;
+
+    /**
+     * Instantiates a new MultiPixelPackedSampleModel with the specified
+     * parameters.
+     * 
+     * @param dataType
+     *            the data type of the samples.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param numberOfBits
+     *            the number of bits per pixel.
+     * @param scanlineStride
+     *            the scanline stride of the of the image data.
+     * @param dataBitOffset
+     *            the array of the band offsets.
+     */
+    public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits,
+            int scanlineStride, int dataBitOffset) {
+
+        super(dataType, w, h, 1);
+        if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT
+                && dataType != DataBuffer.TYPE_INT) {
+            // awt.61=Unsupported data type: {0}
+            throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$
+                    dataType));
+        }
+
+        this.scanlineStride = scanlineStride;
+        if (numberOfBits == 0) {
+            // awt.20C=Number of Bits equals to zero
+            throw new RasterFormatException(Messages.getString("awt.20C")); //$NON-NLS-1$
+        }
+        this.pixelBitStride = numberOfBits;
+        this.dataElementSize = DataBuffer.getDataTypeSize(dataType);
+        if (dataElementSize % pixelBitStride != 0) {
+            // awt.20D=The number of bits per pixel is not a power of 2 or
+            // pixels span data element boundaries
+            throw new RasterFormatException(Messages.getString("awt.20D")); //$NON-NLS-1$
+        }
+
+        if (dataBitOffset % numberOfBits != 0) {
+            // awt.20E=Data Bit offset is not a multiple of pixel bit stride
+            throw new RasterFormatException(Messages.getString("awt.20E")); //$NON-NLS-1$
+        }
+        this.dataBitOffset = dataBitOffset;
+
+        this.pixelsPerDataElement = dataElementSize / pixelBitStride;
+        this.bitMask = (1 << numberOfBits) - 1;
+    }
+
+    /**
+     * Instantiates a new MultiPixelPackedSampleModel with the specified
+     * parameters.
+     * 
+     * @param dataType
+     *            the data type of the samples.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param numberOfBits
+     *            the number of bits per pixel.
+     */
+    public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits) {
+
+        this(dataType, w, h, numberOfBits,
+                (numberOfBits * w + DataBuffer.getDataTypeSize(dataType) - 1)
+                        / DataBuffer.getDataTypeSize(dataType), 0);
+    }
+
+    @Override
+    public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        switch (getTransferType()) {
+            case DataBuffer.TYPE_BYTE:
+                byte bdata[];
+                if (obj == null) {
+                    bdata = new byte[1];
+                } else {
+                    bdata = (byte[])obj;
+                }
+                bdata[0] = (byte)getSample(x, y, 0, data);
+                obj = bdata;
+                break;
+            case DataBuffer.TYPE_USHORT:
+                short sdata[];
+                if (obj == null) {
+                    sdata = new short[1];
+                } else {
+                    sdata = (short[])obj;
+                }
+                sdata[0] = (short)getSample(x, y, 0, data);
+                obj = sdata;
+                break;
+            case DataBuffer.TYPE_INT:
+                int idata[];
+                if (obj == null) {
+                    idata = new int[1];
+                } else {
+                    idata = (int[])obj;
+                }
+                idata[0] = getSample(x, y, 0, data);
+                obj = idata;
+                break;
+        }
+
+        return obj;
+    }
+
+    @Override
+    public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+        setSample(x, y, obj, data, 1, 0);
+    }
+
+    /**
+     * Compares this MultiPixelPackedSampleModel object with the specified
+     * object.
+     * 
+     * @param o
+     *            the Object to be compared.
+     * @return true, if the object is a MultiPixelPackedSampleModel with the
+     *         same data parameter values as this MultiPixelPackedSampleModel,
+     *         false otherwise.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if ((o == null) || !(o instanceof MultiPixelPackedSampleModel)) {
+            return false;
+        }
+
+        MultiPixelPackedSampleModel model = (MultiPixelPackedSampleModel)o;
+        return this.width == model.width && this.height == model.height
+                && this.numBands == model.numBands && this.dataType == model.dataType
+                && this.pixelBitStride == model.pixelBitStride && this.bitMask == model.bitMask
+                && this.pixelsPerDataElement == model.pixelsPerDataElement
+                && this.dataElementSize == model.dataElementSize
+                && this.dataBitOffset == model.dataBitOffset
+                && this.scanlineStride == model.scanlineStride;
+    }
+
+    @Override
+    public SampleModel createSubsetSampleModel(int bands[]) {
+        if (bands != null && bands.length != 1) {
+            // awt.20F=Number of bands must be only 1
+            throw new RasterFormatException(Messages.getString("awt.20F")); //$NON-NLS-1$
+        }
+        return createCompatibleSampleModel(width, height);
+    }
+
+    @Override
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+        return new MultiPixelPackedSampleModel(dataType, w, h, pixelBitStride);
+    }
+
+    @Override
+    public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int pixel[];
+        if (iArray == null) {
+            pixel = new int[numBands];
+        } else {
+            pixel = iArray;
+        }
+
+        pixel[0] = getSample(x, y, 0, data);
+        return pixel;
+    }
+
+    @Override
+    public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+        setSample(x, y, iArray, data, 2, 0);
+    }
+
+    @Override
+    public int getSample(int x, int y, int b, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height || b != 0) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        int bitnum = dataBitOffset + x * pixelBitStride;
+        int elem = data.getElem(y * scanlineStride + bitnum / dataElementSize);
+        int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - pixelBitStride;
+
+        return (elem >> shift) & bitMask;
+    }
+
+    @Override
+    public void setSample(int x, int y, int b, int s, DataBuffer data) {
+        if (b != 0) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        setSample(x, y, null, data, 3, s);
+    }
+
+    @Override
+    public DataBuffer createDataBuffer() {
+        DataBuffer dataBuffer = null;
+        int size = scanlineStride * height;
+
+        switch (dataType) {
+            case DataBuffer.TYPE_BYTE:
+                dataBuffer = new DataBufferByte(size + (dataBitOffset + 7) / 8);
+                break;
+            case DataBuffer.TYPE_USHORT:
+                dataBuffer = new DataBufferUShort(size + (dataBitOffset + 15) / 16);
+                break;
+            case DataBuffer.TYPE_INT:
+                dataBuffer = new DataBufferInt(size + (dataBitOffset + 31) / 32);
+                break;
+        }
+        return dataBuffer;
+    }
+
+    /**
+     * Gets the offset of the specified pixel in the data array.
+     * 
+     * @param x
+     *            the X coordinate of the specified pixel.
+     * @param y
+     *            the Y coordinate of the specified pixel.
+     * @return the offset of the specified pixel.
+     */
+    public int getOffset(int x, int y) {
+        return y * scanlineStride + (x * pixelBitStride + dataBitOffset) / dataElementSize;
+    }
+
+    @Override
+    public int getSampleSize(int band) {
+        return pixelBitStride;
+    }
+
+    /**
+     * Gets the bit offset in the data element which is stored for the specified
+     * pixel of a scanline.
+     * 
+     * @param x
+     *            the pixel.
+     * @return the bit offset of the pixel in the data element.
+     */
+    public int getBitOffset(int x) {
+        return (x * pixelBitStride + dataBitOffset) % dataElementSize;
+    }
+
+    @Override
+    public int[] getSampleSize() {
+        int sampleSizes[] = {
+            pixelBitStride
+        };
+        return sampleSizes;
+    }
+
+    /**
+     * Returns a hash code of this MultiPixelPackedSampleModel class.
+     * 
+     * @return the hash code of this MultiPixelPackedSampleModel class.
+     */
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        int tmp = 0;
+
+        hash = width;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= height;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= numBands;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= dataType;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= scanlineStride;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= pixelBitStride;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= dataBitOffset;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= bitMask;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= dataElementSize;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= pixelsPerDataElement;
+        return hash;
+    }
+
+    @Override
+    public int getTransferType() {
+        if (pixelBitStride > 16) {
+            return DataBuffer.TYPE_INT;
+        } else if (pixelBitStride > 8) {
+            return DataBuffer.TYPE_USHORT;
+        } else {
+            return DataBuffer.TYPE_BYTE;
+        }
+    }
+
+    /**
+     * Gets the scanline stride of this MultiPixelPackedSampleModel.
+     * 
+     * @return the scanline stride of this MultiPixelPackedSampleModel.
+     */
+    public int getScanlineStride() {
+        return scanlineStride;
+    }
+
+    /**
+     * Gets the pixel bit stride of this MultiPixelPackedSampleModel.
+     * 
+     * @return the pixel bit stride of this MultiPixelPackedSampleModel.
+     */
+    public int getPixelBitStride() {
+        return pixelBitStride;
+    }
+
+    @Override
+    public int getNumDataElements() {
+        return 1;
+    }
+
+    /**
+     * Gets the data bit offset.
+     * 
+     * @return the data bit offset.
+     */
+    public int getDataBitOffset() {
+        return dataBitOffset;
+    }
+
+    /**
+     * This method is used by other methods of this class. The behavior of this
+     * method depends on the method which has been invoke this one. The argument
+     * methodId is used to choose valid behavior in a particular case. If
+     * methodId is equal to 1 it means that this method has been invoked by the
+     * setDataElements() method, 2 - means setPixel(), and setSample() in any
+     * other cases.
+     * 
+     * @param x
+     *            the x.
+     * @param y
+     *            the y.
+     * @param obj
+     *            the obj.
+     * @param data
+     *            the data.
+     * @param methodId
+     *            the method id.
+     * @param s
+     *            the s.
+     */
+    private void setSample(final int x, final int y, final Object obj, final DataBuffer data,
+            final int methodId, int s) {
+        if ((x < 0) || (y < 0) || (x >= this.width) || (y >= this.height)) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        final int bitnum = dataBitOffset + x * pixelBitStride;
+        final int idx = y * scanlineStride + bitnum / dataElementSize;
+        final int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - pixelBitStride;
+        final int mask = ~(bitMask << shift);
+        int elem = data.getElem(idx);
+
+        switch (methodId) {
+            case 1: { // Invoked from setDataElements()
+                switch (getTransferType()) {
+                    case DataBuffer.TYPE_BYTE:
+                        s = ((byte[])obj)[0] & 0xff;
+                        break;
+                    case DataBuffer.TYPE_USHORT:
+                        s = ((short[])obj)[0] & 0xffff;
+                        break;
+                    case DataBuffer.TYPE_INT:
+                        s = ((int[])obj)[0];
+                        break;
+                }
+                break;
+            }
+            case 2: { // Invoked from setPixel()
+                s = ((int[])obj)[0];
+                break;
+            }
+        }
+
+        elem &= mask;
+        elem |= (s & bitMask) << shift;
+        data.setElem(idx, elem);
+    }
+}
diff --git a/awt/java/awt/image/PackedColorModel.java b/awt/java/awt/image/PackedColorModel.java
new file mode 100644
index 0000000..4d1c2e5
--- /dev/null
+++ b/awt/java/awt/image/PackedColorModel.java
@@ -0,0 +1,402 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The class PackedColorModel represents a color model where the components are
+ * just the red, green, and blue bands, plus an alpha band if alpha is
+ * supported.
+ * 
+ * @since Android 1.0
+ */
+public abstract class PackedColorModel extends ColorModel {
+
+    /**
+     * The component masks.
+     */
+    int componentMasks[];
+
+    /**
+     * The offsets.
+     */
+    int offsets[];
+
+    /**
+     * The scales.
+     */
+    float scales[];
+
+    /**
+     * Instantiates a new packed color model.
+     * 
+     * @param space
+     *            the color space.
+     * @param bits
+     *            the array of component masks.
+     * @param colorMaskArray
+     *            the array that gives the bitmask corresponding to each color
+     *            band (red, green, and blue).
+     * @param alphaMask
+     *            the bitmask corresponding to the alpha band.
+     * @param isAlphaPremultiplied
+     *            whether the alpha is pre-multiplied in this color model.
+     * @param trans
+     *            the transparency strategy, @see java.awt.Transparency.
+     * @param transferType
+     *            the transfer type (primitive java type to use for the
+     *            components).
+     * @throws IllegalArgumentException
+     *             if the number of bits in the combined bitmasks for the color
+     *             bands is less than one or greater than 32.
+     */
+    public PackedColorModel(ColorSpace space, int bits, int colorMaskArray[], int alphaMask,
+            boolean isAlphaPremultiplied, int trans, int transferType) {
+
+        super(bits, createBits(colorMaskArray, alphaMask), space, (alphaMask == 0 ? false : true),
+                isAlphaPremultiplied, trans, validateTransferType(transferType));
+
+        if (pixel_bits < 1 || pixel_bits > 32) {
+            // awt.236=The bits is less than 1 or greater than 32
+            throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$
+        }
+
+        componentMasks = new int[numComponents];
+        for (int i = 0; i < numColorComponents; i++) {
+            componentMasks[i] = colorMaskArray[i];
+        }
+
+        if (hasAlpha) {
+            componentMasks[numColorComponents] = alphaMask;
+            if (this.bits[numColorComponents] == 1) {
+                transparency = Transparency.BITMASK;
+            }
+        }
+
+        parseComponents();
+    }
+
+    /**
+     * Instantiates a new packed color model.
+     * 
+     * @param space
+     *            the color space.
+     * @param bits
+     *            the array of component masks.
+     * @param rmask
+     *            the bitmask corresponding to the red band.
+     * @param gmask
+     *            the bitmask corresponding to the green band.
+     * @param bmask
+     *            the bitmask corresponding to the blue band.
+     * @param amask
+     *            the bitmask corresponding to the alpha band.
+     * @param isAlphaPremultiplied
+     *            whether the alpha is pre-multiplied in this color model.
+     * @param trans
+     *            the transparency strategy, @see java.awt.Transparency.
+     * @param transferType
+     *            the transfer type (primitive java type to use for the
+     *            components).
+     * @throws IllegalArgumentException
+     *             if the number of bits in the combined bitmasks for the color
+     *             bands is less than one or greater than 32.
+     */
+    public PackedColorModel(ColorSpace space, int bits, int rmask, int gmask, int bmask, int amask,
+            boolean isAlphaPremultiplied, int trans, int transferType) {
+
+        super(bits, createBits(rmask, gmask, bmask, amask), space, (amask == 0 ? false : true),
+                isAlphaPremultiplied, trans, validateTransferType(transferType));
+
+        if (pixel_bits < 1 || pixel_bits > 32) {
+            // awt.236=The bits is less than 1 or greater than 32
+            throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$
+        }
+
+        if (cs.getType() != ColorSpace.TYPE_RGB) {
+            // awt.239=The space is not a TYPE_RGB space
+            throw new IllegalArgumentException(Messages.getString("awt.239")); //$NON-NLS-1$
+        }
+
+        for (int i = 0; i < numColorComponents; i++) {
+            if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) {
+                // awt.23A=The min/max normalized component values are not
+                // 0.0/1.0
+                throw new IllegalArgumentException(Messages.getString("awt.23A")); //$NON-NLS-1$
+            }
+        }
+        componentMasks = new int[numComponents];
+        componentMasks[0] = rmask;
+        componentMasks[1] = gmask;
+        componentMasks[2] = bmask;
+
+        if (hasAlpha) {
+            componentMasks[3] = amask;
+            if (this.bits[3] == 1) {
+                transparency = Transparency.BITMASK;
+            }
+        }
+
+        parseComponents();
+    }
+
+    @Override
+    public WritableRaster getAlphaRaster(WritableRaster raster) {
+        if (!hasAlpha) {
+            return null;
+        }
+
+        int x = raster.getMinX();
+        int y = raster.getMinY();
+        int w = raster.getWidth();
+        int h = raster.getHeight();
+        int band[] = new int[1];
+        band[0] = raster.getNumBands() - 1;
+        return raster.createWritableChild(x, y, w, h, x, y, band);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof PackedColorModel)) {
+            return false;
+        }
+        PackedColorModel cm = (PackedColorModel)obj;
+
+        return (pixel_bits == cm.getPixelSize() && transferType == cm.getTransferType()
+                && cs.getType() == cm.getColorSpace().getType() && hasAlpha == cm.hasAlpha()
+                && isAlphaPremultiplied == cm.isAlphaPremultiplied()
+                && transparency == cm.getTransparency()
+                && numColorComponents == cm.getNumColorComponents()
+                && numComponents == cm.getNumComponents()
+                && Arrays.equals(bits, cm.getComponentSize()) && Arrays.equals(componentMasks, cm
+                .getMasks()));
+    }
+
+    @Override
+    public boolean isCompatibleSampleModel(SampleModel sm) {
+        if (sm == null) {
+            return false;
+        }
+        if (!(sm instanceof SinglePixelPackedSampleModel)) {
+            return false;
+        }
+        SinglePixelPackedSampleModel esm = (SinglePixelPackedSampleModel)sm;
+
+        return ((esm.getNumBands() == numComponents) && (esm.getTransferType() == transferType) && Arrays
+                .equals(esm.getBitMasks(), componentMasks));
+    }
+
+    @Override
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+        return new SinglePixelPackedSampleModel(transferType, w, h, componentMasks);
+    }
+
+    /**
+     * Gets the bitmask corresponding to the specified color component.
+     * 
+     * @param index
+     *            the index of the desired color.
+     * @return the mask.
+     */
+    public final int getMask(int index) {
+        return componentMasks[index];
+    }
+
+    /**
+     * Gets the bitmasks of the components.
+     * 
+     * @return the masks.
+     */
+    public final int[] getMasks() {
+        return (componentMasks.clone());
+    }
+
+    /**
+     * Creates the bits.
+     * 
+     * @param colorMaskArray
+     *            the color mask array.
+     * @param alphaMask
+     *            the alpha mask.
+     * @return the int[].
+     */
+    private static int[] createBits(int colorMaskArray[], int alphaMask) {
+        int bits[];
+        int numComp;
+        if (alphaMask == 0) {
+            numComp = colorMaskArray.length;
+        } else {
+            numComp = colorMaskArray.length + 1;
+        }
+
+        bits = new int[numComp];
+        int i = 0;
+        for (; i < colorMaskArray.length; i++) {
+            bits[i] = countCompBits(colorMaskArray[i]);
+            if (bits[i] < 0) {
+                // awt.23B=The mask of the {0} component is not contiguous
+                throw new IllegalArgumentException(Messages.getString("awt.23B", i)); //$NON-NLS-1$
+            }
+        }
+
+        if (i < numComp) {
+            bits[i] = countCompBits(alphaMask);
+
+            if (bits[i] < 0) {
+                // awt.23C=The mask of the alpha component is not contiguous
+                throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$
+            }
+        }
+
+        return bits;
+    }
+
+    /**
+     * Creates the bits.
+     * 
+     * @param rmask
+     *            the rmask.
+     * @param gmask
+     *            the gmask.
+     * @param bmask
+     *            the bmask.
+     * @param amask
+     *            the amask.
+     * @return the int[].
+     */
+    private static int[] createBits(int rmask, int gmask, int bmask, int amask) {
+
+        int numComp;
+        if (amask == 0) {
+            numComp = 3;
+        } else {
+            numComp = 4;
+        }
+        int bits[] = new int[numComp];
+
+        bits[0] = countCompBits(rmask);
+        if (bits[0] < 0) {
+            // awt.23D=The mask of the red component is not contiguous
+            throw new IllegalArgumentException(Messages.getString("awt.23D")); //$NON-NLS-1$
+        }
+
+        bits[1] = countCompBits(gmask);
+        if (bits[1] < 0) {
+            // awt.23E=The mask of the green component is not contiguous
+            throw new IllegalArgumentException(Messages.getString("awt.23E")); //$NON-NLS-1$
+        }
+
+        bits[2] = countCompBits(bmask);
+        if (bits[2] < 0) {
+            // awt.23F=The mask of the blue component is not contiguous
+            throw new IllegalArgumentException(Messages.getString("awt.23F")); //$NON-NLS-1$
+        }
+
+        if (amask != 0) {
+            bits[3] = countCompBits(amask);
+            if (bits[3] < 0) {
+                // awt.23C=The mask of the alpha component is not contiguous
+                throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$
+            }
+        }
+
+        return bits;
+    }
+
+    /**
+     * Count comp bits.
+     * 
+     * @param compMask
+     *            the comp mask.
+     * @return the int.
+     */
+    private static int countCompBits(int compMask) {
+        int bits = 0;
+        if (compMask != 0) {
+            // Deleting final zeros
+            while ((compMask & 1) == 0) {
+                compMask >>>= 1;
+            }
+            // Counting component bits
+            while ((compMask & 1) == 1) {
+                compMask >>>= 1;
+                bits++;
+            }
+        }
+
+        if (compMask != 0) {
+            return -1;
+        }
+
+        return bits;
+    }
+
+    /**
+     * Validate transfer type.
+     * 
+     * @param transferType
+     *            the transfer type.
+     * @return the int.
+     */
+    private static int validateTransferType(int transferType) {
+        if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT
+                && transferType != DataBuffer.TYPE_INT) {
+            // awt.240=The transferType not is one of DataBuffer.TYPE_BYTE,
+            // DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT
+            throw new IllegalArgumentException(Messages.getString("awt.240")); //$NON-NLS-1$
+        }
+        return transferType;
+    }
+
+    /**
+     * Parses the components.
+     */
+    private void parseComponents() {
+        offsets = new int[numComponents];
+        scales = new float[numComponents];
+        for (int i = 0; i < numComponents; i++) {
+            int off = 0;
+            int mask = componentMasks[i];
+            while ((mask & 1) == 0) {
+                mask >>>= 1;
+                off++;
+            }
+            offsets[i] = off;
+            if (bits[i] == 0) {
+                scales[i] = 256.0f; // May be any value different from zero,
+                // because will dividing by zero
+            } else {
+                scales[i] = 255.0f / maxValues[i];
+            }
+        }
+
+    }
+
+}
diff --git a/awt/java/awt/image/PixelGrabber.java b/awt/java/awt/image/PixelGrabber.java
new file mode 100644
index 0000000..cecd5c8
--- /dev/null
+++ b/awt/java/awt/image/PixelGrabber.java
@@ -0,0 +1,408 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Image;
+import java.util.Hashtable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class PixelGrabber implements ImageConsumer {
+
+    int width;
+    int height;
+    int X;
+    int Y;
+    int offset;
+    int scanline;
+    ImageProducer producer;
+
+    byte bData[];
+    int iData[];
+    ColorModel cm;
+
+    private int grabberStatus;
+    private int dataType;
+    private boolean isGrabbing;
+    private boolean isRGB;
+
+
+    private static final int DATA_TYPE_BYTE = 0;
+    private static final int DATA_TYPE_INT = 1;
+    private static final int DATA_TYPE_UNDEFINED = 2;
+
+    private static final int ALL_BITS = (ImageObserver.FRAMEBITS |
+            ImageObserver.ALLBITS);
+
+    private static final int GRABBING_STOP = ALL_BITS | ImageObserver.ERROR;
+
+
+
+    public PixelGrabber(ImageProducer ip, int x, int y, int w, int h, int[] pix,
+            int off, int scansize) {
+        initialize(ip, x, y, w, h, pix, off, scansize, true);
+    }
+
+    public PixelGrabber(Image img, int x, int y, int w, int h, int[] pix,
+            int off, int scansize) {
+        initialize(img.getSource(), x, y, w, h, pix, off, scansize, true);
+    }
+
+    public PixelGrabber(Image img, int x, int y, int w, int h, boolean forceRGB) {
+        initialize(img.getSource(), x, y, w, h, null, 0, 0, forceRGB);
+    }
+
+    public void setProperties(Hashtable<?, ?> props) {
+        return;
+    }
+
+    public synchronized Object getPixels() {
+        switch(dataType){
+        case DATA_TYPE_BYTE:
+            return bData;
+        case DATA_TYPE_INT:
+            return iData;
+        default:
+            return null;
+        }
+    }
+
+    public void setColorModel(ColorModel model) {
+        return;
+    }
+
+    public void setPixels(int srcX, int srcY, int srcW, int srcH,
+            ColorModel model, byte[] pixels, int srcOff, int srcScan) {
+        if(srcY < Y){
+            int delta = Y - srcY;
+            if(delta >= height) {
+                return;
+            }
+            srcY += delta;
+            srcH -= delta;
+            srcOff += srcScan * delta;
+        }
+
+        if(srcY + srcH > Y + height){
+            srcH = Y + height - srcY;
+            if(srcH <= 0) {
+                return;
+            }
+        }
+
+        if(srcX < X){
+            int delta = X - srcX;
+            if(delta >= width) {
+                return;
+            }
+            srcW -= delta;
+            srcX += delta;
+            srcOff += delta;
+        }
+
+        if(srcX + srcW > X + width){
+            srcW = X + width - srcX;
+            if(srcW <= 0) {
+                return;
+            }
+        }
+        if(scanline == 0) {
+            scanline = width;
+        }
+        int realOff = offset + (srcY - Y) * scanline + (srcX - X);
+        switch(dataType){
+        case DATA_TYPE_UNDEFINED:
+            cm = model;
+            if(model != ColorModel.getRGBdefault()){
+                bData = new byte[width * height];
+                isRGB = false;
+                dataType = DATA_TYPE_BYTE;
+            }else{
+                iData = new int[width * height];
+                isRGB = true;
+                dataType = DATA_TYPE_INT;
+            }
+        case DATA_TYPE_BYTE:
+            if(!isRGB && cm == model){
+                for(int y = 0; y < srcH; y++){
+                    System.arraycopy(pixels, srcOff, bData, realOff, srcW);
+                    srcOff += srcScan;
+                    realOff += scanline;
+                }
+                break;
+            }
+            forceToRGB();
+        case DATA_TYPE_INT:
+            for(int y = 0; y < srcH; y++){
+                for(int x = 0; x < srcW; x++){
+                    iData[realOff + x] = cm.getRGB(pixels[srcOff + x] & 0xff);                    
+                }
+                srcOff += srcScan;
+                realOff += scanline;
+            }
+        }
+
+        return;
+    }
+
+    public void setPixels(int srcX, int srcY, int srcW, int srcH,
+            ColorModel model, int[] pixels, int srcOff, int srcScan) {
+
+        if(srcY < Y){
+            int delta = Y - srcY;
+            if(delta >= height) {
+                return;
+            }
+            srcY += delta;
+            srcH -= delta;
+            srcOff += srcScan * delta;
+        }
+
+        if(srcY + srcH > Y + height){
+            srcH = Y + height - srcY;
+            if(srcH <= 0) {
+                return;
+            }
+        }
+
+        if(srcX < X){
+            int delta = X - srcX;
+            if(delta >= width) {
+                return;
+            }
+            srcW -= delta;
+            srcX += delta;
+            srcOff += delta;
+        }
+
+        if(srcX + srcW > X + width){
+            srcW = X + width - srcX;
+            if(srcW <= 0) {
+                return;
+            }
+        }
+        if(scanline == 0) {
+            scanline = width;
+        }
+        int realOff = offset + (srcY - Y) * scanline + (srcX - X);
+
+        int mask = 0xFF;
+
+        switch(dataType){
+        case DATA_TYPE_UNDEFINED:
+            cm = model;
+            iData = new int[width * height];
+            dataType = DATA_TYPE_INT;
+            isRGB = (cm == ColorModel.getRGBdefault());
+
+        case DATA_TYPE_INT:
+            if(cm == model){
+                for(int y = 0; y < srcH; y++){
+                    System.arraycopy(pixels, srcOff, iData, realOff, srcW);
+                    srcOff += srcScan;
+                    realOff += scanline;
+                }
+                break;
+            }
+            mask = 0xFFFFFFFF;
+
+        case DATA_TYPE_BYTE:
+            forceToRGB();
+            for(int y = 0; y < srcH; y++){
+                for(int x = 0; x < srcW; x++){
+                    iData[realOff+x] = cm.getRGB(pixels[srcOff+x] & mask);
+                }
+                srcOff += srcScan;
+                realOff += scanline;
+            }
+        }
+    }
+
+    public synchronized ColorModel getColorModel() {
+        return cm;
+    }
+
+    public synchronized boolean grabPixels(long ms) 
+    throws InterruptedException {
+        if((grabberStatus & GRABBING_STOP) != 0){
+            return ((grabberStatus & ALL_BITS) != 0);
+        }
+
+        long start = System.currentTimeMillis();
+
+        if(!isGrabbing){
+            isGrabbing = true;
+            grabberStatus &= ~ImageObserver.ABORT;
+            producer.startProduction(this);
+        }
+        while((grabberStatus & GRABBING_STOP) == 0){
+            if(ms != 0){
+                ms = start + ms - System.currentTimeMillis();
+                if(ms <= 0) {
+                    break;
+                }
+            }
+            wait(ms);
+        }
+
+        return ((grabberStatus & ALL_BITS) != 0);
+    }
+
+    public void setDimensions(int w, int h) {
+        if(width < 0) {
+            width = w - X;
+        }
+        if(height < 0) {
+            height = h - Y;
+        }
+
+        grabberStatus |= ImageObserver.WIDTH | ImageObserver.HEIGHT;
+
+        if(width <=0 || height <=0){
+            imageComplete(STATICIMAGEDONE);
+            return;
+        }
+
+        if(isRGB && dataType == DATA_TYPE_UNDEFINED){
+            iData = new int[width * height];
+            dataType = DATA_TYPE_INT;
+            scanline = width;
+        }
+    }
+
+    public void setHints(int hints) {
+        return;
+    }
+
+    public synchronized void imageComplete(int status) {
+        switch(status){
+        case IMAGEABORTED:
+            grabberStatus |= ImageObserver.ABORT;
+            break;
+        case IMAGEERROR:
+            grabberStatus |= ImageObserver.ERROR | ImageObserver.ABORT;
+            break;
+        case SINGLEFRAMEDONE:
+            grabberStatus |= ImageObserver.FRAMEBITS;
+            break;
+        case STATICIMAGEDONE:
+            grabberStatus |= ImageObserver.ALLBITS;
+            break;
+        default:
+            // awt.26A=Incorrect ImageConsumer completion status
+            throw new IllegalArgumentException(Messages.getString("awt.26A")); //$NON-NLS-1$
+        }
+        isGrabbing = false;
+        producer.removeConsumer(this);
+        notifyAll();
+    }
+
+    public boolean grabPixels() throws InterruptedException {
+        return grabPixels(0);
+    }
+
+    public synchronized void startGrabbing() {
+        if((grabberStatus & GRABBING_STOP) != 0){
+            return;
+        }
+        if(!isGrabbing){
+            isGrabbing = true;
+            grabberStatus &= ~ImageObserver.ABORT;
+            producer.startProduction(this);
+        }
+    }
+
+    public synchronized void abortGrabbing() {
+        imageComplete(IMAGEABORTED);
+    }
+
+    public synchronized int status() {
+        return grabberStatus;
+    }
+
+    public synchronized int getWidth() {
+        if(width < 0) {
+            return -1;
+        }
+        return width;
+    }
+
+    public synchronized int getStatus() {
+        return grabberStatus;
+    }
+
+    public synchronized int getHeight() {
+        if(height < 0) {
+            return -1;
+        }
+        return height;
+    }
+
+    private void initialize(ImageProducer ip, int x, int y, int w, int h,
+            int pixels[], int off, int scansize, boolean forceRGB){
+
+        producer = ip;
+        X = x;
+        Y = y;
+        width = w;
+        height = h;
+        iData = pixels;
+        dataType = (pixels == null) ? DATA_TYPE_UNDEFINED : DATA_TYPE_INT;
+        offset = off;
+        scanline = scansize;
+        if(forceRGB){
+            cm = ColorModel.getRGBdefault();
+            isRGB = true;
+        }
+    }
+
+    /**
+     * Force pixels to INT RGB mode
+     */
+    private void forceToRGB(){
+        if (isRGB)
+            return;
+    
+        switch(dataType){
+        case DATA_TYPE_BYTE:
+            iData = new int[width * height];
+            for(int i = 0; i < iData.length; i++){
+                iData[i] = cm.getRGB(bData[i] & 0xff);
+            }
+            dataType = DATA_TYPE_INT;
+            bData = null;
+            break;
+
+        case DATA_TYPE_INT:
+            int buff[] = new int[width * height];
+            for(int i = 0; i < iData.length; i++){
+                buff[i] = cm.getRGB(iData[i]);
+            }
+            iData = buff;
+            break;
+        }
+        offset = 0;
+        scanline = width;
+        cm = ColorModel.getRGBdefault();
+        isRGB = true;
+    }
+
+}
diff --git a/awt/java/awt/image/PixelInterleavedSampleModel.java b/awt/java/awt/image/PixelInterleavedSampleModel.java
new file mode 100644
index 0000000..8e646f8
--- /dev/null
+++ b/awt/java/awt/image/PixelInterleavedSampleModel.java
@@ -0,0 +1,134 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The PixelInterleavedSampleModel class represents image data as represented as
+ * interleaved pixels and for which each sample of a pixel takes one data
+ * element of the DataBuffer.
+ * 
+ * @since Android 1.0
+ */
+public class PixelInterleavedSampleModel extends ComponentSampleModel {
+
+    /**
+     * Instantiates a new PixelInterleavedSampleModel with the specified
+     * parameters.
+     * 
+     * @param dataType
+     *            the data type of the samples.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param pixelStride
+     *            the pixel stride of the image data.
+     * @param scanlineStride
+     *            the scanline stride of the of the image data.
+     * @param bandOffsets
+     *            the array of the band offsets.
+     */
+    public PixelInterleavedSampleModel(int dataType, int w, int h, int pixelStride,
+            int scanlineStride, int bandOffsets[]) {
+
+        super(dataType, w, h, pixelStride, scanlineStride, bandOffsets);
+
+        int maxOffset = bandOffsets[0];
+        int minOffset = bandOffsets[0];
+        for (int i = 1; i < bandOffsets.length; i++) {
+            if (bandOffsets[i] > maxOffset) {
+                maxOffset = bandOffsets[i];
+            }
+            if (bandOffsets[i] < minOffset) {
+                minOffset = bandOffsets[i];
+            }
+        }
+
+        maxOffset -= minOffset;
+
+        if (maxOffset > scanlineStride) {
+            // awt.241=Any offset between bands is greater than the Scanline
+            // stride
+            throw new IllegalArgumentException(Messages.getString("awt.241")); //$NON-NLS-1$
+        }
+
+        if (maxOffset > pixelStride) {
+            // awt.242=Pixel stride is less than any offset between bands
+            throw new IllegalArgumentException(Messages.getString("awt.242")); //$NON-NLS-1$
+        }
+
+        if (pixelStride * w > scanlineStride) {
+            // awt.243=Product of Pixel stride and w is greater than Scanline
+            // stride
+            throw new IllegalArgumentException(Messages.getString("awt.243")); //$NON-NLS-1$
+        }
+
+    }
+
+    @Override
+    public SampleModel createSubsetSampleModel(int bands[]) {
+        int newOffsets[] = new int[bands.length];
+        for (int i = 0; i < bands.length; i++) {
+            newOffsets[i] = bandOffsets[bands[i]];
+        }
+
+        return new PixelInterleavedSampleModel(dataType, width, height, pixelStride,
+                scanlineStride, newOffsets);
+    }
+
+    @Override
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+        int newOffsets[];
+        int minOffset = bandOffsets[0];
+
+        for (int i = 1; i < numBands; i++) {
+            if (bandOffsets[i] < minOffset) {
+                minOffset = bandOffsets[i];
+            }
+        }
+
+        if (minOffset > 0) {
+            newOffsets = new int[numBands];
+            for (int i = 0; i < numBands; i++) {
+                newOffsets[i] = bandOffsets[i] - minOffset;
+            }
+        } else {
+            newOffsets = bandOffsets;
+        }
+
+        return new PixelInterleavedSampleModel(dataType, w, h, pixelStride, pixelStride * w,
+                newOffsets);
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = super.hashCode();
+        int tmp = hash >>> 8;
+        hash <<= 8;
+        hash |= tmp;
+
+        return hash ^ 0x66;
+    }
+
+}
diff --git a/awt/java/awt/image/RGBImageFilter.java b/awt/java/awt/image/RGBImageFilter.java
new file mode 100644
index 0000000..f5fe5d9
--- /dev/null
+++ b/awt/java/awt/image/RGBImageFilter.java
@@ -0,0 +1,195 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+/**
+ * The RGBImageFilter class represents a filter which modifies pixels of an
+ * image in the default RGB ColorModel.
+ * 
+ * @since Android 1.0
+ */
+public abstract class RGBImageFilter extends ImageFilter {
+
+    /**
+     * The original model is the ColorModel to be replaced by the new model when
+     * substituteColorModel is called.
+     */
+    protected ColorModel origmodel;
+
+    /**
+     * The new model is the ColorModel with which to replace the original model
+     * when substituteColorModel is called.
+     */
+    protected ColorModel newmodel;
+
+    /**
+     * The canFilterIndexColorModel indicates if it is acceptable to apply the
+     * color filtering of the filterRGB method to the color table entries of an
+     * IndexColorModel object.
+     */
+    protected boolean canFilterIndexColorModel;
+
+    /**
+     * Instantiates a new RGBImageFilter.
+     */
+    public RGBImageFilter() {
+    }
+
+    /**
+     * Filters an IndexColorModel object by calling filterRGB function for each
+     * entry of IndexColorModel.
+     * 
+     * @param icm
+     *            the IndexColorModel to be filtered.
+     * @return the IndexColorModel.
+     */
+    public IndexColorModel filterIndexColorModel(IndexColorModel icm) {
+        int transferType = icm.getTransferType();
+        int bits = icm.getPixelSize();
+        int mapSize = icm.getMapSize();
+        int colorMap[] = new int[mapSize];
+        int filteredColorMap[] = new int[mapSize];
+        icm.getRGBs(colorMap);
+        int trans = -1;
+        boolean hasAlpha = false;
+        for (int i = 0; i < mapSize; i++) {
+            filteredColorMap[i] = filterRGB(-1, -1, colorMap[i]);
+            int alpha = filteredColorMap[i] >>> 24;
+            if (alpha != 0xff) {
+                if (!hasAlpha) {
+                    hasAlpha = true;
+                }
+                if (alpha == 0 && trans < 0) {
+                    trans = i;
+                }
+            }
+        }
+
+        return new IndexColorModel(bits, mapSize, filteredColorMap, 0, hasAlpha, trans,
+                transferType);
+    }
+
+    /**
+     * Replaces the original color model and the new one.
+     * 
+     * @param oldcm
+     *            the old ColorModel.
+     * @param newcm
+     *            the new ColorModel.
+     */
+    public void substituteColorModel(ColorModel oldcm, ColorModel newcm) {
+        origmodel = oldcm;
+        newmodel = newcm;
+    }
+
+    @Override
+    public void setColorModel(ColorModel model) {
+        if (model instanceof IndexColorModel && canFilterIndexColorModel) {
+            IndexColorModel icm = (IndexColorModel)model;
+            ColorModel filteredModel = filterIndexColorModel(icm);
+            substituteColorModel(model, filteredModel);
+            consumer.setColorModel(filteredModel);
+        } else {
+            consumer.setColorModel(ColorModel.getRGBdefault());
+        }
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off,
+            int scansize) {
+
+        if (model == null || model == origmodel) {
+            consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize);
+        } else {
+            int rgbPixels[] = new int[w];
+            for (int sy = y, pixelsOff = off; sy < y + h; sy++, pixelsOff += scansize) {
+
+                for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+                    rgbPixels[idx] = model.getRGB(pixels[pixelsOff + idx]);
+                }
+                filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w);
+            }
+        }
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off,
+            int scansize) {
+
+        if (model == null || model == origmodel) {
+            consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize);
+        } else {
+            int rgbPixels[] = new int[w];
+            for (int sy = y, pixelsOff = off; sy < y + h; sy++, pixelsOff += scansize) {
+
+                for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+                    rgbPixels[idx] = model.getRGB(pixels[pixelsOff + idx] & 0xff);
+                }
+                filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w);
+            }
+        }
+    }
+
+    /**
+     * Filters a region of pixels in the default RGB ColorModel by calling the
+     * filterRGB method for them.
+     * 
+     * @param x
+     *            the X coordinate of region.
+     * @param y
+     *            the Y coordinate of region.
+     * @param w
+     *            the width of region.
+     * @param h
+     *            the height of region.
+     * @param pixels
+     *            the pixels array.
+     * @param off
+     *            the offset of array.
+     * @param scansize
+     *            the distance between rows of pixels in the array.
+     */
+    public void filterRGBPixels(int x, int y, int w, int h, int[] pixels, int off, int scansize) {
+
+        for (int sy = y, lineOff = off; sy < y + h; sy++, lineOff += scansize) {
+            for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+                pixels[lineOff + idx] = filterRGB(sx, sy, pixels[lineOff + idx]);
+            }
+        }
+        consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), pixels, off, scansize);
+    }
+
+    /**
+     * Converts a single input pixel in the default RGB ColorModel to a single
+     * output pixel.
+     * 
+     * @param x
+     *            the X pixel's coordinate.
+     * @param y
+     *            the Y pixel's coordinate.
+     * @param rgb
+     *            a pixel in the default RGB color model.
+     * @return a filtered pixel in the default RGB color model.
+     */
+    public abstract int filterRGB(int x, int y, int rgb);
+
+}
diff --git a/awt/java/awt/image/Raster.java b/awt/java/awt/image/Raster.java
new file mode 100644
index 0000000..6749fde
--- /dev/null
+++ b/awt/java/awt/image/Raster.java
@@ -0,0 +1,1515 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+
+import org.apache.harmony.awt.gl.image.OrdinaryWritableRaster;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Raster class represents a rectangular area of pixels. This class is
+ * defined by DataBuffer and SampleModel objects. The DataBuffer object stores
+ * sample values and DSampleModel defines the location of sample in this
+ * DataBuffer.
+ * 
+ * @since Android 1.0
+ */
+public class Raster {
+
+    /**
+     * The DataBuffer of this Raster.
+     */
+    protected DataBuffer dataBuffer;
+
+    /**
+     * The height of this Raster.
+     */
+    protected int height;
+
+    /**
+     * The X coordinate of the upper left pixel in this Raster.
+     */
+    protected int minX;
+
+    /**
+     * The Y coordinate of the upper left pixel in this Raster.
+     */
+    protected int minY;
+
+    /**
+     * The number of bands in this Raster.
+     */
+    protected int numBands;
+
+    /**
+     * The number of data elements.
+     */
+    protected int numDataElements;
+
+    /**
+     * The parent of this Raster.
+     */
+    protected Raster parent;
+
+    /**
+     * The SampleModel of this Raster.
+     */
+    protected SampleModel sampleModel;
+
+    /**
+     * The X translation from the coordinate space of the SampleModel of this
+     * Raster.
+     */
+    protected int sampleModelTranslateX;
+
+    /**
+     * The Y translation from the coordinate space of the SampleModel of this
+     * Raster.
+     */
+    protected int sampleModelTranslateY;
+
+    /**
+     * The width of this Raster.
+     */
+    protected int width;
+
+    /**
+     * Creates a Raster object with a BandedSampleModel and the specified
+     * DataBuffer. The number of bands is defined by the length of bandOffsets
+     * or bankIndices arrays.
+     * 
+     * @param dataBuffer
+     *            the specified DataBuffer.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param scanlineStride
+     *            the scanline stride of the image data.
+     * @param bankIndices
+     *            the bank indices of bands.
+     * @param bandOffsets
+     *            the band offsets of bands.
+     * @param location
+     *            the location which defines the upper left corner of Raster.
+     * @return the WritableRaster object.
+     */
+    public static WritableRaster createBandedRaster(DataBuffer dataBuffer, int w, int h,
+            int scanlineStride, int bankIndices[], int bandOffsets[], Point location) {
+
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) {
+            // awt.276=location.x + w or location.y + h results in integer
+            // overflow
+            throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+        }
+
+        if (bankIndices == null || bandOffsets == null) {
+            // awt.277=bankIndices or bandOffsets is null
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$
+        }
+
+        if (dataBuffer == null) {
+            // awt.278=dataBuffer is null
+            throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$
+        }
+
+        int dataType = dataBuffer.getDataType();
+
+        if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT
+                && dataType != DataBuffer.TYPE_INT) {
+            // awt.230=dataType is not one of the supported data types
+            throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+        }
+
+        BandedSampleModel sampleModel = new BandedSampleModel(dataType, w, h, scanlineStride,
+                bankIndices, bandOffsets);
+
+        return new OrdinaryWritableRaster(sampleModel, dataBuffer, location);
+    }
+
+    /**
+     * Creates a Raster object with a BandedSampleModel and the specified data
+     * type. The Data type can be one of the following values: TYPE_BYTE,
+     * TYPE_USHORT, or TYPE_INT.
+     * 
+     * @param dataType
+     *            the data type of the samples: TYPE_BYTE, TYPE_USHORT, or
+     *            TYPE_INT.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param scanlineStride
+     *            the scanline stride of the image data.
+     * @param bankIndices
+     *            the bank indices of bands.
+     * @param bandOffsets
+     *            the band offsets of bands.
+     * @param location
+     *            the location which defines the upper left corner of the
+     *            Raster.
+     * @return the WritableRaster object.
+     */
+    public static WritableRaster createBandedRaster(int dataType, int w, int h, int scanlineStride,
+            int bankIndices[], int bandOffsets[], Point location) {
+
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) {
+            // awt.276=location.x + w or location.y + h results in integer
+            // overflow
+            throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+        }
+
+        if (bankIndices == null || bandOffsets == null) {
+            // awt.277=bankIndices or bandOffsets is null
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$
+        }
+
+        if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT
+                && dataType != DataBuffer.TYPE_INT) {
+            // awt.230=dataType is not one of the supported data types
+            throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+        }
+
+        int maxOffset = bandOffsets[0];
+        int maxBank = bankIndices[0];
+
+        for (int i = 0; i < bankIndices.length; i++) {
+            if (bandOffsets[i] > maxOffset) {
+                maxOffset = bandOffsets[i];
+            }
+            if (bankIndices[i] > maxBank) {
+                maxBank = bankIndices[i];
+            }
+        }
+
+        int numBanks = maxBank + 1;
+        int dataSize = scanlineStride * (h - 1) + w + maxOffset;
+
+        DataBuffer data = null;
+
+        switch (dataType) {
+            case DataBuffer.TYPE_BYTE:
+                data = new DataBufferByte(dataSize, numBanks);
+                break;
+            case DataBuffer.TYPE_USHORT:
+                data = new DataBufferUShort(dataSize, numBanks);
+                break;
+            case DataBuffer.TYPE_INT:
+                data = new DataBufferInt(dataSize, numBanks);
+                break;
+        }
+        return createBandedRaster(data, w, h, scanlineStride, bankIndices, bandOffsets, location);
+    }
+
+    /**
+     * Creates a Raster object with a BandedSampleModel and the specified data
+     * type. The Data type can be one of the following values: TYPE_BYTE,
+     * TYPE_USHORT, or TYPE_INT.
+     * 
+     * @param dataType
+     *            the data type of the samples: TYPE_BYTE, TYPE_USHORT, or
+     *            TYPE_INT.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param bands
+     *            the number of bands.
+     * @param location
+     *            the location which defines the upper left corner of the
+     *            Raster.
+     * @return the WritableRaster object.
+     */
+    public static WritableRaster createBandedRaster(int dataType, int w, int h, int bands,
+            Point location) {
+
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) {
+            // awt.276=location.x + w or location.y + h results in integer
+            // overflow
+            throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+        }
+
+        if (bands < 1) {
+            // awt.279=bands is less than 1
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.279")); //$NON-NLS-1$
+        }
+
+        int bandOffsets[] = new int[bands];
+        int bankIndices[] = new int[bands];
+
+        for (int i = 0; i < bands; i++) {
+            bandOffsets[i] = 0;
+            bankIndices[i] = i;
+        }
+        return createBandedRaster(dataType, w, h, w, bankIndices, bandOffsets, location);
+    }
+
+    /**
+     * Creates a Raster object with a PixelInterleavedSampleModel and the
+     * specified DataBuffer.
+     * 
+     * @param dataBuffer
+     *            the DataBuffer.
+     * @param w
+     *            the width of image data.
+     * @param h
+     *            the height of image data.
+     * @param scanlineStride
+     *            the scanline stride of the image data.
+     * @param pixelStride
+     *            the pixel stride of image data.
+     * @param bandOffsets
+     *            the band offsets of bands.
+     * @param location
+     *            the location which defines the upper left corner of the
+     *            Raster.
+     * @return the WritableRaster object.
+     */
+    public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer, int w, int h,
+            int scanlineStride, int pixelStride, int bandOffsets[], Point location) {
+
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) {
+            // awt.276=location.x + w or location.y + h results in integer
+            // overflow
+            throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+        }
+
+        if (dataBuffer == null) {
+            // awt.278=dataBuffer is null
+            throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$
+        }
+
+        int dataType = dataBuffer.getDataType();
+        if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT) {
+            // awt.230=dataType is not one of the supported data types
+            throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+        }
+
+        if (dataBuffer.getNumBanks() > 1) {
+            // awt.27A=dataBuffer has more than one bank
+            throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$
+        }
+
+        if (bandOffsets == null) {
+            // awt.27B=bandOffsets is null
+            throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$
+        }
+
+        PixelInterleavedSampleModel sampleModel = new PixelInterleavedSampleModel(dataType, w, h,
+                pixelStride, scanlineStride, bandOffsets);
+
+        return new OrdinaryWritableRaster(sampleModel, dataBuffer, location);
+
+    }
+
+    /**
+     * Creates a Raster object with a PixelInterleavedSampleModel and the
+     * specified data type. The Data type can be one of the following values:
+     * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+     * 
+     * @param dataType
+     *            the data type of the samples: TYPE_BYTE, TYPE_USHORT, or
+     *            TYPE_INT.
+     * @param w
+     *            the width of image data.
+     * @param h
+     *            the height of image data.
+     * @param scanlineStride
+     *            the scanline stride of the image data.
+     * @param pixelStride
+     *            the pixel stride of image data.
+     * @param bandOffsets
+     *            the band offsets of bands.
+     * @param location
+     *            the location which defines the upper left corner of the
+     *            Raster.
+     * @return the WritableRaster object.
+     */
+    public static WritableRaster createInterleavedRaster(int dataType, int w, int h,
+            int scanlineStride, int pixelStride, int bandOffsets[], Point location) {
+
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) {
+            // awt.276=location.x + w or location.y + h results in integer
+            // overflow
+            throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+        }
+
+        if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT) {
+            // awt.230=dataType is not one of the supported data types
+            throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+        }
+
+        if (bandOffsets == null) {
+            // awt.27B=bandOffsets is null
+            throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$
+        }
+
+        int minOffset = bandOffsets[0];
+        for (int i = 1; i < bandOffsets.length; i++) {
+            if (bandOffsets[i] < minOffset) {
+                minOffset = bandOffsets[i];
+            }
+        }
+        int size = (h - 1) * scanlineStride + w * pixelStride + minOffset;
+        DataBuffer data = null;
+
+        switch (dataType) {
+            case DataBuffer.TYPE_BYTE:
+                data = new DataBufferByte(size);
+                break;
+            case DataBuffer.TYPE_USHORT:
+                data = new DataBufferUShort(size);
+                break;
+        }
+
+        return createInterleavedRaster(data, w, h, scanlineStride, pixelStride, bandOffsets,
+                location);
+    }
+
+    /**
+     * Creates a Raster object with a PixelInterleavedSampleModel and the
+     * specified data type. The Data type can be one of the following values:
+     * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+     * 
+     * @param dataType
+     *            the data type of samples: TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+     * @param w
+     *            the width of image data.
+     * @param h
+     *            the height of image data.
+     * @param bands
+     *            the number of bands.
+     * @param location
+     *            the location which defines the upper left corner of the
+     *            Raster.
+     * @return the WritableRaster.
+     */
+    public static WritableRaster createInterleavedRaster(int dataType, int w, int h, int bands,
+            Point location) {
+
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) {
+            // awt.276=location.x + w or location.y + h results in integer
+            // overflow
+            throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+        }
+
+        if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT) {
+            // awt.230=dataType is not one of the supported data types
+            throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+        }
+
+        int bandOffsets[] = new int[bands];
+        for (int i = 0; i < bands; i++) {
+            bandOffsets[i] = i;
+        }
+
+        return createInterleavedRaster(dataType, w, h, w * bands, bands, bandOffsets, location);
+    }
+
+    /**
+     * Creates a Raster object with a SinglePixelPackedSampleModel and the
+     * specified DataBuffer.
+     * 
+     * @param dataBuffer
+     *            the DataBuffer.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param scanlineStride
+     *            the scanline stride of the image data.
+     * @param bandMasks
+     *            the band masks.
+     * @param location
+     *            the location which defines the upper left corner of the
+     *            Raster.
+     * @return the WritableRaster.
+     */
+    public static WritableRaster createPackedRaster(DataBuffer dataBuffer, int w, int h,
+            int scanlineStride, int bandMasks[], Point location) {
+        if (dataBuffer == null) {
+            // awt.278=dataBuffer is null
+            throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$
+        }
+
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) {
+            // awt.276=location.x + w or location.y + h results in integer
+            // overflow
+            throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+        }
+
+        if (bandMasks == null) {
+            // awt.27C=bandMasks is null
+            throw new RasterFormatException(Messages.getString("awt.27C")); //$NON-NLS-1$
+        }
+
+        if (dataBuffer.getNumBanks() > 1) {
+            // awt.27A=dataBuffer has more than one bank
+            throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$
+        }
+
+        int dataType = dataBuffer.getDataType();
+        if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT
+                && dataType != DataBuffer.TYPE_INT) {
+            // awt.230=dataType is not one of the supported data types
+            throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+        }
+
+        SinglePixelPackedSampleModel sampleModel = new SinglePixelPackedSampleModel(dataType, w, h,
+                scanlineStride, bandMasks);
+
+        return new OrdinaryWritableRaster(sampleModel, dataBuffer, location);
+    }
+
+    /**
+     * Creates a Raster object with a MultiPixelPackedSampleModel and the
+     * specified DataBuffer.
+     * 
+     * @param dataBuffer
+     *            the DataBuffer.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param bitsPerPixel
+     *            the number of bits per pixel.
+     * @param location
+     *            the location which defines the upper left corner of the
+     *            Raster.
+     * @return the WritableRaster.
+     */
+    public static WritableRaster createPackedRaster(DataBuffer dataBuffer, int w, int h,
+            int bitsPerPixel, Point location) {
+
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) {
+            // awt.276=location.x + w or location.y + h results in integer
+            // overflow
+            throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+        }
+
+        if (dataBuffer == null) {
+            // awt.278=dataBuffer is null
+            throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$
+        }
+
+        if (dataBuffer.getNumBanks() > 1) {
+            // awt.27A=dataBuffer has more than one bank
+            throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$
+        }
+
+        int dataType = dataBuffer.getDataType();
+        if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT
+                && dataType != DataBuffer.TYPE_INT) {
+            // awt.230=dataType is not one of the supported data types
+            throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+        }
+
+        MultiPixelPackedSampleModel sampleModel = new MultiPixelPackedSampleModel(dataType, w, h,
+                bitsPerPixel);
+
+        return new OrdinaryWritableRaster(sampleModel, dataBuffer, location);
+
+    }
+
+    /**
+     * Creates a Raster object with a MultiPixelPackedSampleModel and the
+     * specified DataBuffer.
+     * 
+     * @param dataType
+     *            the data type of samples: TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param bands
+     *            the number of bands.
+     * @param bitsPerBand
+     *            the number of bits per band.
+     * @param location
+     *            the location which defines the upper left corner of the
+     *            Raster.
+     * @return the WritableRaster.
+     */
+    public static WritableRaster createPackedRaster(int dataType, int w, int h, int bands,
+            int bitsPerBand, Point location) {
+
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) {
+            // awt.276=location.x + w or location.y + h results in integer
+            // overflow
+            throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+        }
+
+        if (bands < 1 || bitsPerBand < 1) {
+            // awt.27D=bitsPerBand or bands is not greater than zero
+            throw new IllegalArgumentException(Messages.getString("awt.27D")); //$NON-NLS-1$
+        }
+
+        if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT
+                && dataType != DataBuffer.TYPE_INT) {
+            // awt.230=dataType is not one of the supported data types
+            throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+        }
+
+        if (bitsPerBand * bands > DataBuffer.getDataTypeSize(dataType)) {
+            // awt.27E=The product of bitsPerBand and bands is greater than the
+            // number of bits held by dataType
+            throw new IllegalArgumentException(Messages.getString("awt.27E")); //$NON-NLS-1$
+        }
+
+        if (bands > 1) {
+
+            int bandMasks[] = new int[bands];
+            int mask = (1 << bitsPerBand) - 1;
+
+            for (int i = 0; i < bands; i++) {
+                bandMasks[i] = mask << (bitsPerBand * (bands - 1 - i));
+            }
+
+            return createPackedRaster(dataType, w, h, bandMasks, location);
+        }
+        DataBuffer data = null;
+        int size = ((bitsPerBand * w + DataBuffer.getDataTypeSize(dataType) - 1) / DataBuffer
+                .getDataTypeSize(dataType))
+                * h;
+
+        switch (dataType) {
+            case DataBuffer.TYPE_BYTE:
+                data = new DataBufferByte(size);
+                break;
+            case DataBuffer.TYPE_USHORT:
+                data = new DataBufferUShort(size);
+                break;
+            case DataBuffer.TYPE_INT:
+                data = new DataBufferInt(size);
+                break;
+        }
+        return createPackedRaster(data, w, h, bitsPerBand, location);
+    }
+
+    /**
+     * Creates a Raster object with a SinglePixelPackedSampleModel and the
+     * specified DataBuffer.
+     * 
+     * @param dataType
+     *            the data type of samples: TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param bandMasks
+     *            the band masks.
+     * @param location
+     *            the location which defines the upper left corner of the
+     *            Raster.
+     * @return the WritableRaster.
+     */
+    public static WritableRaster createPackedRaster(int dataType, int w, int h, int bandMasks[],
+            Point location) {
+
+        if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT
+                && dataType != DataBuffer.TYPE_INT) {
+            // awt.230=dataType is not one of the supported data types
+            throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+        }
+
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) {
+            // awt.276=location.x + w or location.y + h results in integer
+            // overflow
+            throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+        }
+
+        if (bandMasks == null) {
+            // awt.27C=bandMasks is null
+            throw new NullPointerException(Messages.getString("awt.27C")); //$NON-NLS-1$
+        }
+
+        DataBuffer data = null;
+
+        switch (dataType) {
+            case DataBuffer.TYPE_BYTE:
+                data = new DataBufferByte(w * h);
+                break;
+            case DataBuffer.TYPE_USHORT:
+                data = new DataBufferUShort(w * h);
+                break;
+            case DataBuffer.TYPE_INT:
+                data = new DataBufferInt(w * h);
+                break;
+        }
+
+        return createPackedRaster(data, w, h, w, bandMasks, location);
+    }
+
+    /**
+     * Creates a Raster object with the specified DataBuffer and SampleModel.
+     * 
+     * @param sm
+     *            the specified SampleModel.
+     * @param db
+     *            the specified DataBuffer.
+     * @param location
+     *            the location which defines the upper left corner of the
+     *            Raster.
+     * @return the Raster.
+     */
+    public static Raster createRaster(SampleModel sm, DataBuffer db, Point location) {
+
+        if (sm == null || db == null) {
+            // awt.27F=SampleModel or DataBuffer is null
+            throw new NullPointerException(Messages.getString("awt.27F")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        return new Raster(sm, db, location);
+    }
+
+    /**
+     * Creates a WritableRaster with the specified SampleModel and DataBuffer.
+     * 
+     * @param sm
+     *            the specified SampleModel.
+     * @param db
+     *            the specified DataBuffer.
+     * @param location
+     *            the location which defines the upper left corner of the
+     *            Raster.
+     * @return the WritableRaster.
+     */
+    public static WritableRaster createWritableRaster(SampleModel sm, DataBuffer db, Point location) {
+
+        if (sm == null || db == null) {
+            // awt.27F=SampleModel or DataBuffer is null
+            throw new NullPointerException(Messages.getString("awt.27F")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        return new OrdinaryWritableRaster(sm, db, location);
+    }
+
+    /**
+     * Creates a WritableRaster with the specified SampleModel.
+     * 
+     * @param sm
+     *            the specified SampleModel.
+     * @param location
+     *            the location which defines the upper left corner of the
+     *            Raster.
+     * @return the WritableRaster.
+     */
+    public static WritableRaster createWritableRaster(SampleModel sm, Point location) {
+
+        if (sm == null) {
+            // awt.280=SampleModel is null
+            throw new NullPointerException(Messages.getString("awt.280")); //$NON-NLS-1$
+        }
+
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+
+        return createWritableRaster(sm, sm.createDataBuffer(), location);
+    }
+
+    /**
+     * Instantiates a new Raster object with the specified SampleModel and
+     * DataBuffer.
+     * 
+     * @param sampleModel
+     *            the specified SampleModel.
+     * @param dataBuffer
+     *            the specified DataBuffer.
+     * @param origin
+     *            the specified origin.
+     */
+    protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, Point origin) {
+
+        this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.getWidth(),
+                sampleModel.getHeight()), origin, null);
+    }
+
+    /**
+     * Instantiates a new Raster object with the specified SampleModel,
+     * DataBuffer, rectangular region and parent Raster.
+     * 
+     * @param sampleModel
+     *            the specified SampleModel.
+     * @param dataBuffer
+     *            the specified DataBuffer.
+     * @param aRegion
+     *            the a rectangular region which defines the new image bounds.
+     * @param sampleModelTranslate
+     *            this point defines the translation point from the SampleModel
+     *            coordinates to the new Raster coordinates.
+     * @param parent
+     *            the parent of this Raster.
+     */
+    protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, Rectangle aRegion,
+            Point sampleModelTranslate, Raster parent) {
+
+        if (sampleModel == null || dataBuffer == null || aRegion == null
+                || sampleModelTranslate == null) {
+            // awt.281=sampleModel, dataBuffer, aRegion or sampleModelTranslate
+            // is null
+            throw new NullPointerException(Messages.getString("awt.281")); //$NON-NLS-1$
+        }
+
+        if (aRegion.width <= 0 || aRegion.height <= 0) {
+            // awt.282=aRegion has width or height less than or equal to zero
+            throw new RasterFormatException(Messages.getString("awt.282")); //$NON-NLS-1$
+        }
+
+        if ((long)aRegion.x + (long)aRegion.width > Integer.MAX_VALUE) {
+            // awt.283=Overflow X coordinate of Raster
+            throw new RasterFormatException(Messages.getString("awt.283")); //$NON-NLS-1$
+        }
+
+        if ((long)aRegion.y + (long)aRegion.height > Integer.MAX_VALUE) {
+            // awt.284=Overflow Y coordinate of Raster
+            throw new RasterFormatException(Messages.getString("awt.284")); //$NON-NLS-1$
+        }
+
+        if (sampleModel instanceof ComponentSampleModel) {
+            validateDataBuffer(dataBuffer, aRegion.width, aRegion.height,
+                    ((ComponentSampleModel)sampleModel).getScanlineStride());
+        } else if (sampleModel instanceof MultiPixelPackedSampleModel) {
+            validateDataBuffer(dataBuffer, aRegion.width, aRegion.height,
+                    ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride());
+        } else if (sampleModel instanceof SinglePixelPackedSampleModel) {
+            validateDataBuffer(dataBuffer, aRegion.width, aRegion.height,
+                    ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride());
+        }
+
+        this.sampleModel = sampleModel;
+        this.dataBuffer = dataBuffer;
+        this.minX = aRegion.x;
+        this.minY = aRegion.y;
+        this.width = aRegion.width;
+        this.height = aRegion.height;
+        this.sampleModelTranslateX = sampleModelTranslate.x;
+        this.sampleModelTranslateY = sampleModelTranslate.y;
+        this.parent = parent;
+        this.numBands = sampleModel.getNumBands();
+        this.numDataElements = sampleModel.getNumDataElements();
+
+    }
+
+    /**
+     * Instantiates a new Raster with the specified SampleModel.
+     * 
+     * @param sampleModel
+     *            the specified SampleModel.
+     * @param origin
+     *            the origin.
+     */
+    protected Raster(SampleModel sampleModel, Point origin) {
+        this(sampleModel, sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y,
+                sampleModel.getWidth(), sampleModel.getHeight()), origin, null);
+    }
+
+    /**
+     * Creates the child of this Raster by sharing the specified rectangular
+     * area in this raster. The parentX, parentY, width and height parameters
+     * specify the rectangular area to be shared.
+     * 
+     * @param parentX
+     *            the X coordinate of the upper left corner of this Raster.
+     * @param parentY
+     *            the Y coordinate of the upper left corner of this Raster.
+     * @param width
+     *            the width of the child area.
+     * @param height
+     *            the height of the child area.
+     * @param childMinX
+     *            the X coordinate of child area mapped to the parentX
+     *            coordinate.
+     * @param childMinY
+     *            the Y coordinate of child area mapped to the parentY
+     *            coordinate.
+     * @param bandList
+     *            the array of band indices.
+     * @return the Raster.
+     */
+    public Raster createChild(int parentX, int parentY, int width, int height, int childMinX,
+            int childMinY, int bandList[]) {
+        if (width <= 0 || height <= 0) {
+            // awt.285=Width or Height of child Raster is less than or equal to
+            // zero
+            throw new RasterFormatException(Messages.getString("awt.285")); //$NON-NLS-1$
+        }
+
+        if (parentX < this.minX || parentX + width > this.minX + this.width) {
+            // awt.286=parentX disposes outside Raster
+            throw new RasterFormatException(Messages.getString("awt.286")); //$NON-NLS-1$
+        }
+
+        if (parentY < this.minY || parentY + height > this.minY + this.height) {
+            // awt.287=parentY disposes outside Raster
+            throw new RasterFormatException(Messages.getString("awt.287")); //$NON-NLS-1$
+        }
+
+        if ((long)parentX + width > Integer.MAX_VALUE) {
+            // awt.288=parentX + width results in integer overflow
+            throw new RasterFormatException(Messages.getString("awt.288")); //$NON-NLS-1$
+        }
+
+        if ((long)parentY + height > Integer.MAX_VALUE) {
+            // awt.289=parentY + height results in integer overflow
+            throw new RasterFormatException(Messages.getString("awt.289")); //$NON-NLS-1$
+        }
+
+        if ((long)childMinX + width > Integer.MAX_VALUE) {
+            // awt.28A=childMinX + width results in integer overflow
+            throw new RasterFormatException(Messages.getString("awt.28A")); //$NON-NLS-1$
+        }
+
+        if ((long)childMinY + height > Integer.MAX_VALUE) {
+            // awt.28B=childMinY + height results in integer overflow
+            throw new RasterFormatException(Messages.getString("awt.28B")); //$NON-NLS-1$
+        }
+
+        SampleModel childModel;
+
+        if (bandList == null) {
+            childModel = sampleModel;
+        } else {
+            childModel = sampleModel.createSubsetSampleModel(bandList);
+        }
+
+        int childTranslateX = childMinX - parentX;
+        int childTranslateY = childMinY - parentY;
+
+        return new Raster(childModel, dataBuffer,
+                new Rectangle(childMinX, childMinY, width, height), new Point(childTranslateX
+                        + sampleModelTranslateX, childTranslateY + sampleModelTranslateY), this);
+    }
+
+    /**
+     * Create a compatible WritableRaster with the same parameters as this
+     * Raster.
+     * 
+     * @return the WritableRaster.
+     */
+    public WritableRaster createCompatibleWritableRaster() {
+        return new OrdinaryWritableRaster(sampleModel, new Point(0, 0));
+    }
+
+    /**
+     * Create a compatible WritableRaster with the same parameters as this
+     * Raster and the specified size.
+     * 
+     * @param w
+     *            the width of the new WritableRaster.
+     * @param h
+     *            the height of the new WritableRaster.
+     * @return the WritableRaster.
+     */
+    public WritableRaster createCompatibleWritableRaster(int w, int h) {
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        SampleModel sm = sampleModel.createCompatibleSampleModel(w, h);
+
+        return new OrdinaryWritableRaster(sm, new Point(0, 0));
+    }
+
+    /**
+     * Create a compatible WritableRaster with the same parameters as this
+     * Raster and the specified size and location.
+     * 
+     * @param x
+     *            the X coordinate of the new WritableRaster.
+     * @param y
+     *            the Y coordinate of the new WritableRaster.
+     * @param w
+     *            the width of the new WritableRaster.
+     * @param h
+     *            the height of the new WritableRaster.
+     * @return the WritableRaster.
+     */
+    public WritableRaster createCompatibleWritableRaster(int x, int y, int w, int h) {
+
+        WritableRaster raster = createCompatibleWritableRaster(w, h);
+
+        return raster.createWritableChild(0, 0, w, h, x, y, null);
+    }
+
+    /**
+     * Create a compatible WritableRaster with the same parameters as this
+     * Raster and the specified rectangle which determines new WritableRaster's
+     * location and size.
+     * 
+     * @param rect
+     *            the specified Rectangle.
+     * @return the WritableRaster.
+     */
+    public WritableRaster createCompatibleWritableRaster(Rectangle rect) {
+        if (rect == null) {
+            // awt.28C=Rect is null
+            throw new NullPointerException(Messages.getString("awt.28C")); //$NON-NLS-1$
+        }
+
+        return createCompatibleWritableRaster(rect.x, rect.y, rect.width, rect.height);
+    }
+
+    /**
+     * Creates the translated child of this Raster. The New Raster object is a
+     * reference to the this Raster with a different location.
+     * 
+     * @param childMinX
+     *            the X coordinate of the new Raster.
+     * @param childMinY
+     *            the Y coordinate of the new Raster.
+     * @return the Raster.
+     */
+    public Raster createTranslatedChild(int childMinX, int childMinY) {
+        return createChild(minX, minY, width, height, childMinX, childMinY, null);
+    }
+
+    /**
+     * Gets the bounds of this Raster as a rectangle.
+     * 
+     * @return the bounds of this Raster.
+     */
+    public Rectangle getBounds() {
+        return new Rectangle(minX, minY, width, height);
+    }
+
+    /**
+     * Gets the DataBuffer associated with this Raster.
+     * 
+     * @return the DataBuffer associated with this Raster.
+     */
+    public DataBuffer getDataBuffer() {
+        return dataBuffer;
+    }
+
+    /**
+     * Gets the data elements which represent the pixel data of the specified
+     * rectangle area as a primitive array. The following image data types are
+     * supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+     * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or
+     * DataBuffer.TYPE_DOUBLE.
+     * 
+     * @param x
+     *            the X coordinate of the area of pixels.
+     * @param y
+     *            the Y coordinate of the area of pixels.
+     * @param w
+     *            the width of the area of pixels.
+     * @param h
+     *            the height of the area of pixels.
+     * @param outData
+     *            the resulting array.
+     * @return the data elements of the specified area of this Raster.
+     */
+    public Object getDataElements(int x, int y, int w, int h, Object outData) {
+        return sampleModel.getDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, w,
+                h, outData, dataBuffer);
+    }
+
+    /**
+     * Gets the data elements which represent the specified pixel of this Raster
+     * as a primitive array. The following image data types are supported:
+     * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT,
+     * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param outData
+     *            the resulting data.
+     * @return the data elements of the specified pixel of this Raster.
+     */
+    public Object getDataElements(int x, int y, Object outData) {
+        return sampleModel.getDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY,
+                outData, dataBuffer);
+    }
+
+    /**
+     * Gets the height of this Raster.
+     * 
+     * @return the height of this Raster.
+     */
+    public final int getHeight() {
+        return height;
+    }
+
+    /**
+     * Gets the minimum X coordinate of this Raster.
+     * 
+     * @return the minimum X coordinate of this Raster.
+     */
+    public final int getMinX() {
+        return minX;
+    }
+
+    /**
+     * Gets the minimum Y coordinate of this Raster.
+     * 
+     * @return the minimum Y coordinate of this Raster.
+     */
+    public final int getMinY() {
+        return minY;
+    }
+
+    /**
+     * Gets the number of bands in this Raster.
+     * 
+     * @return the number of bands in this Raster.
+     */
+    public final int getNumBands() {
+        return numBands;
+    }
+
+    /**
+     * Gets the number of data elements for one pixel.
+     * 
+     * @return the number of data elements for one pixel.
+     */
+    public final int getNumDataElements() {
+        return numDataElements;
+    }
+
+    /**
+     * Gets the parent Raster for this Raster object.
+     * 
+     * @return the parent Raster for this Raster object.
+     */
+    public Raster getParent() {
+        return parent;
+    }
+
+    /**
+     * Gets a double array of samples for the specified pixel in this Raster.
+     * 
+     * @param x
+     *            the pixel's X coordinate.
+     * @param y
+     *            the pixel's Y coordinate.
+     * @param dArray
+     *            the double array where result array will be stored.
+     * @return the double array of samples for the specified pixel in this
+     *         Raster.
+     */
+    public double[] getPixel(int x, int y, double dArray[]) {
+        return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, dArray,
+                dataBuffer);
+    }
+
+    /**
+     * Gets a float array of samples for the specified pixel in this Raster.
+     * 
+     * @param x
+     *            the pixel's X coordinate.
+     * @param y
+     *            the pixel's Y coordinate.
+     * @param fArray
+     *            the float array where the result array will be stored.
+     * @return the float array of samples for the specified pixel in this
+     *         Raster.
+     */
+    public float[] getPixel(int x, int y, float fArray[]) {
+        return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, fArray,
+                dataBuffer);
+    }
+
+    /**
+     * Gets an integer array of samples for the specified pixel in this Raster.
+     * 
+     * @param x
+     *            the pixel's X coordinate.
+     * @param y
+     *            the pixel's Y coordinate.
+     * @param iArray
+     *            the integer array where the result array will be stored.
+     * @return the integer array of samples for the specified pixel in this
+     *         Raster.
+     */
+    public int[] getPixel(int x, int y, int iArray[]) {
+        return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, iArray,
+                dataBuffer);
+    }
+
+    /**
+     * Gets an double array of samples for the specified rectangular area of
+     * pixels in this Raster.
+     * 
+     * @param x
+     *            the X coordinate of the area of pixels.
+     * @param y
+     *            the Y coordinate of the area of pixels.
+     * @param w
+     *            the width of the area of pixels.
+     * @param h
+     *            the height of the area of pixels.
+     * @param dArray
+     *            the resulting array.
+     * @return the double array of samples for the specified rectangular area of
+     *         pixels in this Raster.
+     */
+    public double[] getPixels(int x, int y, int w, int h, double dArray[]) {
+        return sampleModel.getPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h,
+                dArray, dataBuffer);
+    }
+
+    /**
+     * Gets an float array of samples for the specified rectangular area of
+     * pixels in this Raster.
+     * 
+     * @param x
+     *            the X coordinate of the area of pixels.
+     * @param y
+     *            the Y coordinate of the area of pixels.
+     * @param w
+     *            the width of the area of pixels.
+     * @param h
+     *            the height of the area of pixels.
+     * @param fArray
+     *            the resulting array.
+     * @return the float array of samples for the specified rectangular area of
+     *         pixels in this Raster.
+     */
+    public float[] getPixels(int x, int y, int w, int h, float fArray[]) {
+        return sampleModel.getPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h,
+                fArray, dataBuffer);
+    }
+
+    /**
+     * Gets an integer array of samples for the specified rectangular area of
+     * pixels in this raster.
+     * 
+     * @param x
+     *            the X coordinate of the area of pixels.
+     * @param y
+     *            the Y coordinate of the area of pixels.
+     * @param w
+     *            the width of pixel's the area of pixels.
+     * @param h
+     *            the height of pixel's the area of pixels.
+     * @param iArray
+     *            the resulting array.
+     * @return the integer array of samples for the specified rectangular area
+     *         of pixels in this Raster.
+     */
+    public int[] getPixels(int x, int y, int w, int h, int iArray[]) {
+        return sampleModel.getPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h,
+                iArray, dataBuffer);
+    }
+
+    /**
+     * Gets the sample for the specified band of the specified pixel as an
+     * integer.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param b
+     *            the band.
+     * @return the sample for the specified band of the specified pixel as an
+     *         integer.
+     */
+    public int getSample(int x, int y, int b) {
+        return sampleModel.getSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b,
+                dataBuffer);
+    }
+
+    /**
+     * Gets the sample for the specified band of the specified pixel as a
+     * double.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param b
+     *            the band.
+     * @return the sample for the specified band of the specified pixel as a
+     *         double.
+     */
+    public double getSampleDouble(int x, int y, int b) {
+        return sampleModel.getSampleDouble(x - sampleModelTranslateX, y - sampleModelTranslateY, b,
+                dataBuffer);
+    }
+
+    /**
+     * Gets the sample for the specified band of the specified pixel as a float.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param b
+     *            the band.
+     * @return the sample for the specified band of the specified pixel as a
+     *         float.
+     */
+    public float getSampleFloat(int x, int y, int b) {
+        return sampleModel.getSampleFloat(x - sampleModelTranslateX, y - sampleModelTranslateY, b,
+                dataBuffer);
+    }
+
+    /**
+     * Gets the SampleModel associated with this Raster.
+     * 
+     * @return the SampleModel associated with this Raster.
+     */
+    public SampleModel getSampleModel() {
+        return sampleModel;
+    }
+
+    /**
+     * Gets the translation of the X coordinate from the SampleModel coordinate
+     * system to the Rasters's coordinate system.
+     * 
+     * @return the value of the translation of the X coordinate from the
+     *         SampleModel coordinate system to the Rasters's coordinate system.
+     */
+    public final int getSampleModelTranslateX() {
+        return sampleModelTranslateX;
+    }
+
+    /**
+     * Gets the translation of the Y coordinate from the SampleModel coordinate
+     * system to the Rasters's coordinate system.
+     * 
+     * @return the value of the translation of the Y coordinate from the
+     *         SampleModel coordinate system to the Rasters's coordinate system.
+     */
+    public final int getSampleModelTranslateY() {
+        return sampleModelTranslateY;
+    }
+
+    /**
+     * Gets the double array of samples for the specified band of the specified
+     * rectangular area of pixels in this Raster as a double array.
+     * 
+     * @param x
+     *            the X coordinate of the rectangular area of pixels.
+     * @param y
+     *            the Y coordinate of the rectangular area of pixels.
+     * @param w
+     *            the width of the rectangular area of pixels.
+     * @param h
+     *            the height of the rectangular area of pixels.
+     * @param b
+     *            the band.
+     * @param dArray
+     *            the resulting double array.
+     * @return the double array of samples for the specified band of the
+     *         specified rectangular area of pixels.
+     */
+    public double[] getSamples(int x, int y, int w, int h, int b, double dArray[]) {
+
+        return sampleModel.getSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h,
+                b, dArray, dataBuffer);
+    }
+
+    /**
+     * Gets the float array of samples for the specified band of the specified
+     * rectangular area of pixels in this Raster as a float array.
+     * 
+     * @param x
+     *            the X coordinate of the rectangular area of pixels.
+     * @param y
+     *            the Y coordinate of the rectangular area of pixels.
+     * @param w
+     *            the width of the rectangular area of pixels.
+     * @param h
+     *            the height of the rectangular area of pixels.
+     * @param b
+     *            the band.
+     * @param fArray
+     *            the resulting float array.
+     * @return the float array of samples for the specified band of the
+     *         specified rectangular area of pixels.
+     */
+    public float[] getSamples(int x, int y, int w, int h, int b, float fArray[]) {
+
+        return sampleModel.getSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h,
+                b, fArray, dataBuffer);
+    }
+
+    /**
+     * Gets the integer array of samples for the specified band of the specified
+     * rectangular area of pixels in this Raster as a integer array.
+     * 
+     * @param x
+     *            the X coordinate of the rectangular area of pixels.
+     * @param y
+     *            the Y coordinate of the rectangular area of pixels.
+     * @param w
+     *            the width of the rectangular area of pixels.
+     * @param h
+     *            the height of the rectangular area of pixels.
+     * @param b
+     *            the band.
+     * @param iArray
+     *            the resulting integer array.
+     * @return the integer array of samples for the specified band of the
+     *         specified rectangular area of pixels.
+     */
+    public int[] getSamples(int x, int y, int w, int h, int b, int iArray[]) {
+        return sampleModel.getSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h,
+                b, iArray, dataBuffer);
+    }
+
+    /**
+     * Gets the transfer type for pixels of this Raster.
+     * 
+     * @see SampleModel#getTransferType()
+     * @return the transfer type for pixels of this Raster.
+     */
+    public final int getTransferType() {
+        return sampleModel.getTransferType();
+    }
+
+    /**
+     * Gets the width of this Raster.
+     * 
+     * @return the width of this Raster.
+     */
+    public final int getWidth() {
+        return width;
+    }
+
+    /**
+     * Validate data buffer.
+     * 
+     * @param dataBuffer
+     *            the data buffer.
+     * @param w
+     *            the w.
+     * @param h
+     *            the h.
+     * @param scanlineStride
+     *            the scanline stride.
+     */
+    private static void validateDataBuffer(final DataBuffer dataBuffer, final int w, final int h,
+            final int scanlineStride) {
+        if (dataBuffer.getSize() < (scanlineStride * (h - 1) + w - 1)) {
+            // awt.298=dataBuffer is too small
+            throw new RasterFormatException(Messages.getString("awt.298")); //$NON-NLS-1$
+        }
+    }
+}
diff --git a/awt/java/awt/image/RasterFormatException.java b/awt/java/awt/image/RasterFormatException.java
new file mode 100644
index 0000000..c667141
--- /dev/null
+++ b/awt/java/awt/image/RasterFormatException.java
@@ -0,0 +1,48 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+/**
+ * The RasterFormatException class represents the exception that is thrown when
+ * there's an invalid layout in the Raster.
+ * 
+ * @since Android 1.0
+ */
+public class RasterFormatException extends RuntimeException {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = 96598996116164315L;
+
+    /**
+     * Instantiates a new RasterFormatException with the specified detail
+     * message.
+     * 
+     * @param s
+     *            the detail message.
+     */
+    public RasterFormatException(String s) {
+        super(s);
+    }
+
+}
diff --git a/awt/java/awt/image/RasterOp.java b/awt/java/awt/image/RasterOp.java
new file mode 100644
index 0000000..19a84c9
--- /dev/null
+++ b/awt/java/awt/image/RasterOp.java
@@ -0,0 +1,88 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.RenderingHints;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The RasterOp interface provides methods for performing transformations from
+ * source data to destination data for Raster objects. The source and
+ * destination objects should contain the appropriate number of bands for the
+ * particular classes which implement this interface.
+ * 
+ * @since Android 1.0
+ */
+public interface RasterOp {
+
+    /**
+     * Creates a destination WritableRaster with the specified Raster; this
+     * destination image data is empty and has the correct size and number of
+     * bands.
+     * 
+     * @param src
+     *            the source Raster.
+     * @return the WritableRaster.
+     */
+    public WritableRaster createCompatibleDestRaster(Raster src);
+
+    /**
+     * Performs a filter operation on the source Raster and stores the resulting
+     * image data to the destination WritableRaster.
+     * 
+     * @param src
+     *            the source Raster.
+     * @param dst
+     *            the destination WritableRaster, where the result is stored.
+     * @return the filtered WritableRaster.
+     */
+    public WritableRaster filter(Raster src, WritableRaster dst);
+
+    /**
+     * Gets the bounds of the filtered Raster.
+     * 
+     * @param src
+     *            the source Raster to be filtered.
+     * @return the rectangle bounds of the filtered Raster.
+     */
+    public Rectangle2D getBounds2D(Raster src);
+
+    /**
+     * Gets the point of the destination image which corresponds to the
+     * specified point in the source raster.
+     * 
+     * @param srcPoint
+     *            the point of the source raster.
+     * @param dstPoint
+     *            the point where the result will be stored.
+     * @return the destination point.
+     */
+    public Point2D getPoint2D(Point2D srcPoint, Point2D dstPoint);
+
+    /**
+     * Gets the RenderingHints of the RasterOp.
+     * 
+     * @return the RenderingHints of the RasterOp.
+     */
+    public RenderingHints getRenderingHints();
+}
diff --git a/awt/java/awt/image/RenderedImage.java b/awt/java/awt/image/RenderedImage.java
new file mode 100644
index 0000000..5eafa64
--- /dev/null
+++ b/awt/java/awt/image/RenderedImage.java
@@ -0,0 +1,198 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.Rectangle;
+import java.util.Vector;
+
+/**
+ * The RenderedImage interface should be implemented by all objects which
+ * contains image data. The image data is represented as a single tile or an
+ * array of tiles.
+ * 
+ * @since Android 1.0
+ */
+public interface RenderedImage {
+
+    /**
+     * Gets the property with the specified name from the property set of this
+     * RenderedImage.
+     * 
+     * @param name
+     *            the property's name.
+     * @return the property value corresponded to this property's name.
+     */
+    public Object getProperty(String name);
+
+    /**
+     * Copies the region of this RenderedImage to the specified WritableRaster.
+     * The bounds of the region are the bounds of the WritableRaster.
+     * 
+     * @param raster
+     *            the WritableRaster.
+     * @return the created WritableRaster.
+     */
+    public WritableRaster copyData(WritableRaster raster);
+
+    /**
+     * Gets the image data of the image's region as one tile.
+     * 
+     * @param rect
+     *            the rectangular region of RenderedImage.
+     * @return the image data of the image's region as one tile.
+     */
+    public Raster getData(Rectangle rect);
+
+    /**
+     * Gets all RenderedImage objects which are the source of this RenderedImage
+     * object.
+     * 
+     * @return a Vector of RenderedImage objects which are the source of this
+     *         RenderedImage object or null, if there is no information about
+     *         them.
+     */
+    public Vector<RenderedImage> getSources();
+
+    /**
+     * Gets the set of all property names for this RenderedImage.
+     * 
+     * @return the array of all property names for this RenderedImage.
+     */
+    public String[] getPropertyNames();
+
+    /**
+     * Gets the SampleModel of this RenderedImage.
+     * 
+     * @return the SampleModel of this RenderedImage.
+     */
+    public SampleModel getSampleModel();
+
+    /**
+     * Gets the tile corresponded to the specified indices in the tile array.
+     * 
+     * @param tileX
+     *            the X index of the tile.
+     * @param tileY
+     *            the Y index of the tile.
+     * @return the tile corresponded to the specified indices in the tile array.
+     */
+    public Raster getTile(int tileX, int tileY);
+
+    /**
+     * Gets the image data of this image as one tile.
+     * 
+     * @return the image data of this image as one tile.
+     */
+    public Raster getData();
+
+    /**
+     * Gets the ColorModel of this RenderedImage.
+     * 
+     * @return the ColorModel of this RenderedImage.
+     */
+    public ColorModel getColorModel();
+
+    /**
+     * Gets the width of the RenderedImage.
+     * 
+     * @return the width of the RenderedImage.
+     */
+    public int getWidth();
+
+    /**
+     * Gets the tile width.
+     * 
+     * @return the tile width in pixels.
+     */
+    public int getTileWidth();
+
+    /**
+     * Gets the tile height.
+     * 
+     * @return the tile height in pixels.
+     */
+    public int getTileHeight();
+
+    /**
+     * Gets the Y offset of the tile grid.
+     * 
+     * @return the Y offset of the tile grid.
+     */
+    public int getTileGridYOffset();
+
+    /**
+     * Gets the X offset of the tile grid.
+     * 
+     * @return the X offset of the tile grid.
+     */
+    public int getTileGridXOffset();
+
+    /**
+     * Gets the number of tiles along Y direction.
+     * 
+     * @return the number of tiles along Y direction.
+     */
+    public int getNumYTiles();
+
+    /**
+     * Gets the number of tiles along X direction.
+     * 
+     * @return the number of tiles along X direction.
+     */
+    public int getNumXTiles();
+
+    /**
+     * Gets the minimum Y coordinate of this RenderedImage.
+     * 
+     * @return the minimum Y coordinate of this RenderedImage.
+     */
+    public int getMinY();
+
+    /**
+     * Gets the minimum X coordinate of this RenderedImage.
+     * 
+     * @return the minimum X coordinate of this RenderedImage.
+     */
+    public int getMinX();
+
+    /**
+     * Gets the minimum tile's index along the Y direction.
+     * 
+     * @return the minimum tile's index along the Y direction.
+     */
+    public int getMinTileY();
+
+    /**
+     * Gets the minimum tile's index along the X direction.
+     * 
+     * @return the minimum tile's index along the X direction.
+     */
+    public int getMinTileX();
+
+    /**
+     * Gets the height of the RenderedImage.
+     * 
+     * @return the height of the RenderedImage.
+     */
+    public int getHeight();
+
+}
diff --git a/awt/java/awt/image/ReplicateScaleFilter.java b/awt/java/awt/image/ReplicateScaleFilter.java
new file mode 100644
index 0000000..51c0f49
--- /dev/null
+++ b/awt/java/awt/image/ReplicateScaleFilter.java
@@ -0,0 +1,225 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.util.Hashtable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ReplicateScaleFilter class scales an source image by replicating rows and
+ * columns of pixels to scale up or omitting rows and columns of pixels to scale
+ * down.
+ * 
+ * @since Android 1.0
+ */
+public class ReplicateScaleFilter extends ImageFilter {
+
+    /**
+     * The width of a source image.
+     */
+    protected int srcWidth;
+
+    /**
+     * The height of a source image.
+     */
+    protected int srcHeight;
+
+    /**
+     * The width of a destination image.
+     */
+    protected int destWidth;
+
+    /**
+     * The height of a destination image.
+     */
+    protected int destHeight;
+
+    /**
+     * The integer array of source rows.
+     */
+    protected int[] srcrows;
+
+    /**
+     * The integer array of source columns.
+     */
+    protected int[] srccols;
+
+    /**
+     * An Object (byte array with a destination width) provides a row of pixel
+     * data to the ImageConsumer.
+     */
+    protected Object outpixbuf;
+
+    /**
+     * Instantiates a new ReplicateScaleFilter that filters the image with the
+     * specified width and height.
+     * 
+     * @param width
+     *            the width of scaled image.
+     * @param height
+     *            the height of scaled image.
+     */
+    public ReplicateScaleFilter(int width, int height) {
+        if (width == 0 || height == 0) {
+            // awt.234=Width or Height equals zero
+            throw new IllegalArgumentException(Messages.getString("awt.234")); //$NON-NLS-1$
+        }
+
+        this.destWidth = width;
+        this.destHeight = height;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void setProperties(Hashtable<?, ?> props) {
+        Hashtable<Object, Object> fprops;
+        if (props == null) {
+            fprops = new Hashtable<Object, Object>();
+        } else {
+            fprops = (Hashtable<Object, Object>)props.clone();
+        }
+        String propName = "Rescale Filters"; //$NON-NLS-1$
+        String prop = "destWidth=" + destWidth + "; " + //$NON-NLS-1$ //$NON-NLS-2$
+                "destHeight=" + destHeight; //$NON-NLS-1$
+        Object o = fprops.get(propName);
+        if (o != null) {
+            if (o instanceof String) {
+                prop = (String)o + "; " + prop; //$NON-NLS-1$
+            } else {
+                prop = o.toString() + "; " + prop; //$NON-NLS-1$
+            }
+        }
+        fprops.put(propName, prop);
+        consumer.setProperties(fprops);
+    }
+
+    // setPixels methods produce pixels according to Java API Spacification
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off,
+            int scansize) {
+
+        if (srccols == null) {
+            initArrays();
+        }
+        int buff[];
+        if (outpixbuf == null || !(outpixbuf instanceof int[])) {
+            buff = new int[destWidth];
+            outpixbuf = buff;
+        } else {
+            buff = (int[])outpixbuf;
+        }
+
+        int wa = (srcWidth - 1) >>> 1;
+        int ha = (srcHeight - 1) >>> 1;
+        int dstX = (x * destWidth + wa) / srcWidth;
+        int dstY = (y * destHeight + ha) / srcHeight;
+
+        int sx, sy, dx, dy;
+        dy = dstY;
+        while ((dy < destHeight) && ((sy = srcrows[dy]) < y + h)) {
+            dx = dstX;
+            int srcOff = off + (sy - y) * scansize;
+            while ((dx < destWidth) && ((sx = srccols[dx]) < x + w)) {
+                buff[dx] = pixels[srcOff + (sx - x)];
+                dx++;
+            }
+
+            consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff, dstX, destWidth);
+            dy++;
+        }
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off,
+            int scansize) {
+
+        if (srccols == null) {
+            initArrays();
+        }
+        byte buff[];
+        if (outpixbuf == null || !(outpixbuf instanceof byte[])) {
+            buff = new byte[destWidth];
+            outpixbuf = buff;
+        } else {
+            buff = (byte[])outpixbuf;
+        }
+
+        int wa = (srcWidth - 1) >>> 1;
+        int ha = (srcHeight - 1) >>> 1;
+        int dstX = (x * destWidth + wa) / srcWidth;
+        int dstY = (y * destHeight + ha) / srcHeight;
+
+        int sx, sy, dx, dy;
+        dy = dstY;
+        while ((dy < destHeight) && ((sy = srcrows[dy]) < y + h)) {
+            dx = dstX;
+            int srcOff = off + (sy - y) * scansize;
+            while ((dx < destWidth) && ((sx = srccols[dx]) < x + w)) {
+                buff[dx] = pixels[srcOff + (sx - x)];
+                dx++;
+            }
+
+            consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff, dstX, destWidth);
+            dy++;
+        }
+    }
+
+    @Override
+    public void setDimensions(int w, int h) {
+        srcWidth = w;
+        srcHeight = h;
+
+        if (destWidth < 0 && destHeight < 0) {
+            destWidth = srcWidth;
+            destHeight = srcHeight;
+        } else if (destWidth < 0) {
+            destWidth = destHeight * srcWidth / srcHeight;
+        } else if (destHeight < 0) {
+            destHeight = destWidth * srcHeight / srcWidth;
+        }
+        consumer.setDimensions(destWidth, destHeight);
+    }
+
+    /**
+     * Initialization of srccols and srcrows arrays.
+     */
+    private void initArrays() {
+        if ((destWidth < 0) || (destHeight < 0)) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        srccols = new int[destWidth];
+        int ca = srcWidth >>> 1;
+        for (int i = 0; i < destWidth; i++) {
+            srccols[i] = (i * srcWidth + ca) / destWidth;
+        }
+
+        srcrows = new int[destHeight];
+        int ra = srcHeight >>> 1;
+        for (int i = 0; i < destHeight; i++) {
+            srcrows[i] = (i * srcHeight + ra) / destHeight;
+        }
+    }
+
+}
diff --git a/awt/java/awt/image/RescaleOp.java b/awt/java/awt/image/RescaleOp.java
new file mode 100644
index 0000000..d7e2bd7
--- /dev/null
+++ b/awt/java/awt/image/RescaleOp.java
@@ -0,0 +1,659 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 6, 2005
+ */
+
+package java.awt.image;
+
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.*;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class RescaleOp performs rescaling of the source image data by
+ * multiplying the pixel values with a scale factor and then adding an offset.
+ * 
+ * @since Android 1.0
+ */
+public class RescaleOp implements BufferedImageOp, RasterOp {
+
+    /**
+     * The scale factors.
+     */
+    private float scaleFactors[];
+
+    /**
+     * The offsets.
+     */
+    private float offsets[];
+
+    /**
+     * The hints.
+     */
+    private RenderingHints hints;
+
+    static {
+        // TODO
+        // System.loadLibrary("imageops");
+    }
+
+    /**
+     * Instantiates a new RescaleOp object with the specified scale factors and
+     * offsets.
+     * 
+     * @param scaleFactors
+     *            the array of scale factor values.
+     * @param offsets
+     *            the array of offset values.
+     * @param hints
+     *            the RenderingHints or null.
+     */
+    public RescaleOp(float[] scaleFactors, float[] offsets, RenderingHints hints) {
+        int numFactors = Math.min(scaleFactors.length, offsets.length);
+
+        this.scaleFactors = new float[numFactors];
+        this.offsets = new float[numFactors];
+
+        System.arraycopy(scaleFactors, 0, this.scaleFactors, 0, numFactors);
+        System.arraycopy(offsets, 0, this.offsets, 0, numFactors);
+
+        this.hints = hints;
+    }
+
+    /**
+     * Instantiates a new RescaleOp object with the specified scale factor and
+     * offset.
+     * 
+     * @param scaleFactor
+     *            the scale factor.
+     * @param offset
+     *            the offset.
+     * @param hints
+     *            the RenderingHints or null.
+     */
+    public RescaleOp(float scaleFactor, float offset, RenderingHints hints) {
+        scaleFactors = new float[1];
+        offsets = new float[1];
+
+        scaleFactors[0] = scaleFactor;
+        offsets[0] = offset;
+
+        this.hints = hints;
+    }
+
+    /**
+     * Gets the number of scaling factors.
+     * 
+     * @return the number of scaling factors.
+     */
+    public final int getNumFactors() {
+        return scaleFactors.length;
+    }
+
+    public final RenderingHints getRenderingHints() {
+        return hints;
+    }
+
+    /**
+     * Gets the scale factors of this RescaleOp.
+     * 
+     * @param scaleFactors
+     *            the desired scale factors array will be copied to this array.
+     * @return the scale factors array.
+     */
+    public final float[] getScaleFactors(float[] scaleFactors) {
+        if (scaleFactors == null) {
+            scaleFactors = new float[this.scaleFactors.length];
+        }
+
+        int minLength = Math.min(scaleFactors.length, this.scaleFactors.length);
+        System.arraycopy(this.scaleFactors, 0, scaleFactors, 0, minLength);
+        return scaleFactors;
+    }
+
+    /**
+     * Gets the offsets array of this RescaleOp.
+     * 
+     * @param offsets
+     *            the desired offsets array will be copied to this array.
+     * @return the offsets array of this RescaleOp.
+     */
+    public final float[] getOffsets(float[] offsets) {
+        if (offsets == null) {
+            offsets = new float[this.offsets.length];
+        }
+
+        int minLength = Math.min(offsets.length, this.offsets.length);
+        System.arraycopy(this.offsets, 0, offsets, 0, minLength);
+        return offsets;
+    }
+
+    public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+        if (dstPt == null) {
+            dstPt = new Point2D.Float();
+        }
+
+        dstPt.setLocation(srcPt);
+        return dstPt;
+    }
+
+    public final Rectangle2D getBounds2D(Raster src) {
+        return src.getBounds();
+    }
+
+    public final Rectangle2D getBounds2D(BufferedImage src) {
+        return getBounds2D(src.getRaster());
+    }
+
+    public WritableRaster createCompatibleDestRaster(Raster src) {
+        return src.createCompatibleWritableRaster();
+    }
+
+    public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
+        if (dstCM == null) {
+            dstCM = src.getColorModel();
+        }
+
+        if (dstCM instanceof IndexColorModel) {
+            dstCM = ColorModel.getRGBdefault();
+        }
+
+        WritableRaster r = dstCM.isCompatibleSampleModel(src.getSampleModel()) ? src.getRaster()
+                .createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : dstCM
+                .createCompatibleWritableRaster(src.getWidth(), src.getHeight());
+
+        return new BufferedImage(dstCM, r, dstCM.isAlphaPremultiplied(), null);
+    }
+
+    public final WritableRaster filter(Raster src, WritableRaster dst) {
+        if (dst == null) {
+            dst = createCompatibleDestRaster(src);
+        } else {
+            if (src.getNumBands() != dst.getNumBands()) {
+                // awt.21D=Number of src bands ({0}) does not match number of
+                // dst bands ({1})
+                throw new IllegalArgumentException(Messages.getString("awt.21D", //$NON-NLS-1$
+                        src.getNumBands(), dst.getNumBands()));
+            }
+        }
+
+        if (this.scaleFactors.length != 1 && this.scaleFactors.length != src.getNumBands()) {
+            // awt.21E=Number of scaling constants is not equal to the number of
+            // bands
+            throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$
+        }
+
+        // TODO
+        // if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, false) != 0)
+        if (slowFilter(src, dst, false) != 0) {
+            // awt.21F=Unable to transform source
+            throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$
+        }
+
+        return dst;
+    }
+
+    /**
+     * Slow filter.
+     * 
+     * @param src
+     *            the src.
+     * @param dst
+     *            the dst.
+     * @param skipAlpha
+     *            the skip alpha.
+     * @return the int.
+     */
+    private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) {
+        SampleModel sm = src.getSampleModel();
+
+        int numBands = src.getNumBands();
+        int srcHeight = src.getHeight();
+        int srcWidth = src.getWidth();
+
+        int srcMinX = src.getMinX();
+        int srcMinY = src.getMinY();
+        int dstMinX = dst.getMinX();
+        int dstMinY = dst.getMinY();
+
+        int[] maxValues = new int[numBands];
+        int[] masks = new int[numBands];
+        int[] sampleSizes = sm.getSampleSize();
+
+        for (int i = 0; i < numBands; i++) {
+            maxValues[i] = (1 << sampleSizes[i]) - 1;
+            masks[i] = ~(maxValues[i]);
+        }
+
+        // Processing bounds
+        float[] pixels = null;
+        pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels);
+
+        // Cycle over pixels to be calculated
+        if (skipAlpha) { // Always suppose that alpha channel is the last band
+            if (scaleFactors.length > 1) {
+                for (int i = 0; i < pixels.length;) {
+                    for (int bandIdx = 0; bandIdx < numBands - 1; bandIdx++, i++) {
+                        pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx];
+                        // Check for overflow now
+                        if (((int)pixels[i] & masks[bandIdx]) != 0) {
+                            if (pixels[i] < 0) {
+                                pixels[i] = 0;
+                            } else {
+                                pixels[i] = maxValues[bandIdx];
+                            }
+                        }
+                    }
+
+                    i++;
+                }
+            } else {
+                for (int i = 0; i < pixels.length;) {
+                    for (int bandIdx = 0; bandIdx < numBands - 1; bandIdx++, i++) {
+                        pixels[i] = pixels[i] * scaleFactors[0] + offsets[0];
+                        // Check for overflow now
+                        if (((int)pixels[i] & masks[bandIdx]) != 0) {
+                            if (pixels[i] < 0) {
+                                pixels[i] = 0;
+                            } else {
+                                pixels[i] = maxValues[bandIdx];
+                            }
+                        }
+                    }
+
+                    i++;
+                }
+            }
+        } else {
+            if (scaleFactors.length > 1) {
+                for (int i = 0; i < pixels.length;) {
+                    for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++) {
+                        pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx];
+                        // Check for overflow now
+                        if (((int)pixels[i] & masks[bandIdx]) != 0) {
+                            if (pixels[i] < 0) {
+                                pixels[i] = 0;
+                            } else {
+                                pixels[i] = maxValues[bandIdx];
+                            }
+                        }
+                    }
+                }
+            } else {
+                for (int i = 0; i < pixels.length;) {
+                    for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++) {
+                        pixels[i] = pixels[i] * scaleFactors[0] + offsets[0];
+                        // Check for overflow now
+                        if (((int)pixels[i] & masks[bandIdx]) != 0) {
+                            if (pixels[i] < 0) {
+                                pixels[i] = 0;
+                            } else {
+                                pixels[i] = maxValues[bandIdx];
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        dst.setPixels(dstMinX, dstMinY, srcWidth, srcHeight, pixels);
+
+        return 0;
+    }
+
+    public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+        ColorModel srcCM = src.getColorModel();
+
+        if (srcCM instanceof IndexColorModel) {
+            // awt.220=Source should not have IndexColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.220")); //$NON-NLS-1$
+        }
+
+        // Check if the number of scaling factors matches the number of bands
+        int nComponents = srcCM.getNumComponents();
+        boolean skipAlpha;
+        if (srcCM.hasAlpha()) {
+            if (scaleFactors.length == 1 || scaleFactors.length == nComponents - 1) {
+                skipAlpha = true;
+            } else if (scaleFactors.length == nComponents) {
+                skipAlpha = false;
+            } else {
+                // awt.21E=Number of scaling constants is not equal to the
+                // number of bands
+                throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$
+            }
+        } else if (scaleFactors.length == 1 || scaleFactors.length == nComponents) {
+            skipAlpha = false;
+        } else {
+            // awt.21E=Number of scaling constants is not equal to the number of
+            // bands
+            throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$
+        }
+
+        BufferedImage finalDst = null;
+        if (dst == null) {
+            finalDst = dst;
+            dst = createCompatibleDestImage(src, srcCM);
+        } else if (!srcCM.equals(dst.getColorModel())) {
+            // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB
+            // as same
+            if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst
+                    .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) {
+                finalDst = dst;
+                dst = createCompatibleDestImage(src, srcCM);
+            }
+        }
+
+        // TODO
+        // if (ippFilter(src.getRaster(), dst.getRaster(), src.getType(),
+        // skipAlpha) != 0)
+        if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) {
+            // awt.21F=Unable to transform source
+            throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$
+        }
+
+        if (finalDst != null) {
+            Graphics2D g = finalDst.createGraphics();
+            g.setComposite(AlphaComposite.Src);
+            g.drawImage(dst, 0, 0, null);
+        } else {
+            finalDst = dst;
+        }
+
+        return finalDst;
+    }
+
+    // Don't forget to pass allocated arrays for levels and values, size should
+    // be numBands*4
+    /**
+     * Creates the levels.
+     * 
+     * @param sm
+     *            the sm.
+     * @param numBands
+     *            the num bands.
+     * @param skipAlpha
+     *            the skip alpha.
+     * @param levels
+     *            the levels.
+     * @param values
+     *            the values.
+     * @param channelsOrder
+     *            the channels order.
+     */
+    private final void createLevels(SampleModel sm, int numBands, boolean skipAlpha, int levels[],
+            int values[], int channelsOrder[]) {
+        // Suppose same sample size for all channels, otherwise use slow filter
+        int maxValue = (1 << sm.getSampleSize(0)) - 1;
+
+        // For simplicity introduce these arrays
+        float extScaleFactors[] = new float[numBands];
+        float extOffsets[] = new float[numBands];
+
+        if (scaleFactors.length != 1) {
+            System.arraycopy(scaleFactors, 0, extScaleFactors, 0, scaleFactors.length);
+            System.arraycopy(offsets, 0, extOffsets, 0, scaleFactors.length);
+        } else {
+            for (int i = 0; i < numBands; i++) {
+                extScaleFactors[i] = scaleFactors[0];
+                extOffsets[i] = offsets[0];
+            }
+        }
+
+        if (skipAlpha) {
+            extScaleFactors[numBands - 1] = 1;
+            extOffsets[numBands - 1] = 0;
+        }
+
+        // Create a levels
+        for (int i = 0; i < numBands; i++) {
+            if (extScaleFactors[i] == 0) {
+                levels[i * 4] = 0;
+                levels[i * 4 + 1] = 0;
+                levels[i * 4 + 2] = maxValue + 1;
+                levels[i * 4 + 3] = maxValue + 1;
+            }
+
+            float minLevel = -extOffsets[i] / extScaleFactors[i];
+            float maxLevel = (maxValue - extOffsets[i]) / extScaleFactors[i];
+
+            if (minLevel < 0) {
+                minLevel = 0;
+            } else if (minLevel > maxValue) {
+                minLevel = maxValue;
+            }
+
+            if (maxLevel < 0) {
+                maxLevel = 0;
+            } else if (maxLevel > maxValue) {
+                maxLevel = maxValue;
+            }
+
+            levels[i * 4] = 0;
+            if (minLevel > maxLevel) {
+                levels[i * 4 + 1] = (int)maxLevel;
+                levels[i * 4 + 2] = (int)minLevel;
+            } else {
+                levels[i * 4 + 1] = (int)minLevel;
+                levels[i * 4 + 2] = (int)maxLevel;
+            }
+            levels[i * 4 + 3] = maxValue + 1;
+
+            // Fill values
+            for (int k = 0; k < 4; k++) {
+                int idx = i * 4 + k;
+                values[idx] = (int)(extScaleFactors[i] * levels[idx] + extOffsets[i]);
+                if (values[idx] < 0) {
+                    values[idx] = 0;
+                } else if (values[idx] > maxValue) {
+                    values[idx] = maxValue;
+                }
+            }
+        }
+
+        // Reorder data if channels are stored in different order
+        if (channelsOrder != null) {
+            int len = numBands * 4;
+            int savedLevels[] = new int[len];
+            int savedValues[] = new int[len];
+            System.arraycopy(levels, 0, savedLevels, 0, len);
+            System.arraycopy(values, 0, savedValues, 0, len);
+            for (int i = 0; i < channelsOrder.length; i++) {
+                System.arraycopy(savedLevels, i * 4, levels, channelsOrder[i] * 4, 4);
+                System.arraycopy(savedValues, i * 4, values, channelsOrder[i] * 4, 4);
+            }
+        }
+    }
+
+    // TODO remove when this method is used
+    /**
+     * Ipp filter.
+     * 
+     * @param src
+     *            the src.
+     * @param dst
+     *            the dst.
+     * @param imageType
+     *            the image type.
+     * @param skipAlpha
+     *            the skip alpha.
+     * @return the int.
+     */
+    @SuppressWarnings("unused")
+    private final int ippFilter(Raster src, WritableRaster dst, int imageType, boolean skipAlpha) {
+        int res;
+
+        int srcStride, dstStride;
+        int channels;
+        int offsets[] = null;
+        int channelsOrder[] = null;
+
+        switch (imageType) {
+            case BufferedImage.TYPE_INT_ARGB:
+            case BufferedImage.TYPE_INT_ARGB_PRE:
+            case BufferedImage.TYPE_INT_RGB: {
+                channels = 4;
+                srcStride = src.getWidth() * 4;
+                dstStride = dst.getWidth() * 4;
+                channelsOrder = new int[] {
+                        2, 1, 0, 3
+                };
+                break;
+            }
+
+            case BufferedImage.TYPE_4BYTE_ABGR:
+            case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+            case BufferedImage.TYPE_INT_BGR: {
+                channels = 4;
+                srcStride = src.getWidth() * 4;
+                dstStride = dst.getWidth() * 4;
+                break;
+            }
+
+            case BufferedImage.TYPE_BYTE_GRAY: {
+                channels = 1;
+                srcStride = src.getWidth();
+                dstStride = dst.getWidth();
+                break;
+            }
+
+            case BufferedImage.TYPE_3BYTE_BGR: {
+                channels = 3;
+                srcStride = src.getWidth() * 3;
+                dstStride = dst.getWidth() * 3;
+                channelsOrder = new int[] {
+                        2, 1, 0
+                };
+                break;
+            }
+
+            case BufferedImage.TYPE_USHORT_GRAY:
+            case BufferedImage.TYPE_USHORT_565_RGB:
+            case BufferedImage.TYPE_USHORT_555_RGB:
+            case BufferedImage.TYPE_BYTE_BINARY: {
+                return slowFilter(src, dst, skipAlpha);
+            }
+
+            default: {
+                SampleModel srcSM = src.getSampleModel();
+                SampleModel dstSM = dst.getSampleModel();
+
+                if (srcSM instanceof PixelInterleavedSampleModel
+                        && dstSM instanceof PixelInterleavedSampleModel) {
+                    // Check PixelInterleavedSampleModel
+                    if (srcSM.getDataType() != DataBuffer.TYPE_BYTE
+                            || dstSM.getDataType() != DataBuffer.TYPE_BYTE) {
+                        return slowFilter(src, dst, skipAlpha);
+                    }
+
+                    channels = srcSM.getNumBands(); // Have IPP functions for 1,
+                    // 3 and 4 channels
+                    if (!(channels == 1 || channels == 3 || channels == 4)) {
+                        return slowFilter(src, dst, skipAlpha);
+                    }
+
+                    srcStride = ((ComponentSampleModel)srcSM).getScanlineStride();
+                    dstStride = ((ComponentSampleModel)dstSM).getScanlineStride();
+
+                    channelsOrder = ((ComponentSampleModel)srcSM).getBandOffsets();
+                } else if (srcSM instanceof SinglePixelPackedSampleModel
+                        && dstSM instanceof SinglePixelPackedSampleModel) {
+                    // Check SinglePixelPackedSampleModel
+                    SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM;
+                    SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM;
+
+                    channels = sppsm1.getNumBands();
+
+                    // TYPE_INT_RGB, TYPE_INT_ARGB...
+                    if (sppsm1.getDataType() != DataBuffer.TYPE_INT
+                            || sppsm2.getDataType() != DataBuffer.TYPE_INT
+                            || !(channels == 3 || channels == 4)) {
+                        return slowFilter(src, dst, skipAlpha);
+                    }
+
+                    // Check compatibility of sample models
+                    if (!Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets())
+                            || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) {
+                        return slowFilter(src, dst, skipAlpha);
+                    }
+
+                    for (int i = 0; i < channels; i++) {
+                        if (sppsm1.getSampleSize(i) != 8) {
+                            return slowFilter(src, dst, skipAlpha);
+                        }
+                    }
+
+                    channelsOrder = new int[channels];
+                    int bitOffsets[] = sppsm1.getBitOffsets();
+                    for (int i = 0; i < channels; i++) {
+                        channelsOrder[i] = bitOffsets[i] / 8;
+                    }
+
+                    if (channels == 3) { // Don't skip channel now, could be
+                        // optimized
+                        channels = 4;
+                    }
+
+                    srcStride = sppsm1.getScanlineStride() * 4;
+                    dstStride = sppsm2.getScanlineStride() * 4;
+                } else {
+                    return slowFilter(src, dst, skipAlpha);
+                }
+
+                // Fill offsets if there's a child raster
+                if (src.getParent() != null || dst.getParent() != null) {
+                    if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0
+                            || dst.getSampleModelTranslateX() != 0
+                            || dst.getSampleModelTranslateY() != 0) {
+                        offsets = new int[4];
+                        offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+                        offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+                        offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+                        offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+                    }
+                }
+            }
+        }
+
+        int levels[] = new int[4 * channels];
+        int values[] = new int[4 * channels];
+
+        createLevels(src.getSampleModel(), channels, skipAlpha, levels, values, channelsOrder);
+
+        Object srcData, dstData;
+        AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+        try {
+            srcData = dbAccess.getData(src.getDataBuffer());
+            dstData = dbAccess.getData(dst.getDataBuffer());
+        } catch (IllegalArgumentException e) {
+            return -1; // Unknown data buffer type
+        }
+
+        res = LookupOp.ippLUT(srcData, src.getWidth(), src.getHeight(), srcStride, dstData, dst
+                .getWidth(), dst.getHeight(), dstStride, levels, values, channels, offsets, true);
+
+        return res;
+    }
+}
diff --git a/awt/java/awt/image/SampleModel.java b/awt/java/awt/image/SampleModel.java
new file mode 100644
index 0000000..c967fa6
--- /dev/null
+++ b/awt/java/awt/image/SampleModel.java
@@ -0,0 +1,1166 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The SampleModel class is abstract class for retrieving pixel's samples in the
+ * data of an image. Each pixel contains several samples. A sample is the set of
+ * values of the bands for single pixel. For example, each pixel in the RGB
+ * model contains three samples and there are three corresponding bands in the
+ * image data of such pixels representing red, green and blue components.
+ * <p>
+ * The image data is represented as a Raster with a DataBuffer and a
+ * SampleModel. The SampleModel allows access to the samples in the DataBuffer.
+ * 
+ * @since Android 1.0
+ */
+public abstract class SampleModel {
+
+    /**
+     * The width of the image data which this SampleModel describes.
+     */
+    protected int width;
+
+    /**
+     * The height of the image data which this SampleModel describes.
+     */
+    protected int height;
+
+    /**
+     * The number of bands of image data which this SampleModel describes.
+     */
+    protected int numBands;
+
+    /**
+     * The data type of the image data which this SampleModel describes.
+     */
+    protected int dataType;
+
+    /**
+     * Instantiates a new SampleModel with the specified data type, width,
+     * height and number of bands.
+     * 
+     * @param dataType
+     *            the data type of the image data.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param numBands
+     *            the number of bands of the image data.
+     */
+    public SampleModel(int dataType, int w, int h, int numBands) {
+        if (w <= 0 || h <= 0) {
+            // awt.22E=w or h is less than or equal to zero
+            throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$
+        }
+
+        double squre = ((double)w) * ((double)h);
+        if (squre >= Integer.MAX_VALUE) {
+            // awt.22F=The product of w and h is greater than Integer.MAX_VALUE
+            throw new IllegalArgumentException(Messages.getString("awt.22F")); //$NON-NLS-1$
+        }
+
+        if (dataType < DataBuffer.TYPE_BYTE || dataType > DataBuffer.TYPE_DOUBLE
+                && dataType != DataBuffer.TYPE_UNDEFINED) {
+            // awt.230=dataType is not one of the supported data types
+            throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+        }
+
+        if (numBands < 1) {
+            // awt.231=Number of bands must be more then 0
+            throw new IllegalArgumentException(Messages.getString("awt.231")); //$NON-NLS-1$
+        }
+
+        this.dataType = dataType;
+        this.width = w;
+        this.height = h;
+        this.numBands = numBands;
+
+    }
+
+    /**
+     * Gets the data array for the specified pixel of the specified DataBuffer
+     * with one of the following types: DataBuffer.TYPE_BYTE,
+     * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+     * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+     * 
+     * @param x
+     *            the X coordinate of pixel.
+     * @param y
+     *            the Y coordinate of pixel.
+     * @param obj
+     *            the Object is a data where the result will be stored.
+     * @param data
+     *            the image data.
+     * @return the data array for the specified pixel of the specified
+     *         DataBuffer.
+     */
+    public abstract Object getDataElements(int x, int y, Object obj, DataBuffer data);
+
+    /**
+     * Gets the array of pixel data for the specified rectangular area of pixels
+     * of the specified DataBuffer with one of the following types:
+     * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT,
+     * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+     * 
+     * @param x
+     *            the X coordinate of the rectangular pixel area.
+     * @param y
+     *            the Y coordinate of the rectangular pixel area.
+     * @param w
+     *            the width of the rectangular pixel area.
+     * @param h
+     *            the height of the rectangular pixel area.
+     * @param obj
+     *            the Object is an array with the primitive type, where the
+     *            result array will be stored.
+     * @param data
+     *            the image data.
+     * @return the array of pixel data for the specified rectangular area of
+     *         pixels of the specified DataBuffer object.
+     */
+    public Object getDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) {
+        int numDataElements = getNumDataElements();
+        int idx = 0;
+
+        switch (getTransferType()) {
+            case DataBuffer.TYPE_BYTE:
+                byte bdata[];
+                byte bbuf[] = null;
+
+                if (obj == null) {
+                    bdata = new byte[numDataElements * w * h];
+                } else {
+                    bdata = (byte[])obj;
+                }
+
+                for (int i = y; i < y + h; i++) {
+                    for (int j = x; j < x + w; j++) {
+                        bbuf = (byte[])getDataElements(j, i, bbuf, data);
+                        for (int n = 0; n < numDataElements; n++) {
+                            bdata[idx++] = bbuf[n];
+                        }
+                    }
+                }
+                obj = bdata;
+                break;
+
+            case DataBuffer.TYPE_SHORT:
+            case DataBuffer.TYPE_USHORT:
+                short sdata[];
+                short sbuf[] = null;
+
+                if (obj == null) {
+                    sdata = new short[numDataElements * w * h];
+                } else {
+                    sdata = (short[])obj;
+                }
+
+                for (int i = y; i < y + h; i++) {
+                    for (int j = x; j < x + w; j++) {
+                        sbuf = (short[])getDataElements(j, i, sbuf, data);
+                        for (int n = 0; n < numDataElements; n++) {
+                            sdata[idx++] = sbuf[n];
+                        }
+                    }
+                }
+                obj = sdata;
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int idata[];
+                int ibuf[] = null;
+
+                if (obj == null) {
+                    idata = new int[numDataElements * w * h];
+                } else {
+                    idata = (int[])obj;
+                }
+
+                for (int i = y; i < y + h; i++) {
+                    for (int j = x; j < x + w; j++) {
+                        ibuf = (int[])getDataElements(j, i, ibuf, data);
+                        for (int n = 0; n < numDataElements; n++) {
+                            idata[idx++] = ibuf[n];
+                        }
+                    }
+                }
+                obj = idata;
+                break;
+
+            case DataBuffer.TYPE_FLOAT:
+                float fdata[];
+                float fbuf[] = null;
+
+                if (obj == null) {
+                    fdata = new float[numDataElements * w * h];
+                } else {
+                    fdata = (float[])obj;
+                }
+
+                for (int i = y; i < y + h; i++) {
+                    for (int j = x; j < x + w; j++) {
+                        fbuf = (float[])getDataElements(j, i, fbuf, data);
+                        for (int n = 0; n < numDataElements; n++) {
+                            fdata[idx++] = fbuf[n];
+                        }
+                    }
+                }
+                obj = fdata;
+                break;
+
+            case DataBuffer.TYPE_DOUBLE:
+                double ddata[];
+                double dbuf[] = null;
+
+                if (obj == null) {
+                    ddata = new double[numDataElements * w * h];
+                } else {
+                    ddata = (double[])obj;
+                }
+
+                for (int i = y; i < y + h; i++) {
+                    for (int j = x; j < x + w; j++) {
+                        dbuf = (double[])getDataElements(j, i, dbuf, data);
+                        for (int n = 0; n < numDataElements; n++) {
+                            ddata[idx++] = dbuf[n];
+                        }
+                    }
+                }
+                obj = ddata;
+                break;
+
+        }
+
+        return obj;
+    }
+
+    /**
+     * Sets the data for a single pixel in the specified DataBuffer from a
+     * primitive array with one of the following types: DataBuffer.TYPE_BYTE,
+     * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+     * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+     * 
+     * @param x
+     *            the X coordinate of pixel.
+     * @param y
+     *            the Y coordinate of pixel.
+     * @param obj
+     *            the Object - the array of primitive pixel data to be set.
+     * @param data
+     *            the image data.
+     */
+    public abstract void setDataElements(int x, int y, Object obj, DataBuffer data);
+
+    /**
+     * Sets the data elements for a rectangular area of pixels in the specified
+     * DataBuffer from a primitive array with one of the following types:
+     * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT,
+     * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+     * 
+     * @param x
+     *            the X coordinate of the specified rectangular area.
+     * @param y
+     *            the Y coordinate of the specified rectangular area.
+     * @param w
+     *            the width of rectangle.
+     * @param h
+     *            the height of rectangle.
+     * @param obj
+     *            the Object - the array of primitive pixel data to be set.
+     * @param data
+     *            the image data.
+     */
+    public void setDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) {
+        int numDataElements = getNumDataElements();
+        int idx = 0;
+
+        switch (getTransferType()) {
+            case DataBuffer.TYPE_BYTE:
+                byte bbuf[] = new byte[numDataElements];
+                for (int i = y; i < y + h; i++) {
+                    for (int j = x; j < x + w; j++) {
+                        for (int n = 0; n < numDataElements; n++) {
+                            bbuf[n] = ((byte[])obj)[idx++];
+                        }
+                        setDataElements(j, i, bbuf, data);
+                    }
+                }
+
+                break;
+
+            case DataBuffer.TYPE_SHORT:
+            case DataBuffer.TYPE_USHORT:
+                short sbuf[] = new short[numDataElements];
+                for (int i = y; i < y + h; i++) {
+                    for (int j = x; j < x + w; j++) {
+                        for (int n = 0; n < numDataElements; n++) {
+                            sbuf[n] = ((short[])obj)[idx++];
+                        }
+                        setDataElements(j, i, sbuf, data);
+                    }
+                }
+                break;
+
+            case DataBuffer.TYPE_INT:
+                int ibuf[] = new int[numDataElements];
+                for (int i = y; i < y + h; i++) {
+                    for (int j = x; j < x + w; j++) {
+                        for (int n = 0; n < numDataElements; n++) {
+                            ibuf[n] = ((int[])obj)[idx++];
+                        }
+                        setDataElements(j, i, ibuf, data);
+                    }
+                }
+                break;
+
+            case DataBuffer.TYPE_FLOAT:
+                float fbuf[] = new float[numDataElements];
+                for (int i = y; i < y + h; i++) {
+                    for (int j = x; j < x + w; j++) {
+                        for (int n = 0; n < numDataElements; n++) {
+                            fbuf[n] = ((float[])obj)[idx++];
+                        }
+                        setDataElements(j, i, fbuf, data);
+                    }
+                }
+                break;
+
+            case DataBuffer.TYPE_DOUBLE:
+                double dbuf[] = new double[numDataElements];
+                for (int i = y; i < y + h; i++) {
+                    for (int j = x; j < x + w; j++) {
+                        for (int n = 0; n < numDataElements; n++) {
+                            dbuf[n] = ((double[])obj)[idx++];
+                        }
+                        setDataElements(j, i, dbuf, data);
+                    }
+                }
+                break;
+
+        }
+    }
+
+    /**
+     * Creates a new SampleModel with the specified bands of this SampleModel.
+     * 
+     * @param bands
+     *            the array of bands from this SampleModel.
+     * @return the SampleModel with the specified bands of this SampleModel.
+     */
+    public abstract SampleModel createSubsetSampleModel(int bands[]);
+
+    /**
+     * Creates the SampleModel which has the same data as in this SampleModel
+     * with a different width and height.
+     * 
+     * @param a0
+     *            the width of the image data.
+     * @param a1
+     *            the height of the image data.
+     * @return the SampleModel which has the same data as in this SampleModel
+     *         with a different width and height.
+     */
+    public abstract SampleModel createCompatibleSampleModel(int a0, int a1);
+
+    /**
+     * Gets the samples of the specified pixel as an integer array.
+     * 
+     * @param x
+     *            the X coordinate of pixel.
+     * @param y
+     *            the Y coordinate of pixel.
+     * @param iArray
+     *            the integer array where result will be stored.
+     * @param data
+     *            the image data.
+     * @return the integer array with the samples of the specified pixel.
+     */
+    public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int pixel[];
+
+        if (iArray == null) {
+            pixel = new int[numBands];
+        } else {
+            pixel = iArray;
+        }
+
+        for (int i = 0; i < numBands; i++) {
+            pixel[i] = getSample(x, y, i, data);
+        }
+
+        return pixel;
+    }
+
+    /**
+     * Sets a pixel of the DataBuffer from a integer array of samples.
+     * 
+     * @param x
+     *            the X coordinate of pixel.
+     * @param y
+     *            the Y coordinate of pixel.
+     * @param iArray
+     *            the integer array.
+     * @param data
+     *            the image data.
+     */
+    public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        for (int i = 0; i < numBands; i++) {
+            setSample(x, y, i, iArray[i], data);
+        }
+    }
+
+    /**
+     * Gets the samples of the specified pixel as a float array.
+     * 
+     * @param x
+     *            the X coordinate of pixel.
+     * @param y
+     *            the Y coordinate of pixel.
+     * @param fArray
+     *            the float array where result will be stored.
+     * @param data
+     *            the image data.
+     * @return the float array with the samples of the specified pixel.
+     */
+    public float[] getPixel(int x, int y, float fArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        float pixel[];
+
+        if (fArray == null) {
+            pixel = new float[numBands];
+        } else {
+            pixel = fArray;
+        }
+
+        for (int i = 0; i < numBands; i++) {
+            pixel[i] = getSampleFloat(x, y, i, data);
+        }
+
+        return pixel;
+    }
+
+    /**
+     * Sets a pixel of the DataBuffer from a float array of samples.
+     * 
+     * @param x
+     *            the X coordinate of pixel.
+     * @param y
+     *            the Y coordinate of pixel.
+     * @param fArray
+     *            the float array.
+     * @param data
+     *            the image data.
+     */
+    public void setPixel(int x, int y, float fArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        for (int i = 0; i < numBands; i++) {
+            setSample(x, y, i, fArray[i], data);
+        }
+    }
+
+    /**
+     * Gets the samples of the specified pixel as a double array.
+     * 
+     * @param x
+     *            the X coordinate of pixel.
+     * @param y
+     *            the Y coordinate of pixel.
+     * @param dArray
+     *            the double array where result will be stored.
+     * @param data
+     *            the image data.
+     * @return the double array with the samples of the specified pixel.
+     */
+    public double[] getPixel(int x, int y, double dArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        double pixel[];
+
+        if (dArray == null) {
+            pixel = new double[numBands];
+        } else {
+            pixel = dArray;
+        }
+
+        for (int i = 0; i < numBands; i++) {
+            pixel[i] = getSampleDouble(x, y, i, data);
+        }
+
+        return pixel;
+    }
+
+    /**
+     * Sets a pixel of the DataBuffer from a double array of samples.
+     * 
+     * @param x
+     *            the X coordinate of pixel.
+     * @param y
+     *            the Y coordinate of pixel.
+     * @param dArray
+     *            the double array.
+     * @param data
+     *            the image data.
+     */
+    public void setPixel(int x, int y, double dArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        for (int i = 0; i < numBands; i++) {
+            setSample(x, y, i, dArray[i], data);
+        }
+    }
+
+    /**
+     * Gets the sample of a specified band for the specified pixel as an
+     * integer.
+     * 
+     * @param x
+     *            the X coordinate of pixel.
+     * @param y
+     *            the Y coordinate of pixel.
+     * @param b
+     *            the specified band.
+     * @param data
+     *            the image data.
+     * @return the sample of a specified band for the specified pixel.
+     */
+    public abstract int getSample(int x, int y, int b, DataBuffer data);
+
+    /**
+     * Gets the sample of a specified band for the specified pixel as a float.
+     * 
+     * @param x
+     *            the X coordinate of pixel.
+     * @param y
+     *            the Y coordinate of pixel.
+     * @param b
+     *            the specified band.
+     * @param data
+     *            the image data.
+     * @return the sample of a specified band for the specified pixel.
+     */
+    public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+        return getSample(x, y, b, data);
+    }
+
+    /**
+     * Gets the sample of a specified band for the specified pixel as a double.
+     * 
+     * @param x
+     *            the X coordinate of pixel.
+     * @param y
+     *            the Y coordinate of pixel.
+     * @param b
+     *            the specified band.
+     * @param data
+     *            the image data.
+     * @return the sample of a specified band for the specified pixel.
+     */
+    public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+        return getSample(x, y, b, data);
+    }
+
+    /**
+     * Gets the samples of the specified rectangular area of pixels as an
+     * integer array.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle of pixels.
+     * @param y
+     *            the Y coordinate of the rectangle of pixels.
+     * @param w
+     *            the width of the rectangle of pixels.
+     * @param h
+     *            the height of the rectangle of pixels.
+     * @param iArray
+     *            the integer array where result will be stored.
+     * @param data
+     *            the image data.
+     * @return the integer array with the samples of the specified rectangular
+     *         area of pixels.
+     */
+    public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int pixels[];
+        int idx = 0;
+
+        if (iArray == null) {
+            pixels = new int[w * h * numBands];
+        } else {
+            pixels = iArray;
+        }
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                for (int n = 0; n < numBands; n++) {
+                    pixels[idx++] = getSample(j, i, n, data);
+                }
+            }
+        }
+        return pixels;
+    }
+
+    /**
+     * Sets all of the samples for a rectangular area of pixels of the
+     * DataBuffer from an integer array.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle of pixels.
+     * @param y
+     *            the Y coordinate of the rectangle of pixels.
+     * @param w
+     *            the width of the rectangle of pixels.
+     * @param h
+     *            the height of the rectangle of pixels.
+     * @param iArray
+     *            the integer array.
+     * @param data
+     *            the image data.
+     */
+    public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int idx = 0;
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                for (int n = 0; n < numBands; n++) {
+                    setSample(j, i, n, iArray[idx++], data);
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the samples of the specified rectangular area of pixels as a float
+     * array.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle of pixels.
+     * @param y
+     *            the Y coordinate of the rectangle of pixels.
+     * @param w
+     *            the width of the rectangle of pixels.
+     * @param h
+     *            the height of the rectangle of pixels.
+     * @param fArray
+     *            the float array where result will be stored.
+     * @param data
+     *            the image data.
+     * @return the float array with the samples of the specified rectangular
+     *         area of pixels.
+     */
+    public float[] getPixels(int x, int y, int w, int h, float fArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        float pixels[];
+        int idx = 0;
+
+        if (fArray == null) {
+            pixels = new float[w * h * numBands];
+        } else {
+            pixels = fArray;
+        }
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                for (int n = 0; n < numBands; n++) {
+                    pixels[idx++] = getSampleFloat(j, i, n, data);
+                }
+            }
+        }
+        return pixels;
+    }
+
+    /**
+     * Sets all of the samples for a rectangular area of pixels of the
+     * DataBuffer from a float array.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle of pixels.
+     * @param y
+     *            the Y coordinate of the rectangle of pixels.
+     * @param w
+     *            the width of the rectangle of pixels.
+     * @param h
+     *            the height of the rectangle of pixels.
+     * @param fArray
+     *            the float array.
+     * @param data
+     *            the image data.
+     */
+    public void setPixels(int x, int y, int w, int h, float fArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int idx = 0;
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                for (int n = 0; n < numBands; n++) {
+                    setSample(j, i, n, fArray[idx++], data);
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the samples of the specified rectangular area of pixels as a double
+     * array.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle of pixels.
+     * @param y
+     *            the Y coordinate of the rectangle of pixels.
+     * @param w
+     *            the width of the rectangle of pixels.
+     * @param h
+     *            the height of the rectangle of pixels.
+     * @param dArray
+     *            the double array where result will be stored.
+     * @param data
+     *            the image data.
+     * @return the double array with the samples of the specified rectangular
+     *         area of pixels.
+     */
+    public double[] getPixels(int x, int y, int w, int h, double dArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        double pixels[];
+        int idx = 0;
+
+        if (dArray == null) {
+            pixels = new double[w * h * numBands];
+        } else {
+            pixels = dArray;
+        }
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                for (int n = 0; n < numBands; n++) {
+                    pixels[idx++] = getSampleDouble(j, i, n, data);
+                }
+            }
+        }
+        return pixels;
+    }
+
+    /**
+     * Sets all of the samples for a rectangular area of pixels of the
+     * DataBuffer from a double array.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle of pixels.
+     * @param y
+     *            the Y coordinate of the rectangle of pixels.
+     * @param w
+     *            the width of the rectangle of pixels.
+     * @param h
+     *            the height of the rectangle of pixels.
+     * @param dArray
+     *            the double array.
+     * @param data
+     *            the image data.
+     */
+    public void setPixels(int x, int y, int w, int h, double dArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int idx = 0;
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                for (int n = 0; n < numBands; n++) {
+                    setSample(j, i, n, dArray[idx++], data);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets a sample of the specified band for the specified pixel in the
+     * DataBuffer as integer value.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param b
+     *            the specified band.
+     * @param s
+     *            the sample as an integer value.
+     * @param data
+     *            the image data.
+     */
+    public abstract void setSample(int x, int y, int b, int s, DataBuffer data);
+
+    /**
+     * Gets the samples of a specified band for a specified rectangular area of
+     * pixels as a integer array.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle.
+     * @param y
+     *            the Y coordinate of the rectangle.
+     * @param w
+     *            the width of the rectangle.
+     * @param h
+     *            the height of the rectangle.
+     * @param b
+     *            the specified band.
+     * @param iArray
+     *            the integer array where result will be stored.
+     * @param data
+     *            the image data.
+     * @return the samples of a specified band for a specified rectangular area
+     *         of pixels.
+     */
+    public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) {
+        int samples[];
+        int idx = 0;
+
+        if (iArray == null) {
+            samples = new int[w * h];
+        } else {
+            samples = iArray;
+        }
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                samples[idx++] = getSample(j, i, b, data);
+            }
+        }
+
+        return samples;
+    }
+
+    /**
+     * Sets the samples from an integer array in the specified band for the
+     * specified rectangle of pixels.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle.
+     * @param y
+     *            the Y coordinate of the rectangle.
+     * @param w
+     *            the width of the rectangle.
+     * @param h
+     *            the height of the rectangle.
+     * @param b
+     *            the specified band.
+     * @param iArray
+     *            the integer array.
+     * @param data
+     *            the image data.
+     */
+    public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) {
+        int idx = 0;
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                setSample(j, i, b, iArray[idx++], data);
+            }
+        }
+    }
+
+    /**
+     * Gets the samples of a specified band for a specified rectangular area of
+     * pixels as a float array.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle.
+     * @param y
+     *            the Y coordinate of the rectangle.
+     * @param w
+     *            the width of the rectangle.
+     * @param h
+     *            the height of the rectangle.
+     * @param b
+     *            the specified band.
+     * @param fArray
+     *            the float array where result will be stored.
+     * @param data
+     *            the image data.
+     * @return the samples of a specified band for a specified rectangular area
+     *         of pixels.
+     */
+    public float[] getSamples(int x, int y, int w, int h, int b, float fArray[], DataBuffer data) {
+        float samples[];
+        int idx = 0;
+
+        if (fArray == null) {
+            samples = new float[w * h];
+        } else {
+            samples = fArray;
+        }
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                samples[idx++] = getSampleFloat(j, i, b, data);
+            }
+        }
+
+        return samples;
+    }
+
+    /**
+     * Sets the samples from an float array in the specified band for the
+     * specified rectangle of pixels.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle.
+     * @param y
+     *            the Y coordinate of the rectangle.
+     * @param w
+     *            the width of the rectangle.
+     * @param h
+     *            the height of the rectangle.
+     * @param b
+     *            the specified band.
+     * @param fArray
+     *            the float array.
+     * @param data
+     *            the image data.
+     */
+    public void setSamples(int x, int y, int w, int h, int b, float fArray[], DataBuffer data) {
+        int idx = 0;
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                setSample(j, i, b, fArray[idx++], data);
+            }
+        }
+    }
+
+    /**
+     * Gets the samples of a specified band for a specified rectangular area of
+     * pixels as a double array.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle.
+     * @param y
+     *            the Y coordinate of the rectangle.
+     * @param w
+     *            the width of the rectangle.
+     * @param h
+     *            the height of the rectangle.
+     * @param b
+     *            the specified band.
+     * @param dArray
+     *            the double array where result will be stored.
+     * @param data
+     *            the image data.
+     * @return the samples of a specified band for a specified rectangular area
+     *         of pixels.
+     */
+    public double[] getSamples(int x, int y, int w, int h, int b, double dArray[], DataBuffer data) {
+        double samples[];
+        int idx = 0;
+
+        if (dArray == null) {
+            samples = new double[w * h];
+        } else {
+            samples = dArray;
+        }
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                samples[idx++] = getSampleDouble(j, i, b, data);
+            }
+        }
+
+        return samples;
+    }
+
+    /**
+     * Sets the samples from an double array in the specified band for the
+     * specified rectangle of pixels.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle.
+     * @param y
+     *            the Y coordinate of the rectangle.
+     * @param w
+     *            the width of the rectangle.
+     * @param h
+     *            the height of the rectangle.
+     * @param b
+     *            the specified band.
+     * @param dArray
+     *            the double array.
+     * @param data
+     *            the image data.
+     */
+    public void setSamples(int x, int y, int w, int h, int b, double dArray[], DataBuffer data) {
+        int idx = 0;
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                setSample(j, i, b, dArray[idx++], data);
+            }
+        }
+    }
+
+    /**
+     * Sets a sample of the specified band for the specified pixel in the
+     * DataBuffer as float value.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param b
+     *            the specified band.
+     * @param s
+     *            the sample as float value.
+     * @param data
+     *            the image data.
+     */
+    public void setSample(int x, int y, int b, float s, DataBuffer data) {
+        setSample(x, y, b, (int)s, data);
+    }
+
+    /**
+     * Sets a sample of the specified band for the specified pixel in the
+     * DataBuffer as double value.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param b
+     *            the specified band.
+     * @param s
+     *            the sample as double value.
+     * @param data
+     *            the image data.
+     */
+    public void setSample(int x, int y, int b, double s, DataBuffer data) {
+        setSample(x, y, b, (int)s, data);
+    }
+
+    /**
+     * Creates a DataBuffer object which corresponds to the SampleModel.
+     * 
+     * @return the DataBuffer object which corresponds to the SampleModel.
+     */
+    public abstract DataBuffer createDataBuffer();
+
+    /**
+     * Gets the sample size in bits for the specified band.
+     * 
+     * @param band
+     *            the specified band.
+     * @return the sample size in bits for the specified band.
+     */
+    public abstract int getSampleSize(int band);
+
+    /**
+     * Gets an array of the sample size in bits for all bands.
+     * 
+     * @return an array of the sample size in bits for all bands.
+     */
+    public abstract int[] getSampleSize();
+
+    /**
+     * Gets the width of the image data of this SampleModel object.
+     * 
+     * @return the width of the image data of this SampleModel object.
+     */
+    public final int getWidth() {
+        return width;
+    }
+
+    /**
+     * Gets the transfer type used to transfer pixels via the getDataElements
+     * and setDataElements methods. Transfer type value can be one of the
+     * predefined type from DataBuffer class or not.
+     * 
+     * @return the transfer type.
+     */
+    public int getTransferType() {
+        return dataType;
+    }
+
+    /**
+     * Returns the number of data elements for pixel transferring via the
+     * getDataElements and setDataElements methods.
+     * 
+     * @return the number of data elements for pixel transferring via the
+     *         getDataElements and setDataElements methods.
+     */
+    public abstract int getNumDataElements();
+
+    /**
+     * Gets the number of bands in the image data of this SampleModel object.
+     * 
+     * @return the number of bands in the image data of this SampleModel object.
+     */
+    public final int getNumBands() {
+        return numBands;
+    }
+
+    /**
+     * Gets the height of the image data of this SampleModel object.
+     * 
+     * @return the height of the image data of this SampleModel object.
+     */
+    public final int getHeight() {
+        return height;
+    }
+
+    /**
+     * Gets the data type of image data of this SampleModel object.
+     * 
+     * @return the data type of image data of this SampleModel object.
+     */
+    public final int getDataType() {
+        return dataType;
+    }
+
+}
diff --git a/awt/java/awt/image/ShortLookupTable.java b/awt/java/awt/image/ShortLookupTable.java
new file mode 100644
index 0000000..4319d58
--- /dev/null
+++ b/awt/java/awt/image/ShortLookupTable.java
@@ -0,0 +1,137 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 14, 2005
+ */
+
+package java.awt.image;
+
+/**
+ * The ShortLookupTable class provides provides functionality for lookup
+ * operations, and is defined by an input short array for bands or components of
+ * image and an offset value. The offset value will be subtracted from the input
+ * values before indexing the input arrays. The output of a lookup operation is
+ * represented as an unsigned short array.
+ * 
+ * @since Android 1.0
+ */
+public class ShortLookupTable extends LookupTable {
+
+    /**
+     * The data.
+     */
+    private short data[][];
+
+    /**
+     * Instantiates a new ShortLookupTable with the specified offset value and
+     * the specified short array which represents lookup table for all bands.
+     * 
+     * @param offset
+     *            the offset value.
+     * @param data
+     *            the data array.
+     */
+    public ShortLookupTable(int offset, short[] data) {
+        super(offset, 1);
+        this.data = new short[1][data.length];
+        // The data array stored as a reference
+        this.data[0] = data;
+    }
+
+    /**
+     * Instantiates a new ShortLookupTable with the specified offset value and
+     * the specified short array of arrays which represents lookup table for
+     * each band.
+     * 
+     * @param offset
+     *            the offset value.
+     * @param data
+     *            the data array of arrays for each band.
+     */
+    public ShortLookupTable(int offset, short[][] data) {
+        super(offset, data.length);
+        this.data = new short[data.length][data[0].length];
+        for (int i = 0; i < data.length; i++) {
+            // The data array for each band stored as a reference
+            this.data[i] = data[i];
+        }
+    }
+
+    /**
+     * Gets the lookup table of this ShortLookupTable object. If this
+     * ShortLookupTable object has one short array for all bands, the returned
+     * array length is one.
+     * 
+     * @return the lookup table of this ShortLookupTable object.
+     */
+    public final short[][] getTable() {
+        return data;
+    }
+
+    /**
+     * Returns a short array which contains samples of the specified pixel which
+     * is translated with the lookup table of this ShortLookupTable object. The
+     * resulted array is stored to the dst array.
+     * 
+     * @param src
+     *            the source array.
+     * @param dst
+     *            the destination array where the result can be stored.
+     * @return the short array of translated samples of a pixel.
+     */
+    public short[] lookupPixel(short[] src, short[] dst) {
+        if (dst == null) {
+            dst = new short[src.length];
+        }
+
+        int offset = getOffset();
+        if (getNumComponents() == 1) {
+            for (int i = 0; i < src.length; i++) {
+                dst[i] = data[0][src[i] - offset];
+            }
+        } else {
+            for (int i = 0; i < getNumComponents(); i++) {
+                dst[i] = data[i][src[i] - offset];
+            }
+        }
+
+        return dst;
+    }
+
+    @Override
+    public int[] lookupPixel(int[] src, int[] dst) {
+        if (dst == null) {
+            dst = new int[src.length];
+        }
+
+        int offset = getOffset();
+        if (getNumComponents() == 1) {
+            for (int i = 0; i < src.length; i++) {
+                dst[i] = data[0][src[i] - offset];
+            }
+        } else {
+            for (int i = 0; i < getNumComponents(); i++) {
+                dst[i] = data[i][src[i] - offset];
+            }
+        }
+
+        return dst;
+    }
+}
diff --git a/awt/java/awt/image/SinglePixelPackedSampleModel.java b/awt/java/awt/image/SinglePixelPackedSampleModel.java
new file mode 100644
index 0000000..69f3353
--- /dev/null
+++ b/awt/java/awt/image/SinglePixelPackedSampleModel.java
@@ -0,0 +1,519 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The SinglePixelPackedSampleModel class represents pixel data where several
+ * samples combine to create a single pixel and are stored in a single data
+ * array element. This class supports TYPE_BYTE, TYPE_USHORT, TYPE_INT data
+ * types.
+ * 
+ * @since Android 1.0
+ */
+public class SinglePixelPackedSampleModel extends SampleModel {
+
+    /**
+     * The bit masks.
+     */
+    private int bitMasks[];
+
+    /**
+     * The bit offsets.
+     */
+    private int bitOffsets[];
+
+    /**
+     * The bit sizes.
+     */
+    private int bitSizes[];
+
+    /**
+     * The scanline stride.
+     */
+    private int scanlineStride;
+
+    /**
+     * The max bit size.
+     */
+    private int maxBitSize;
+
+    /**
+     * Instantiates a new SinglePixelPackedSampleModel with the specified
+     * parameters.
+     * 
+     * @param dataType
+     *            the data type of samples.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param bitMasks
+     *            the bit masks for all the bands.
+     */
+    public SinglePixelPackedSampleModel(int dataType, int w, int h, int bitMasks[]) {
+        this(dataType, w, h, w, bitMasks);
+    }
+
+    /**
+     * Instantiates a new SinglePixelPackedSampleModel with the specified
+     * parameters.
+     * 
+     * @param dataType
+     *            the data type of the samples.
+     * @param w
+     *            the width of the image data.
+     * @param h
+     *            the height of the image data.
+     * @param scanlineStride
+     *            the scanline stride of the image data.
+     * @param bitMasks
+     *            the bit masks for all the bands.
+     */
+    public SinglePixelPackedSampleModel(int dataType, int w, int h, int scanlineStride,
+            int bitMasks[]) {
+
+        super(dataType, w, h, bitMasks.length);
+
+        if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT
+                && dataType != DataBuffer.TYPE_INT) {
+            // awt.61=Unsupported data type: {0}
+            throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$
+                    dataType));
+        }
+
+        this.scanlineStride = scanlineStride;
+        this.bitMasks = bitMasks.clone();
+        this.bitOffsets = new int[this.numBands];
+        this.bitSizes = new int[this.numBands];
+
+        this.maxBitSize = 0;
+
+        for (int i = 0; i < this.numBands; i++) {
+            int offset = 0;
+            int size = 0;
+            int mask = bitMasks[i];
+
+            if (mask != 0) {
+                while ((mask & 1) == 0) {
+                    mask >>>= 1;
+                    offset++;
+                }
+
+                while ((mask & 1) == 1) {
+                    mask >>>= 1;
+                    size++;
+                }
+
+                if (mask != 0) {
+                    // awt.62=Wrong mask : {0}
+                    throw new IllegalArgumentException(Messages.getString("awt.62", bitMasks[i])); //$NON-NLS-1$
+                }
+            }
+
+            this.bitOffsets[i] = offset;
+            this.bitSizes[i] = size;
+
+            if (this.maxBitSize < size) {
+                this.maxBitSize = size;
+            }
+
+        }
+
+    }
+
+    @Override
+    public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        switch (getTransferType()) {
+            case DataBuffer.TYPE_BYTE:
+                byte bdata[];
+                if (obj == null) {
+                    bdata = new byte[1];
+                } else {
+                    bdata = (byte[])obj;
+                }
+
+                bdata[0] = (byte)data.getElem(y * scanlineStride + x);
+                obj = bdata;
+                break;
+            case DataBuffer.TYPE_USHORT:
+                short sdata[];
+                if (obj == null) {
+                    sdata = new short[1];
+                } else {
+                    sdata = (short[])obj;
+                }
+
+                sdata[0] = (short)data.getElem(y * scanlineStride + x);
+                obj = sdata;
+                break;
+            case DataBuffer.TYPE_INT:
+                int idata[];
+                if (obj == null) {
+                    idata = new int[1];
+                } else {
+                    idata = (int[])obj;
+                }
+
+                idata[0] = data.getElem(y * scanlineStride + x);
+                obj = idata;
+                break;
+        }
+        return obj;
+    }
+
+    @Override
+    public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        switch (getTransferType()) {
+            case DataBuffer.TYPE_BYTE:
+                data.setElem(y * scanlineStride + x, ((byte[])obj)[0] & 0xff);
+                break;
+            case DataBuffer.TYPE_USHORT:
+                data.setElem(y * scanlineStride + x, ((short[])obj)[0] & 0xffff);
+                break;
+            case DataBuffer.TYPE_INT:
+                data.setElem(y * scanlineStride + x, ((int[])obj)[0]);
+                break;
+        }
+    }
+
+    /**
+     * Compares this SinglePixelPackedSampleModel object with the specified
+     * object.
+     * 
+     * @param o
+     *            the Object to be compared.
+     * @return true, if this SinglePixelPackedSampleModel object is equal to the
+     *         specified object, false otherwise.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) {
+            return false;
+        }
+
+        SinglePixelPackedSampleModel model = (SinglePixelPackedSampleModel)o;
+        return this.width == model.width && this.height == model.height
+                && this.numBands == model.numBands && this.dataType == model.dataType
+                && Arrays.equals(this.bitMasks, model.bitMasks)
+                && Arrays.equals(this.bitOffsets, model.bitOffsets)
+                && Arrays.equals(this.bitSizes, model.bitSizes)
+                && this.scanlineStride == model.scanlineStride;
+    }
+
+    @Override
+    public SampleModel createSubsetSampleModel(int bands[]) {
+        if (bands.length > this.numBands) {
+            // awt.64=The number of the bands in the subset is greater than the
+            // number of bands in the sample model
+            throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$
+        }
+
+        int masks[] = new int[bands.length];
+        for (int i = 0; i < bands.length; i++) {
+            masks[i] = this.bitMasks[bands[i]];
+        }
+        return new SinglePixelPackedSampleModel(this.dataType, this.width, this.height,
+                this.scanlineStride, masks);
+    }
+
+    @Override
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+        return new SinglePixelPackedSampleModel(this.dataType, w, h, this.bitMasks);
+    }
+
+    @Override
+    public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int pixel[];
+        if (iArray == null) {
+            pixel = new int[this.numBands];
+        } else {
+            pixel = iArray;
+        }
+
+        for (int i = 0; i < this.numBands; i++) {
+            pixel[i] = getSample(x, y, i, data);
+        }
+
+        return pixel;
+    }
+
+    @Override
+    public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        for (int i = 0; i < this.numBands; i++) {
+            setSample(x, y, i, iArray[i], data);
+        }
+    }
+
+    @Override
+    public int getSample(int x, int y, int b, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int sample = data.getElem(y * scanlineStride + x);
+        return ((sample & this.bitMasks[b]) >>> this.bitOffsets[b]);
+    }
+
+    @Override
+    public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width)
+                || ((long)y + (long)h > this.height)) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        int pixels[];
+
+        if (iArray == null) {
+            pixels = new int[w * h * this.numBands];
+        } else {
+            pixels = iArray;
+        }
+
+        int idx = 0;
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                for (int n = 0; n < this.numBands; n++) {
+                    pixels[idx++] = getSample(j, i, n, data);
+                }
+            }
+        }
+        return pixels;
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width)
+                || ((long)y + (long)h > this.height)) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        int idx = 0;
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                for (int n = 0; n < this.numBands; n++) {
+                    setSample(j, i, n, iArray[idx++], data);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setSample(int x, int y, int b, int s, DataBuffer data) {
+        if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+        int tmp = data.getElem(y * scanlineStride + x);
+        tmp &= ~this.bitMasks[b];
+        tmp |= (s << this.bitOffsets[b]) & this.bitMasks[b];
+        data.setElem(y * scanlineStride + x, tmp);
+    }
+
+    @Override
+    public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width)
+                || ((long)y + (long)h > this.height)) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        int samples[];
+        int idx = 0;
+
+        if (iArray == null) {
+            samples = new int[w * h];
+        } else {
+            samples = iArray;
+        }
+
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                samples[idx++] = getSample(j, i, b, data);
+            }
+        }
+
+        return samples;
+    }
+
+    @Override
+    public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width)
+                || ((long)y + (long)h > this.height)) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        int idx = 0;
+        for (int i = y; i < y + h; i++) {
+            for (int j = x; j < x + w; j++) {
+                setSample(x + j, y + i, b, iArray[idx++], data);
+            }
+        }
+    }
+
+    @Override
+    public DataBuffer createDataBuffer() {
+        DataBuffer data = null;
+        int size = (this.height - 1) * scanlineStride + width;
+
+        switch (this.dataType) {
+            case DataBuffer.TYPE_BYTE:
+                data = new DataBufferByte(size);
+                break;
+            case DataBuffer.TYPE_USHORT:
+                data = new DataBufferUShort(size);
+                break;
+            case DataBuffer.TYPE_INT:
+                data = new DataBufferInt(size);
+                break;
+        }
+        return data;
+    }
+
+    /**
+     * Gets the offset of the specified pixel in the data array.
+     * 
+     * @param x
+     *            the X coordinate of the specified pixel.
+     * @param y
+     *            the Y coordinate of the specified pixel.
+     * @return the offset of the specified pixel.
+     */
+    public int getOffset(int x, int y) {
+        return (y * scanlineStride + x);
+    }
+
+    @Override
+    public int getSampleSize(int band) {
+        return bitSizes[band];
+    }
+
+    @Override
+    public int[] getSampleSize() {
+        return bitSizes.clone();
+    }
+
+    /**
+     * Gets an array of the bit offsets of the data array elements.
+     * 
+     * @return an array of the bit offsets.
+     */
+    public int[] getBitOffsets() {
+        return bitOffsets.clone();
+    }
+
+    /**
+     * Gets an array of the bit masks for all bands.
+     * 
+     * @return an array of the bit masks for all bands.
+     */
+    public int[] getBitMasks() {
+        return bitMasks.clone();
+    }
+
+    /**
+     * Returns a hash code of this MultiPixelPackedSampleModel class.
+     * 
+     * @return the hash code of this MultiPixelPackedSampleModel class.
+     */
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        int tmp = 0;
+
+        hash = width;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= height;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= numBands;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        hash ^= dataType;
+        tmp = hash >>> 24;
+        hash <<= 8;
+        hash |= tmp;
+        for (int element : bitMasks) {
+            hash ^= element;
+            tmp = hash >>> 24;
+            hash <<= 8;
+            hash |= tmp;
+        }
+        for (int element : bitOffsets) {
+            hash ^= element;
+            tmp = hash >>> 24;
+            hash <<= 8;
+            hash |= tmp;
+        }
+        for (int element : bitSizes) {
+            hash ^= element;
+            tmp = hash >>> 24;
+            hash <<= 8;
+            hash |= tmp;
+        }
+        hash ^= scanlineStride;
+        return hash;
+    }
+
+    /**
+     * Gets the scanline stride.
+     * 
+     * @return the scanline stride
+     */
+    public int getScanlineStride() {
+        return this.scanlineStride;
+    }
+
+    @Override
+    public int getNumDataElements() {
+        return 1;
+    }
+
+}
diff --git a/awt/java/awt/image/TileObserver.java b/awt/java/awt/image/TileObserver.java
new file mode 100644
index 0000000..7dd97e2
--- /dev/null
+++ b/awt/java/awt/image/TileObserver.java
@@ -0,0 +1,49 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+/**
+ * An asynchronous update interface for receiving notifications about tile
+ * information when tiles of a WritableRenderedImage become modifiable or
+ * unmodifiable.
+ * 
+ * @since Android 1.0
+ */
+public interface TileObserver {
+
+    /**
+     * This method is called when information about a tile update is available.
+     * 
+     * @param source
+     *            the source image.
+     * @param tileX
+     *            the X index of the tile.
+     * @param tileY
+     *            the Y index of the tile.
+     * @param willBeWritable
+     *            parameter which indicates whether the tile will be grabbed for
+     *            writing or be released.
+     */
+    public void tileUpdate(WritableRenderedImage source, int tileX, int tileY,
+            boolean willBeWritable);
+
+}
diff --git a/awt/java/awt/image/VolatileImage.java b/awt/java/awt/image/VolatileImage.java
new file mode 100644
index 0000000..f24e866
--- /dev/null
+++ b/awt/java/awt/image/VolatileImage.java
@@ -0,0 +1,146 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.ImageCapabilities;
+import java.awt.Transparency;
+
+/**
+ * The VolatileImage abstract class represents an image which can lose its
+ * contents at any point. VolatileImage objects are device specific. This class
+ * provides methods for checking if operation of this image are compatible for
+ * the GraphicsConfiguration.
+ * 
+ * @since Android 1.0
+ */
+public abstract class VolatileImage extends Image
+// Volatile image implements Transparency since 1.5
+        implements Transparency {
+
+    /**
+     * The Constant IMAGE_INCOMPATIBLE indicates that this VolatileImage is not
+     * applicable for the GraphicsConfiguration object.
+     */
+    public static final int IMAGE_INCOMPATIBLE = 2;
+
+    /**
+     * The Constant IMAGE_OK indicates that VolatileImage is ready for using.
+     */
+    public static final int IMAGE_OK = 0;
+
+    /**
+     * The Constant IMAGE_RESTORED indicates that VolatileImage will be ready to
+     * use after restoring.
+     */
+    public static final int IMAGE_RESTORED = 1;
+
+    /**
+     * The transparency value of this image.
+     */
+    protected int transparency = OPAQUE;
+
+    /**
+     * Instantiates a new VolatileImage object.
+     */
+    public VolatileImage() {
+        super();
+    }
+
+    /**
+     * Returns true if rendering data is lost during validating. This method
+     * should be called after rendering operation of image.
+     * 
+     * @return true, if contents lost during validating, false otherwise.
+     */
+
+    public abstract boolean contentsLost();
+
+    /**
+     * Creates a Graphics2D used to draw in this VolatileImage.
+     * 
+     * @return the Graphics2D object.
+     */
+    public abstract Graphics2D createGraphics();
+
+    /**
+     * Gets the ImageCapabilities of this VolatileImage.
+     * 
+     * @return the ImageCapabilities of this VolatileImage.
+     */
+    public abstract ImageCapabilities getCapabilities();
+
+    /**
+     * Gets the height of this VolatileImage.
+     * 
+     * @return the height of this VolatileImage.
+     */
+    public abstract int getHeight();
+
+    /**
+     * Gets a BufferedImage representation of current VolatileImage that won't
+     * be affected by any changes to this VolatileImage.
+     * 
+     * @return a BufferedImage representation of current VolatileImage.
+     */
+    public abstract BufferedImage getSnapshot();
+
+    /**
+     * Gets the width of this VolatileImage.
+     * 
+     * @return the width of this VolatileImage.
+     */
+    public abstract int getWidth();
+
+    /**
+     * Validates the drawing surface of the image if the surface had been lost
+     * and if the specified GraphicsConfiguration object is applicable to this
+     * image.
+     * 
+     * @param gc
+     *            the GraphicsConfiguration object.
+     * @return one of the image status constants: IMAGE_OK, IMAGE_RESTORED or
+     *         IMAGE_INCOMPATIBLE.
+     */
+    public abstract int validate(GraphicsConfiguration gc);
+
+    @Override
+    public void flush() {
+    }
+
+    @Override
+    public Graphics getGraphics() {
+        return createGraphics();
+    }
+
+    @Override
+    public ImageProducer getSource() {
+        return getSnapshot().getSource();
+    }
+
+    public int getTransparency() {
+        return transparency;
+    }
+}
diff --git a/awt/java/awt/image/WritableRaster.java b/awt/java/awt/image/WritableRaster.java
new file mode 100644
index 0000000..51366ee
--- /dev/null
+++ b/awt/java/awt/image/WritableRaster.java
@@ -0,0 +1,592 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The WritableRaster class provides functionality for writing samples and pixel
+ * capabilities to the Raster.
+ * 
+ * @since Android 1.0
+ */
+public class WritableRaster extends Raster {
+
+    /**
+     * Instantiates a new WritableRaster object with the specified SampleModel,
+     * DataBuffer, rectangular region and parent WritableRaster.
+     * 
+     * @param sampleModel
+     *            the specified SampleModel.
+     * @param dataBuffer
+     *            the specified DataBuffer.
+     * @param aRegion
+     *            the rectangular region which defines the new image bounds.
+     * @param sampleModelTranslate
+     *            this point defines the translation point from the SampleModel
+     *            to the new WritableRaster coordinates.
+     * @param parent
+     *            the parent of this WritableRaster.
+     */
+    protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, Rectangle aRegion,
+            Point sampleModelTranslate, WritableRaster parent) {
+        super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent);
+    }
+
+    /**
+     * Instantiates a new WritableRaster object with the specified SampleModel
+     * which defines a layout of this WritableRaster and DataBuffer objects
+     * which defines the image data.
+     * 
+     * @param sampleModel
+     *            the specified SampleModel.
+     * @param dataBuffer
+     *            the specified DataBuffer.
+     * @param origin
+     *            the point of origin.
+     */
+    protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, Point origin) {
+        this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.width,
+                sampleModel.height), origin, null);
+    }
+
+    /**
+     * Instantiates a new WritableRaster with the specified SampleModel.
+     * 
+     * @param sampleModel
+     *            the specified SampleModel.
+     * @param origin
+     *            the origin.
+     */
+    protected WritableRaster(SampleModel sampleModel, Point origin) {
+        this(sampleModel, sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y,
+                sampleModel.width, sampleModel.height), origin, null);
+    }
+
+    /**
+     * Sets the data for a single pixel from an input Object which represents an
+     * array of primitive types: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+     * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or
+     * DataBuffer.TYPE_DOUBLE.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param inData
+     *            the input data.
+     */
+    public void setDataElements(int x, int y, Object inData) {
+        sampleModel.setDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, inData,
+                dataBuffer);
+    }
+
+    /**
+     * Sets the data elements which represent pixel data to the specified
+     * rectangle area as a primitive array. The following image data types are
+     * supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+     * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or
+     * DataBuffer.TYPE_DOUBLE.
+     * 
+     * @param x
+     *            the X coordinate of the rectangle of pixels.
+     * @param y
+     *            the Y coordinate of the rectangle of pixels.
+     * @param w
+     *            the width of the rectangle of pixels.
+     * @param h
+     *            the height of the rectangle of pixels.
+     * @param inData
+     *            the array of primitive type data to be set to the specified
+     *            area.
+     */
+    public void setDataElements(int x, int y, int w, int h, Object inData) {
+        sampleModel.setDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h,
+                inData, dataBuffer);
+    }
+
+    /**
+     * Creates the child of this WritableRaster by sharing the specified
+     * rectangular area in this WritableRaster. The parentX, parentY, width and
+     * height parameters specify rectangular area to be shared.
+     * 
+     * @param parentX
+     *            the X coordinate of the upper left corner of the shared
+     *            rectangle with respect to this WritableRaster' coordinates.
+     * @param parentY
+     *            the Y coordinate of the upper left corner of the shared
+     *            rectangle with respect to this WritableRaster' coordinates.
+     * @param w
+     *            the width of the child area.
+     * @param h
+     *            the height of the child area.
+     * @param childMinX
+     *            the X coordinate of child area mapped to the parentX
+     *            coordinate.
+     * @param childMinY
+     *            the Y coordinate of child area mapped to the parentY
+     *            coordinate.
+     * @param bandList
+     *            the array of band indices.
+     * @return the child WritableRaster.
+     */
+    public WritableRaster createWritableChild(int parentX, int parentY, int w, int h,
+            int childMinX, int childMinY, int bandList[]) {
+        if (w <= 0 || h <= 0) {
+            // awt.244=Width or Height of child Raster is less than or equal to
+            // zero
+            throw new RasterFormatException(Messages.getString("awt.244")); //$NON-NLS-1$
+        }
+
+        if (parentX < this.minX || parentX + w > this.minX + this.width) {
+            // awt.245=parentX disposes outside Raster
+            throw new RasterFormatException(Messages.getString("awt.245")); //$NON-NLS-1$
+        }
+
+        if (parentY < this.minY || parentY + h > this.minY + this.height) {
+            // awt.246=parentY disposes outside Raster
+            throw new RasterFormatException(Messages.getString("awt.246")); //$NON-NLS-1$
+        }
+
+        if ((long)parentX + w > Integer.MAX_VALUE) {
+            // awt.247=parentX + w results in integer overflow
+            throw new RasterFormatException(Messages.getString("awt.247")); //$NON-NLS-1$
+        }
+
+        if ((long)parentY + h > Integer.MAX_VALUE) {
+            // awt.248=parentY + h results in integer overflow
+            throw new RasterFormatException(Messages.getString("awt.248")); //$NON-NLS-1$
+        }
+
+        if ((long)childMinX + w > Integer.MAX_VALUE) {
+            // awt.249=childMinX + w results in integer overflow
+            throw new RasterFormatException(Messages.getString("awt.249")); //$NON-NLS-1$
+        }
+
+        if ((long)childMinY + h > Integer.MAX_VALUE) {
+            // awt.24A=childMinY + h results in integer overflow
+            throw new RasterFormatException(Messages.getString("awt.24A")); //$NON-NLS-1$
+        }
+
+        SampleModel childModel;
+
+        if (bandList == null) {
+            childModel = sampleModel;
+        } else {
+            childModel = sampleModel.createSubsetSampleModel(bandList);
+        }
+
+        int childTranslateX = childMinX - parentX;
+        int childTranslateY = childMinY - parentY;
+
+        return new WritableRaster(childModel, dataBuffer,
+                new Rectangle(childMinX, childMinY, w, h), new Point(childTranslateX
+                        + sampleModelTranslateX, childTranslateY + sampleModelTranslateY), this);
+    }
+
+    /**
+     * Creates the translated child of this WritableRaster. New WritableRaster
+     * object is a reference to the this WritableRaster and with different
+     * location.
+     * 
+     * @param childMinX
+     *            the X coordinate of the new WritableRaster.
+     * @param childMinY
+     *            the Y coordinate of the new WritableRaster.
+     * @return the WritableRaster.
+     */
+    public WritableRaster createWritableTranslatedChild(int childMinX, int childMinY) {
+        return createWritableChild(minX, minY, width, height, childMinX, childMinY, null);
+    }
+
+    /**
+     * Gets the parent WritableRaster for this WritableRaster object.
+     * 
+     * @return the parent WritableRaster for this WritableRaster object.
+     */
+    public WritableRaster getWritableParent() {
+        return (WritableRaster)parent;
+    }
+
+    /**
+     * Sets pixels from the specified source Raster srcRaster to this
+     * WritableRaster.
+     * 
+     * @param srcRaster
+     *            the source Raster.
+     */
+    public void setRect(Raster srcRaster) {
+        setRect(0, 0, srcRaster);
+    }
+
+    /**
+     * Sets pixels from the specified source Raster srcRaster to this
+     * WritableRaster. Each pixel with (x, y) coordinates from the source Raster
+     * is copied to pixel with (x+dx, y+dy) coordinates in this WritableRaster.
+     * The pixels with (x+dx, y+dy) coordinates which are out the bounds of this
+     * raster are ignored.
+     * 
+     * @param dx
+     *            the distance the pixel's X coordinate in the source Raster is
+     *            translated when writtien to this WritableRaster.
+     * @param dy
+     *            the distance the pixel's Y coordinate in the source Raster is
+     *            translated when writtien to this WritableRaster.
+     * @param srcRaster
+     *            the source Raster.
+     */
+    public void setRect(int dx, int dy, Raster srcRaster) {
+        int w = srcRaster.getWidth();
+        int h = srcRaster.getHeight();
+
+        int srcX = srcRaster.getMinX();
+        int srcY = srcRaster.getMinY();
+
+        int dstX = srcX + dx;
+        int dstY = srcY + dy;
+
+        if (dstX < this.minX) {
+            int minOffX = this.minX - dstX;
+            w -= minOffX;
+            dstX = this.minX;
+            srcX += minOffX;
+        }
+
+        if (dstY < this.minY) {
+            int minOffY = this.minY - dstY;
+            h -= minOffY;
+            dstY = this.minY;
+            srcY += minOffY;
+        }
+
+        if (dstX + w > this.minX + this.width) {
+            int maxOffX = (dstX + w) - (this.minX + this.width);
+            w -= maxOffX;
+        }
+
+        if (dstY + h > this.minY + this.height) {
+            int maxOffY = (dstY + h) - (this.minY + this.height);
+            h -= maxOffY;
+        }
+
+        if (w <= 0 || h <= 0) {
+            return;
+        }
+
+        switch (sampleModel.getDataType()) {
+            case DataBuffer.TYPE_BYTE:
+            case DataBuffer.TYPE_SHORT:
+            case DataBuffer.TYPE_USHORT:
+            case DataBuffer.TYPE_INT:
+                int iPixelsLine[] = null;
+                for (int i = 0; i < h; i++) {
+                    iPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, iPixelsLine);
+                    setPixels(dstX, dstY + i, w, 1, iPixelsLine);
+                }
+                break;
+
+            case DataBuffer.TYPE_FLOAT:
+                float fPixelsLine[] = null;
+                for (int i = 0; i < h; i++) {
+                    fPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, fPixelsLine);
+                    setPixels(dstX, dstY + i, w, 1, fPixelsLine);
+                }
+                break;
+
+            case DataBuffer.TYPE_DOUBLE:
+                double dPixelsLine[] = null;
+                for (int i = 0; i < h; i++) {
+                    dPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, dPixelsLine);
+                    setPixels(dstX, dstY + i, w, 1, dPixelsLine);
+                }
+                break;
+        }
+    }
+
+    /**
+     * Sets the data for a rectangle of pixels from an input Raster to this
+     * WritableRaster.
+     * 
+     * @param x
+     *            the X coordinate of the point where the data of the input
+     *            Raster is to be written.
+     * @param y
+     *            the Y coordinate of the point where the data of the input
+     *            Raster is to be written.
+     * @param inRaster
+     *            the input Raster.
+     */
+    public void setDataElements(int x, int y, Raster inRaster) {
+        int dstX = x + inRaster.getMinX();
+        int dstY = y + inRaster.getMinY();
+
+        int w = inRaster.getWidth();
+        int h = inRaster.getHeight();
+
+        if (dstX < this.minX || dstX + w > this.minX + this.width || dstY < this.minY
+                || dstY + h > this.minY + this.height) {
+            // awt.63=Coordinates are not in bounds
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+        }
+
+        int srcX = inRaster.getMinX();
+        int srcY = inRaster.getMinY();
+        Object line = null;
+
+        for (int i = 0; i < h; i++) {
+            line = inRaster.getDataElements(srcX, srcY + i, w, 1, line);
+            setDataElements(dstX, dstY + i, w, 1, line);
+        }
+    }
+
+    /**
+     * Sets an integer array of samples for the specified pixel in this
+     * WritableRaster.
+     * 
+     * @param x
+     *            the pixel's X coordinate.
+     * @param y
+     *            the pixel's Y coordinate.
+     * @param iArray
+     *            the integer array of samples.
+     */
+    public void setPixel(int x, int y, int iArray[]) {
+        sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, iArray,
+                dataBuffer);
+    }
+
+    /**
+     * Sets a float array of samples for the specified pixel in this
+     * WritableRaster.
+     * 
+     * @param x
+     *            the pixel's X coordinate.
+     * @param y
+     *            the pixel's Y coordinate.
+     * @param fArray
+     *            the float array of samples.
+     */
+    public void setPixel(int x, int y, float fArray[]) {
+        sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, fArray,
+                dataBuffer);
+    }
+
+    /**
+     * Sets a double array of samples for the specified pixel in this
+     * WritableRaster.
+     * 
+     * @param x
+     *            the pixel's X coordinate.
+     * @param y
+     *            the pixel's Y coordinate.
+     * @param dArray
+     *            the double array of samples.
+     */
+    public void setPixel(int x, int y, double dArray[]) {
+        sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, dArray,
+                dataBuffer);
+    }
+
+    /**
+     * Sets a integer array of samples for the specified rectangular area of
+     * pixels in this WritableRaster.
+     * 
+     * @param x
+     *            the X coordinate of rectangular area.
+     * @param y
+     *            the Y coordinate of rectangular area.
+     * @param w
+     *            the width of rectangular area.
+     * @param h
+     *            the height of rectangular area.
+     * @param iArray
+     *            the integer array of samples.
+     */
+    public void setPixels(int x, int y, int w, int h, int iArray[]) {
+        sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, iArray,
+                dataBuffer);
+    }
+
+    /**
+     * Sets a float array of samples for the specified rectangular area of
+     * pixels in this WritableRaster.
+     * 
+     * @param x
+     *            the X coordinate of rectangular area.
+     * @param y
+     *            the Y coordinate of rectangular area.
+     * @param w
+     *            the width of rectangular area.
+     * @param h
+     *            the height of rectangular area.
+     * @param fArray
+     *            the float array of samples.
+     */
+    public void setPixels(int x, int y, int w, int h, float fArray[]) {
+        sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, fArray,
+                dataBuffer);
+    }
+
+    /**
+     * Sets a double array of samples for the specified rectangular area of
+     * pixels in this WritableRaster.
+     * 
+     * @param x
+     *            the X coordinate of rectangular area.
+     * @param y
+     *            the Y coordinate of rectangular area.
+     * @param w
+     *            the width of rectangular area.
+     * @param h
+     *            the height of rectangular area.
+     * @param dArray
+     *            the double array of samples.
+     */
+    public void setPixels(int x, int y, int w, int h, double dArray[]) {
+        sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, dArray,
+                dataBuffer);
+    }
+
+    /**
+     * Sets the samples for the specified band and the specified rectangular
+     * area of pixels with an integer array of samples.
+     * 
+     * @param x
+     *            the X coordinate of the area of pixels.
+     * @param y
+     *            the Y coordinate of the area of pixels.
+     * @param w
+     *            the width of the area of pixels.
+     * @param h
+     *            the height of the area of pixels.
+     * @param b
+     *            the specified band.
+     * @param iArray
+     *            the integer array of samples.
+     */
+    public void setSamples(int x, int y, int w, int h, int b, int iArray[]) {
+        sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, b,
+                iArray, dataBuffer);
+    }
+
+    /**
+     * Sets the samples for the specified band and the specified rectangular
+     * area of pixels with a float array of samples.
+     * 
+     * @param x
+     *            the X coordinate of the area of pixels.
+     * @param y
+     *            the Y coordinate of the area of pixels.
+     * @param w
+     *            the width of the area of pixels.
+     * @param h
+     *            the height of the area of pixels.
+     * @param b
+     *            the specified band.
+     * @param fArray
+     *            the float array of samples.
+     */
+    public void setSamples(int x, int y, int w, int h, int b, float fArray[]) {
+        sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, b,
+                fArray, dataBuffer);
+    }
+
+    /**
+     * Sets the samples for the specified band and the specified rectangular
+     * area of pixels with a double array of samples.
+     * 
+     * @param x
+     *            the X coordinate of the area of pixels.
+     * @param y
+     *            the Y coordinate of the area of pixels.
+     * @param w
+     *            the width of the area of pixels.
+     * @param h
+     *            the height of the area of pixels.
+     * @param b
+     *            the specified band.
+     * @param dArray
+     *            the double array of samples.
+     */
+    public void setSamples(int x, int y, int w, int h, int b, double dArray[]) {
+        sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, b,
+                dArray, dataBuffer);
+    }
+
+    /**
+     * Sets the sample for the specified band and the specified pixel with an
+     * integer sample.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param b
+     *            the specified band.
+     * @param s
+     *            the sample to be set.
+     */
+    public void setSample(int x, int y, int b, int s) {
+        sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, s,
+                dataBuffer);
+    }
+
+    /**
+     * Sets the sample for the specified band and the specified pixel with a
+     * float sample.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param b
+     *            the specified band.
+     * @param s
+     *            the sample to be set.
+     */
+    public void setSample(int x, int y, int b, float s) {
+        sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, s,
+                dataBuffer);
+    }
+
+    /**
+     * Sets the sample for the specified band and the specified pixel with an
+     * integer sample.
+     * 
+     * @param x
+     *            the X coordinate of the pixel.
+     * @param y
+     *            the Y coordinate of the pixel.
+     * @param b
+     *            the specified band.
+     * @param s
+     *            the sample to be set.
+     */
+    public void setSample(int x, int y, int b, double s) {
+        sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, s,
+                dataBuffer);
+    }
+
+}
diff --git a/awt/java/awt/image/WritableRenderedImage.java b/awt/java/awt/image/WritableRenderedImage.java
new file mode 100644
index 0000000..052353b
--- /dev/null
+++ b/awt/java/awt/image/WritableRenderedImage.java
@@ -0,0 +1,109 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.Point;
+
+/**
+ * The WriteableRenderedImage interface is interface for objects which contains
+ * Raster data of one or several tiles. This interface provides notification
+ * mechanism for obtaining tile's writing status.
+ * 
+ * @since Android 1.0
+ */
+public interface WritableRenderedImage extends RenderedImage {
+
+    /**
+     * Gets and checks out the writable tile for writing.
+     * 
+     * @param tileX
+     *            the X index of the tile.
+     * @param tileY
+     *            the Y index of the tile.
+     * @return the WritableRaster.
+     */
+    public WritableRaster getWritableTile(int tileX, int tileY);
+
+    /**
+     * Removes the registered TileObserver.
+     * 
+     * @param to
+     *            the TileObserver which is registered for this
+     *            WritableRenderedImage.
+     */
+    public void removeTileObserver(TileObserver to);
+
+    /**
+     * Adds the specified TileObserver to this WritableRenderedImage.
+     * 
+     * @param to
+     *            the TileObserver object to be added.
+     */
+    public void addTileObserver(TileObserver to);
+
+    /**
+     * Sets this image to the contents of the specified Raster.
+     * 
+     * @param r
+     *            the specified Raster.
+     */
+    public void setData(Raster r);
+
+    /**
+     * Gets the array of points which represent indices of tiles which are check
+     * out for writing.
+     * 
+     * @return the array of points.
+     */
+    public Point[] getWritableTileIndices();
+
+    /**
+     * Checks if the specified tile is writable or not.
+     * 
+     * @param tileX
+     *            the X index of tile.
+     * @param tileY
+     *            the Y index of tile.
+     * @return true, if the specified tile is writable, false otherwise.
+     */
+    public boolean isTileWritable(int tileX, int tileY);
+
+    /**
+     * Release the specified writable tile. This method removes the writer from
+     * the tile.
+     * 
+     * @param tileX
+     *            the X index of the tile.
+     * @param tileY
+     *            the Y index of the tile.
+     */
+    public void releaseWritableTile(int tileX, int tileY);
+
+    /**
+     * Checks if there is a tile which is checked out for writing.
+     * 
+     * @return true, if any tile is checked out for writing, false if there is
+     *         no such tile.
+     */
+    public boolean hasTileWriters();
+
+}
diff --git a/awt/java/awt/image/package.html b/awt/java/awt/image/package.html
new file mode 100644
index 0000000..b4d6ef0
--- /dev/null
+++ b/awt/java/awt/image/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      This package contains classes and interfaces that allow to modify existing images or to create a new image rather than loading it from a file.
+    </p>
+   @since Android 1.0
+  </body>
+</html>
diff --git a/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java b/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java
new file mode 100644
index 0000000..1881a0c
--- /dev/null
+++ b/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java
@@ -0,0 +1,97 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image.renderable;
+
+import java.awt.geom.Rectangle2D;
+import java.awt.image.RenderedImage;
+
+/**
+ * A factory for creating ContextualRenderedImage objects with utilities for
+ * manipulating the properties in the parameter block.
+ * 
+ * @since Android 1.0
+ */
+public interface ContextualRenderedImageFactory extends RenderedImageFactory {
+
+    /**
+     * Maps a render context to a parameter block and a renderable image.
+     * 
+     * @param a0
+     *            the index.
+     * @param a1
+     *            the RenderContext.
+     * @param a2
+     *            the ParameterBlock.
+     * @param a3
+     *            the RenderableImage.
+     * @return the render context.
+     */
+    public RenderContext mapRenderContext(int a0, RenderContext a1, ParameterBlock a2,
+            RenderableImage a3);
+
+    /**
+     * Gets the value of the property from the parameter block.
+     * 
+     * @param a0
+     *            the parameter block to examine to find the property.
+     * @param a1
+     *            the name of the property.
+     * @return the value of the property.
+     */
+    public Object getProperty(ParameterBlock a0, String a1);
+
+    /**
+     * Creates the rendered image determined by the render context and parameter
+     * block.
+     * 
+     * @param a0
+     *            the RenderContext.
+     * @param a1
+     *            the ParameterBlock.
+     * @return the rendered image.
+     */
+    public RenderedImage create(RenderContext a0, ParameterBlock a1);
+
+    /**
+     * Gets the bounding rectangle from the parameter block.
+     * 
+     * @param a0
+     *            the parameter block to read the bounds from.
+     * @return the bounding rectangle.
+     */
+    public Rectangle2D getBounds2D(ParameterBlock a0);
+
+    /**
+     * Gets the names of all of the supported properties.
+     * 
+     * @return the property names.
+     */
+    public String[] getPropertyNames();
+
+    /**
+     * Checks if this image factory is dynamic.
+     * 
+     * @return true, if this image factory is dynamic.
+     */
+    public boolean isDynamic();
+
+}
diff --git a/awt/java/awt/image/renderable/ParameterBlock.java b/awt/java/awt/image/renderable/ParameterBlock.java
new file mode 100644
index 0000000..7dde73a
--- /dev/null
+++ b/awt/java/awt/image/renderable/ParameterBlock.java
@@ -0,0 +1,568 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image.renderable;
+
+import java.awt.image.RenderedImage;
+import java.io.Serializable;
+import java.util.Vector;
+
+/**
+ * The class ParameterBlock groups an indexed set of parameter data with a set
+ * of renderable (source) images. The mapping between the indexed parameters and
+ * their property names is provided by a {@link ContextualRenderedImageFactory}.
+ * 
+ * @since Android 1.0
+ */
+public class ParameterBlock implements Cloneable, Serializable {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -7577115551785240750L;
+
+    /**
+     * The sources (renderable images).
+     */
+    protected Vector<Object> sources = new Vector<Object>();
+
+    /**
+     * The parameters.
+     */
+    protected Vector<Object> parameters = new Vector<Object>();
+
+    /**
+     * Instantiates a new parameter block.
+     * 
+     * @param sources
+     *            the vector of source images.
+     * @param parameters
+     *            the vector of parameters.
+     */
+    public ParameterBlock(Vector<Object> sources, Vector<Object> parameters) {
+        setSources(sources);
+        setParameters(parameters);
+    }
+
+    /**
+     * Instantiates a new parameter block with no parameters.
+     * 
+     * @param sources
+     *            the vector of source images.
+     */
+    public ParameterBlock(Vector<Object> sources) {
+        setSources(sources);
+    }
+
+    /**
+     * Instantiates a new parameter block with no image or parameter vectors.
+     */
+    public ParameterBlock() {
+    }
+
+    /**
+     * Sets the source image at the specified index.
+     * 
+     * @param source
+     *            the source image.
+     * @param index
+     *            the index where the source will be placed.
+     * @return this parameter block.
+     */
+    public ParameterBlock setSource(Object source, int index) {
+        if (sources.size() < index + 1) {
+            sources.setSize(index + 1);
+        }
+        sources.setElementAt(source, index);
+        return this;
+    }
+
+    /**
+     * Sets the parameter value object at the specified index.
+     * 
+     * @param obj
+     *            the parameter value to place at the desired index.
+     * @param index
+     *            the index where the object is to be placed in the vector of
+     *            parameters.
+     * @return this parameter block.
+     */
+    public ParameterBlock set(Object obj, int index) {
+        if (parameters.size() < index + 1) {
+            parameters.setSize(index + 1);
+        }
+        parameters.setElementAt(obj, index);
+        return this;
+    }
+
+    /**
+     * Adds a source to the vector of sources.
+     * 
+     * @param source
+     *            the source to add.
+     * @return this parameter block.
+     */
+    public ParameterBlock addSource(Object source) {
+        sources.addElement(source);
+        return this;
+    }
+
+    /**
+     * Adds the object to the vector of parameter values
+     * 
+     * @param obj
+     *            the obj to add.
+     * @return this parameter block.
+     */
+    public ParameterBlock add(Object obj) {
+        parameters.addElement(obj);
+        return this;
+    }
+
+    /**
+     * Sets the vector of sources, replacing the existing vector of sources, if
+     * any.
+     * 
+     * @param sources
+     *            the new sources.
+     */
+    public void setSources(Vector<Object> sources) {
+        this.sources = sources;
+    }
+
+    /**
+     * Sets the vector of parameters, replacing the existing vector of
+     * parameters, if any.
+     * 
+     * @param parameters
+     *            the new parameters.
+     */
+    public void setParameters(Vector<Object> parameters) {
+        this.parameters = parameters;
+    }
+
+    /**
+     * Gets the vector of sources.
+     * 
+     * @return the sources.
+     */
+    public Vector<Object> getSources() {
+        return sources;
+    }
+
+    /**
+     * Gets the vector of parameters.
+     * 
+     * @return the parameters.
+     */
+    public Vector<Object> getParameters() {
+        return parameters;
+    }
+
+    /**
+     * Gets the source at the specified index.
+     * 
+     * @param index
+     *            the index.
+     * @return the source object found at the specified index.
+     */
+    public Object getSource(int index) {
+        return sources.elementAt(index);
+    }
+
+    /**
+     * Gets the object parameter found at the specified index.
+     * 
+     * @param index
+     *            the index.
+     * @return the parameter object found at the specified index.
+     */
+    public Object getObjectParameter(int index) {
+        return parameters.elementAt(index);
+    }
+
+    /**
+     * Shallow clone (clones using the superclass clone method).
+     * 
+     * @return the clone of this object.
+     */
+    public Object shallowClone() {
+        try {
+            return super.clone();
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns a copy of this ParameterBlock instance.
+     * 
+     * @return the identical copy of this instance.
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public Object clone() {
+        ParameterBlock replica;
+        try {
+            replica = (ParameterBlock)super.clone();
+        } catch (Exception e) {
+            return null;
+        }
+        if (sources != null) {
+            replica.setSources((Vector<Object>)(sources.clone()));
+        }
+        if (parameters != null) {
+            replica.setParameters((Vector<Object>)(parameters.clone()));
+        }
+        return replica;
+    }
+
+    /**
+     * Gets an array of classes corresponding to all of the parameter values
+     * found in the array of parameters, in order.
+     * 
+     * @return the parameter classes.
+     */
+    public Class[] getParamClasses() {
+        int count = parameters.size();
+        Class paramClasses[] = new Class[count];
+
+        for (int i = 0; i < count; i++) {
+            paramClasses[i] = parameters.elementAt(i).getClass();
+        }
+        return paramClasses;
+    }
+
+    /**
+     * Gets the renderable source image found at the specified index in the
+     * source array.
+     * 
+     * @param index
+     *            the index.
+     * @return the renderable source image.
+     */
+    public RenderableImage getRenderableSource(int index) {
+        return (RenderableImage)sources.elementAt(index);
+    }
+
+    /**
+     * Wraps the short value in a Short and places it in the parameter block at
+     * the specified index.
+     * 
+     * @param s
+     *            the short value of the parameter.
+     * @param index
+     *            the index.
+     * @return this parameter block.
+     */
+    public ParameterBlock set(short s, int index) {
+        return set(new Short(s), index);
+    }
+
+    /**
+     * Wraps the short value in a Short and adds it to the parameter block.
+     * 
+     * @param s
+     *            the short value of the parameter.
+     * @return this parameter block.
+     */
+    public ParameterBlock add(short s) {
+        return add(new Short(s));
+    }
+
+    /**
+     * Wraps the long value in a Long and places it in the parameter block at
+     * the specified index.
+     * 
+     * @param l
+     *            the long value of the parameter.
+     * @param index
+     *            the index.
+     * @return this parameter block.
+     */
+    public ParameterBlock set(long l, int index) {
+        return set(new Long(l), index);
+    }
+
+    /**
+     * Wraps the long value in a Long and adds it to the parameter block.
+     * 
+     * @param l
+     *            the long value of the parameter.
+     * @return this parameter block.
+     */
+    public ParameterBlock add(long l) {
+        return add(new Long(l));
+    }
+
+    /**
+     * Wraps the integer value in an Integer and places it in the parameter
+     * block at the specified index.
+     * 
+     * @param i
+     *            the integer value of the parameter.
+     * @param index
+     *            the index.
+     * @return this parameter block.
+     */
+    public ParameterBlock set(int i, int index) {
+        return set(new Integer(i), index);
+    }
+
+    /**
+     * Wraps the integer value in an Integer and adds it to the parameter block.
+     * 
+     * @param i
+     *            the integer value of the parameter.
+     * @return this parameter block.
+     */
+    public ParameterBlock add(int i) {
+        return add(new Integer(i));
+    }
+
+    /**
+     * Wraps the float value in a Float and places it in the parameter block at
+     * the specified index.
+     * 
+     * @param f
+     *            the float value of the parameter.
+     * @param index
+     *            the index.
+     * @return this parameter block.
+     */
+    public ParameterBlock set(float f, int index) {
+        return set(new Float(f), index);
+    }
+
+    /**
+     * Wraps the float value in a Float and adds it to the parameter block.
+     * 
+     * @param f
+     *            the float value of the parameter.
+     * @return this parameter block.
+     */
+    public ParameterBlock add(float f) {
+        return add(new Float(f));
+    }
+
+    /**
+     * Wraps the double value in a Double and places it in the parameter block
+     * at the specified index.
+     * 
+     * @param d
+     *            the double value of the parameter.
+     * @param index
+     *            the index.
+     * @return this parameter block.
+     */
+    public ParameterBlock set(double d, int index) {
+        return set(new Double(d), index);
+    }
+
+    /**
+     * Wraps the double value in a Double and adds it to the parameter block.
+     * 
+     * @param d
+     *            the double value of the parameter.
+     * @return this parameter block.
+     */
+    public ParameterBlock add(double d) {
+        return add(new Double(d));
+    }
+
+    /**
+     * Wraps the char value in a Character and places it in the parameter block
+     * at the specified index.
+     * 
+     * @param c
+     *            the char value of the parameter.
+     * @param index
+     *            the index.
+     * @return this parameter block.
+     */
+    public ParameterBlock set(char c, int index) {
+        return set(new Character(c), index);
+    }
+
+    /**
+     * Wraps the char value in a Character and adds it to the parameter block.
+     * 
+     * @param c
+     *            the char value of the parameter.
+     * @return this parameter block.
+     */
+    public ParameterBlock add(char c) {
+        return add(new Character(c));
+    }
+
+    /**
+     * Wraps the byte value in a Byte and places it in the parameter block at
+     * the specified index.
+     * 
+     * @param b
+     *            the byte value of the parameter.
+     * @param index
+     *            the index.
+     * @return this parameter block.
+     */
+    public ParameterBlock set(byte b, int index) {
+        return set(new Byte(b), index);
+    }
+
+    /**
+     * Wraps the byte value in a Byte and adds it to the parameter block.
+     * 
+     * @param b
+     *            the byte value of the parameter.
+     * @return the parameter block.
+     */
+    public ParameterBlock add(byte b) {
+        return add(new Byte(b));
+    }
+
+    /**
+     * Gets the RenderedImage at the specified index from the vector of source
+     * images.
+     * 
+     * @param index
+     *            the index.
+     * @return the rendered image.
+     */
+    public RenderedImage getRenderedSource(int index) {
+        return (RenderedImage)sources.elementAt(index);
+    }
+
+    /**
+     * Gets the short-valued parameter found at the desired index in the vector
+     * of parameter values.
+     * 
+     * @param index
+     *            the index.
+     * @return the short parameter.
+     */
+    public short getShortParameter(int index) {
+        return ((Short)parameters.elementAt(index)).shortValue();
+    }
+
+    /**
+     * Gets the long-valued parameter found at the desired index in the vector
+     * of parameter values.
+     * 
+     * @param index
+     *            the index.
+     * @return the long parameter.
+     */
+    public long getLongParameter(int index) {
+        return ((Long)parameters.elementAt(index)).longValue();
+    }
+
+    /**
+     * Gets the integer-valued parameter found at the desired index in the
+     * vector of parameter values.
+     * 
+     * @param index
+     *            the index.
+     * @return the integer parameter.
+     */
+    public int getIntParameter(int index) {
+        return ((Integer)parameters.elementAt(index)).intValue();
+    }
+
+    /**
+     * Gets the float-valued parameter found at the desired index in the vector
+     * of parameter values.
+     * 
+     * @param index
+     *            the index.
+     * @return the float parameter.
+     */
+    public float getFloatParameter(int index) {
+        return ((Float)parameters.elementAt(index)).floatValue();
+    }
+
+    /**
+     * Gets the double-valued parameter found at the desired index in the vector
+     * of parameter values.
+     * 
+     * @param index
+     *            the index.
+     * @return the double parameter.
+     */
+    public double getDoubleParameter(int index) {
+        return ((Double)parameters.elementAt(index)).doubleValue();
+    }
+
+    /**
+     * Gets the char-valued parameter found at the desired index in the vector
+     * of parameter values.
+     * 
+     * @param index
+     *            the index.
+     * @return the char parameter.
+     */
+    public char getCharParameter(int index) {
+        return ((Character)parameters.elementAt(index)).charValue();
+    }
+
+    /**
+     * Gets the byte-valued parameter found at the desired index in the vector
+     * of parameter values.
+     * 
+     * @param index
+     *            the index.
+     * @return the byte parameter.
+     */
+    public byte getByteParameter(int index) {
+        return ((Byte)parameters.elementAt(index)).byteValue();
+    }
+
+    /**
+     * Clears the vector of sources.
+     */
+    public void removeSources() {
+        sources.removeAllElements();
+    }
+
+    /**
+     * Clears the vector of parameters.
+     */
+    public void removeParameters() {
+        parameters.removeAllElements();
+    }
+
+    /**
+     * Gets the number of elements in the vector of sources.
+     * 
+     * @return the number of elements in the vector of sources.
+     */
+    public int getNumSources() {
+        return sources.size();
+    }
+
+    /**
+     * Gets the number of elements in the vector of parameters.
+     * 
+     * @return the number of elements in the vector of parameters.
+     */
+    public int getNumParameters() {
+        return parameters.size();
+    }
+}
diff --git a/awt/java/awt/image/renderable/RenderContext.java b/awt/java/awt/image/renderable/RenderContext.java
new file mode 100644
index 0000000..0db512f
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderContext.java
@@ -0,0 +1,214 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image.renderable;
+
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+
+/**
+ * The Class RenderContext stores data on how an image is to be rendered: the
+ * affine transform, the area of interest, and the rendering hints.
+ * 
+ * @since Android 1.0
+ */
+public class RenderContext implements Cloneable {
+
+    /**
+     * The affine transform.
+     */
+    AffineTransform transform;
+
+    /**
+     * The area of interest.
+     */
+    Shape aoi;
+
+    /**
+     * The rendering hints.
+     */
+    RenderingHints hints;
+
+    /**
+     * Instantiates a new render context.
+     * 
+     * @param usr2dev
+     *            the affine transform.
+     * @param aoi
+     *            the area of interest.
+     * @param hints
+     *            the rendering hints.
+     */
+    public RenderContext(AffineTransform usr2dev, Shape aoi, RenderingHints hints) {
+        this.transform = (AffineTransform)usr2dev.clone();
+        this.aoi = aoi;
+        this.hints = hints;
+    }
+
+    /**
+     * Instantiates a new render context with no specified hints.
+     * 
+     * @param usr2dev
+     *            the affine transform.
+     * @param aoi
+     *            the area of interest.
+     */
+    public RenderContext(AffineTransform usr2dev, Shape aoi) {
+        this(usr2dev, aoi, null);
+    }
+
+    /**
+     * Instantiates a new render context with no specified area of interest.
+     * 
+     * @param usr2dev
+     *            the affine transform.
+     * @param hints
+     *            the rendering hints.
+     */
+    public RenderContext(AffineTransform usr2dev, RenderingHints hints) {
+        this(usr2dev, null, hints);
+    }
+
+    /**
+     * Instantiates a new render context with no rendering hints or area of
+     * interest.
+     * 
+     * @param usr2dev
+     *            the affine transform.
+     */
+    public RenderContext(AffineTransform usr2dev) {
+        this(usr2dev, null, null);
+    }
+
+    @Override
+    public Object clone() {
+        return new RenderContext(transform, aoi, hints);
+    }
+
+    /**
+     * Sets the affine transform for this render context.
+     * 
+     * @param newTransform
+     *            the new affine transform.
+     */
+    public void setTransform(AffineTransform newTransform) {
+        transform = (AffineTransform)newTransform.clone();
+    }
+
+    /**
+     * Concatenates the current transform with the specified transform (so they
+     * are applied with the specified transform acting first) and sets the
+     * resulting transform as the affine transform of this rendering context.
+     * 
+     * @param modTransform
+     *            the new transform which modifies the current transform.
+     * @deprecated use
+     *             {@link RenderContext#preConcatenateTransform(AffineTransform)}
+     *             .
+     */
+    @Deprecated
+    public void preConcetenateTransform(AffineTransform modTransform) {
+        preConcatenateTransform(modTransform);
+    }
+
+    /**
+     * Concatenates the current transform with the specified transform (so they
+     * are applied with the specified transform acting first) and sets the
+     * resulting transform as the affine transform of this rendering context.
+     * 
+     * @param modTransform
+     *            the new transform which modifies the current transform.
+     */
+    public void preConcatenateTransform(AffineTransform modTransform) {
+        transform.preConcatenate(modTransform);
+    }
+
+    /**
+     * Concatenate the specified transform with the current transform.
+     * 
+     * @param modTransform
+     *            the new transform which modifies the current transform.
+     * @deprecated use
+     *             {@link RenderContext#concatenateTransform(AffineTransform)}.
+     */
+    @Deprecated
+    public void concetenateTransform(AffineTransform modTransform) {
+        concatenateTransform(modTransform);
+    }
+
+    /**
+     * Concatenate the specified transform with the current transform.
+     * 
+     * @param modTransform
+     *            the new transform which modifies the current transform.
+     */
+    public void concatenateTransform(AffineTransform modTransform) {
+        transform.concatenate(modTransform);
+    }
+
+    /**
+     * Gets the transform.
+     * 
+     * @return the transform.
+     */
+    public AffineTransform getTransform() {
+        return (AffineTransform)transform.clone();
+    }
+
+    /**
+     * Sets the area of interest.
+     * 
+     * @param newAoi
+     *            the new area of interest.
+     */
+    public void setAreaOfInterest(Shape newAoi) {
+        aoi = newAoi;
+    }
+
+    /**
+     * Gets the area of interest.
+     * 
+     * @return the area of interest.
+     */
+    public Shape getAreaOfInterest() {
+        return aoi;
+    }
+
+    /**
+     * Sets the rendering hints.
+     * 
+     * @param hints
+     *            the new rendering hints.
+     */
+    public void setRenderingHints(RenderingHints hints) {
+        this.hints = hints;
+    }
+
+    /**
+     * Gets the rendering hints.
+     * 
+     * @return the rendering hints.
+     */
+    public RenderingHints getRenderingHints() {
+        return hints;
+    }
+}
diff --git a/awt/java/awt/image/renderable/RenderableImage.java b/awt/java/awt/image/renderable/RenderableImage.java
new file mode 100644
index 0000000..21332f7
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderableImage.java
@@ -0,0 +1,138 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image.renderable;
+
+import java.awt.RenderingHints;
+import java.awt.image.RenderedImage;
+import java.util.Vector;
+
+/**
+ * The Interface RenderableImage is implemented by an object that collects all
+ * of the image-specific data that defines a single image that could be rendered
+ * to different rendering targets.
+ * 
+ * @since Android 1.0
+ */
+public interface RenderableImage {
+
+    /**
+     * The Constant HINTS_OBSERVED indicates that the rendering hints are
+     * applied rather than ignored.
+     */
+    public static final String HINTS_OBSERVED = "HINTS_OBSERVED"; //$NON-NLS-1$
+
+    /**
+     * Gets the property from the RenderableImage's parameter block.
+     * 
+     * @param name
+     *            the name of the property to get.
+     * @return the value of the property.
+     */
+    public Object getProperty(String name);
+
+    /**
+     * Creates the rendered image based on the information contained in the
+     * parameters and the render context.
+     * 
+     * @param renderContext
+     *            the render context giving rendering specifications such as
+     *            transformations.
+     * @return the rendered image.
+     */
+    public RenderedImage createRendering(RenderContext renderContext);
+
+    /**
+     * Creates the scaled rendered image based on the information contained in
+     * the parameters and the render context.
+     * 
+     * @param w
+     *            the desired width after scaling or zero if the scaling should
+     *            be proportional, based on the height.
+     * @param h
+     *            the desired height after scaling or zero if the scaling should
+     *            be proportional, based on the width.
+     * @param hints
+     *            the rendering hints to use.
+     * @return the rendered image.
+     * @throws IllegalArgumentException
+     *             if both the height and width are zero.
+     */
+    public RenderedImage createScaledRendering(int w, int h, RenderingHints hints);
+
+    /**
+     * Gets the vector of sources from the parameter block.
+     * 
+     * @return the sources.
+     */
+    public Vector<RenderableImage> getSources();
+
+    /**
+     * Gets the names of all of the supported properties in the current context.
+     * 
+     * @return the property names.
+     */
+    public String[] getPropertyNames();
+
+    /**
+     * Creates the default rendering (using the identity transform and default
+     * render context).
+     * 
+     * @return the rendered image.
+     */
+    public RenderedImage createDefaultRendering();
+
+    /**
+     * Checks if this context supports dynamic rendering.
+     * 
+     * @return true, if this context supports dynamic rendering.
+     */
+    public boolean isDynamic();
+
+    /**
+     * Gets the width of the image.
+     * 
+     * @return the width of the image.
+     */
+    public float getWidth();
+
+    /**
+     * Gets the y coordinate of the upper left corner.
+     * 
+     * @return the y coordinate of the upper left corner.
+     */
+    public float getMinY();
+
+    /**
+     * Gets the x coordinate of the upper left corner.
+     * 
+     * @return the x coordinate of the upper left corner.
+     */
+    public float getMinX();
+
+    /**
+     * Gets the height of the image.
+     * 
+     * @return the height of the image.
+     */
+    public float getHeight();
+
+}
diff --git a/awt/java/awt/image/renderable/RenderableImageOp.java b/awt/java/awt/image/renderable/RenderableImageOp.java
new file mode 100644
index 0000000..dc45372
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderableImageOp.java
@@ -0,0 +1,191 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image.renderable;
+
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.RenderedImage;
+import java.util.Vector;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class RenderableImageOp is a basic implementation of RenderableImage,
+ * with methods to access the parameter data and perform rendering operations.
+ * 
+ * @since Android 1.0
+ */
+public class RenderableImageOp implements RenderableImage {
+
+    /**
+     * The CRIF.
+     */
+    ContextualRenderedImageFactory CRIF;
+
+    /**
+     * The param block.
+     */
+    ParameterBlock paramBlock;
+
+    /**
+     * The height.
+     */
+    float minX, minY, width, height;
+
+    /**
+     * Instantiates a new renderable image op.
+     * 
+     * @param CRIF
+     *            the cRIF.
+     * @param paramBlock
+     *            the param block.
+     */
+    public RenderableImageOp(ContextualRenderedImageFactory CRIF, ParameterBlock paramBlock) {
+        this.CRIF = CRIF;
+        this.paramBlock = (ParameterBlock)paramBlock.clone();
+        Rectangle2D r = CRIF.getBounds2D(paramBlock);
+        minX = (float)r.getMinX();
+        minY = (float)r.getMinY();
+        width = (float)r.getWidth();
+        height = (float)r.getHeight();
+    }
+
+    public Object getProperty(String name) {
+        return CRIF.getProperty(paramBlock, name);
+    }
+
+    /**
+     * Sets the parameter block.
+     * 
+     * @param paramBlock
+     *            the param block.
+     * @return the parameter block.
+     */
+    public ParameterBlock setParameterBlock(ParameterBlock paramBlock) {
+        ParameterBlock oldParam = this.paramBlock;
+        this.paramBlock = (ParameterBlock)paramBlock.clone();
+        return oldParam;
+    }
+
+    public RenderedImage createRendering(RenderContext renderContext) {
+
+        Vector<RenderableImage> sources = getSources();
+        ParameterBlock rdParam = (ParameterBlock)paramBlock.clone();
+
+        if (sources != null) {
+            Vector<Object> rdSources = new Vector<Object>();
+            int i = 0;
+            while (i < sources.size()) {
+                RenderContext newContext = CRIF
+                        .mapRenderContext(i, renderContext, paramBlock, this);
+                RenderedImage rdim = sources.elementAt(i).createRendering(newContext);
+
+                if (rdim != null) {
+                    rdSources.addElement(rdim);
+                }
+                i++;
+            }
+            if (rdSources.size() > 0) {
+                rdParam.setSources(rdSources);
+            }
+        }
+        return CRIF.create(renderContext, rdParam);
+    }
+
+    public RenderedImage createScaledRendering(int w, int h, RenderingHints hints) {
+        if (w == 0 && h == 0) {
+            // awt.60=Width and Height mustn't be equal zero both
+            throw new IllegalArgumentException(Messages.getString("awt.60")); //$NON-NLS-1$
+        }
+        if (w == 0) {
+            w = Math.round(h * (getWidth() / getHeight()));
+        }
+
+        if (h == 0) {
+            h = Math.round(w * (getHeight() / getWidth()));
+        }
+
+        double sx = (double)w / getWidth();
+        double sy = (double)h / getHeight();
+
+        AffineTransform at = AffineTransform.getScaleInstance(sx, sy);
+        RenderContext context = new RenderContext(at, hints);
+        return createRendering(context);
+    }
+
+    public Vector<RenderableImage> getSources() {
+        if (paramBlock.getNumSources() == 0) {
+            return null;
+        }
+        Vector<RenderableImage> v = new Vector<RenderableImage>();
+        int i = 0;
+        while (i < paramBlock.getNumSources()) {
+            Object o = paramBlock.getSource(i);
+            if (o instanceof RenderableImage) {
+                v.addElement((RenderableImage)o);
+            }
+            i++;
+        }
+        return v;
+    }
+
+    public String[] getPropertyNames() {
+        return CRIF.getPropertyNames();
+    }
+
+    /**
+     * Gets the parameter block.
+     * 
+     * @return the parameter block
+     */
+    public ParameterBlock getParameterBlock() {
+        return paramBlock;
+    }
+
+    public RenderedImage createDefaultRendering() {
+        AffineTransform at = new AffineTransform();
+        RenderContext context = new RenderContext(at);
+        return createRendering(context);
+    }
+
+    public boolean isDynamic() {
+        return CRIF.isDynamic();
+    }
+
+    public float getWidth() {
+        return width;
+    }
+
+    public float getMinY() {
+        return minY;
+    }
+
+    public float getMinX() {
+        return minX;
+    }
+
+    public float getHeight() {
+        return height;
+    }
+
+}
diff --git a/awt/java/awt/image/renderable/RenderableImageProducer.java b/awt/java/awt/image/renderable/RenderableImageProducer.java
new file mode 100644
index 0000000..e83ebc7
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderableImageProducer.java
@@ -0,0 +1,151 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image.renderable;
+
+import java.awt.image.ColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageProducer;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.util.Vector;
+
+/**
+ * The Class RenderableImageProducer provides the implementation for the image
+ * rendering.
+ * 
+ * @since Android 1.0
+ */
+public class RenderableImageProducer implements ImageProducer, Runnable {
+
+    /**
+     * The rbl.
+     */
+    RenderableImage rbl;
+
+    /**
+     * The rc.
+     */
+    RenderContext rc;
+
+    /**
+     * The consumers.
+     */
+    Vector<ImageConsumer> consumers = new Vector<ImageConsumer>();
+
+    /**
+     * Instantiates a new renderable image producer.
+     * 
+     * @param rdblImage
+     *            the rdbl image.
+     * @param rc
+     *            the rc.
+     */
+    public RenderableImageProducer(RenderableImage rdblImage, RenderContext rc) {
+        this.rbl = rdblImage;
+        this.rc = rc;
+    }
+
+    /**
+     * Sets the render context.
+     * 
+     * @param rc
+     *            the new render context.
+     */
+    public synchronized void setRenderContext(RenderContext rc) {
+        this.rc = rc;
+    }
+
+    public synchronized boolean isConsumer(ImageConsumer ic) {
+        return consumers.contains(ic);
+    }
+
+    public synchronized void startProduction(ImageConsumer ic) {
+        addConsumer(ic);
+        Thread t = new Thread(this, "RenderableImageProducer thread"); //$NON-NLS-1$
+        t.start();
+    }
+
+    public void requestTopDownLeftRightResend(ImageConsumer ic) {
+    }
+
+    public synchronized void removeConsumer(ImageConsumer ic) {
+        if (ic != null) {
+            consumers.removeElement(ic);
+        }
+    }
+
+    public synchronized void addConsumer(ImageConsumer ic) {
+        if (ic != null && !consumers.contains(ic)) {
+            consumers.addElement(ic);
+        }
+    }
+
+    /**
+     * Creates the rendered image in a new thread.
+     */
+    public void run() {
+        if (rbl == null) {
+            return;
+        }
+
+        RenderedImage rd;
+        if (rc != null) {
+            rd = rbl.createRendering(rc);
+        } else {
+            rd = rbl.createDefaultRendering();
+        }
+
+        ColorModel cm = rd.getColorModel();
+        if (cm == null) {
+            cm = ColorModel.getRGBdefault();
+        }
+
+        Raster r = rd.getData();
+        int w = r.getWidth();
+        int h = r.getHeight();
+
+        for (ImageConsumer c : consumers) {
+            c.setDimensions(w, h);
+            c.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES
+                    | ImageConsumer.SINGLEFRAME | ImageConsumer.SINGLEPASS);
+        }
+
+        int scanLine[] = new int[w];
+        int pixel[] = null;
+
+        for (int y = 0; y < h; y++) {
+            for (int x = 0; x < w; x++) {
+                pixel = r.getPixel(x, y, pixel);
+                scanLine[x] = cm.getDataElement(pixel, 0);
+            }
+
+            for (ImageConsumer c : consumers) {
+                c.setPixels(0, y, w, 1, cm, scanLine, 0, w);
+            }
+        }
+
+        for (ImageConsumer c : consumers) {
+            c.imageComplete(ImageConsumer.STATICIMAGEDONE);
+        }
+    }
+
+}
diff --git a/awt/java/awt/image/renderable/RenderedImageFactory.java b/awt/java/awt/image/renderable/RenderedImageFactory.java
new file mode 100644
index 0000000..881a40a
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderedImageFactory.java
@@ -0,0 +1,46 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package java.awt.image.renderable;
+
+import java.awt.RenderingHints;
+import java.awt.image.RenderedImage;
+
+/**
+ * A factory for creating RenderedImage objects based on parameters and
+ * rendering hints.
+ * 
+ * @since Android 1.0
+ */
+public interface RenderedImageFactory {
+
+    /**
+     * Creates the rendered image.
+     * 
+     * @param a0
+     *            the ParameterBlock.
+     * @param a1
+     *            the RenderingHints.
+     * @return the rendered image.
+     */
+    public RenderedImage create(ParameterBlock a0, RenderingHints a1);
+
+}
diff --git a/awt/java/awt/image/renderable/package.html b/awt/java/awt/image/renderable/package.html
new file mode 100644
index 0000000..43aaabc
--- /dev/null
+++ b/awt/java/awt/image/renderable/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      This package contains classes to create images which are rendering-independent.
+    </p>
+    @since Android 1.0
+  </body>
+</html>
diff --git a/awt/java/awt/package.html b/awt/java/awt/package.html
new file mode 100644
index 0000000..5a6f9f0
--- /dev/null
+++ b/awt/java/awt/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      This package contains classes and interfaces for creating (graphical) user interfaces (GUI), painting 2D graphics and creating, manipulating and drawing images. 
+    </p>
+  @since Android 1.0
+  </body>
+</html>
diff --git a/awt/java/awt/peer/ButtonPeer.java b/awt/java/awt/peer/ButtonPeer.java
new file mode 100644
index 0000000..cc45b49
--- /dev/null
+++ b/awt/java/awt/peer/ButtonPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ButtonPeer {
+
+}
diff --git a/awt/java/awt/peer/CanvasPeer.java b/awt/java/awt/peer/CanvasPeer.java
new file mode 100644
index 0000000..e276366
--- /dev/null
+++ b/awt/java/awt/peer/CanvasPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface CanvasPeer {
+
+}
diff --git a/awt/java/awt/peer/CheckboxMenuItemPeer.java b/awt/java/awt/peer/CheckboxMenuItemPeer.java
new file mode 100644
index 0000000..296f422
--- /dev/null
+++ b/awt/java/awt/peer/CheckboxMenuItemPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface CheckboxMenuItemPeer {
+
+}
diff --git a/awt/java/awt/peer/CheckboxPeer.java b/awt/java/awt/peer/CheckboxPeer.java
new file mode 100644
index 0000000..e9f8dd1
--- /dev/null
+++ b/awt/java/awt/peer/CheckboxPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface CheckboxPeer {
+
+}
diff --git a/awt/java/awt/peer/ChoicePeer.java b/awt/java/awt/peer/ChoicePeer.java
new file mode 100644
index 0000000..57b7629
--- /dev/null
+++ b/awt/java/awt/peer/ChoicePeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ChoicePeer {
+
+}
diff --git a/awt/java/awt/peer/ComponentPeer.java b/awt/java/awt/peer/ComponentPeer.java
new file mode 100644
index 0000000..bc26791
--- /dev/null
+++ b/awt/java/awt/peer/ComponentPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ComponentPeer {
+
+}
diff --git a/awt/java/awt/peer/DialogPeer.java b/awt/java/awt/peer/DialogPeer.java
new file mode 100644
index 0000000..8ae3049
--- /dev/null
+++ b/awt/java/awt/peer/DialogPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface DialogPeer {
+
+}
diff --git a/awt/java/awt/peer/FileDialogPeer.java b/awt/java/awt/peer/FileDialogPeer.java
new file mode 100644
index 0000000..0d15e48
--- /dev/null
+++ b/awt/java/awt/peer/FileDialogPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface FileDialogPeer {
+
+}
diff --git a/awt/java/awt/peer/FontPeer.java b/awt/java/awt/peer/FontPeer.java
new file mode 100644
index 0000000..fd9815f
--- /dev/null
+++ b/awt/java/awt/peer/FontPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface FontPeer {
+
+}
diff --git a/awt/java/awt/peer/FramePeer.java b/awt/java/awt/peer/FramePeer.java
new file mode 100644
index 0000000..9cfc40b
--- /dev/null
+++ b/awt/java/awt/peer/FramePeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface FramePeer {
+
+}
diff --git a/awt/java/awt/peer/LabelPeer.java b/awt/java/awt/peer/LabelPeer.java
new file mode 100644
index 0000000..052ca9d
--- /dev/null
+++ b/awt/java/awt/peer/LabelPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface LabelPeer {
+
+}
diff --git a/awt/java/awt/peer/LightweightPeer.java b/awt/java/awt/peer/LightweightPeer.java
new file mode 100644
index 0000000..1dee905
--- /dev/null
+++ b/awt/java/awt/peer/LightweightPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface LightweightPeer {
+
+}
diff --git a/awt/java/awt/peer/ListPeer.java b/awt/java/awt/peer/ListPeer.java
new file mode 100644
index 0000000..0a27885
--- /dev/null
+++ b/awt/java/awt/peer/ListPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ListPeer {
+
+}
diff --git a/awt/java/awt/peer/MenuBarPeer.java b/awt/java/awt/peer/MenuBarPeer.java
new file mode 100644
index 0000000..3ad2c16
--- /dev/null
+++ b/awt/java/awt/peer/MenuBarPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MenuBarPeer {
+
+}
diff --git a/awt/java/awt/peer/MenuComponentPeer.java b/awt/java/awt/peer/MenuComponentPeer.java
new file mode 100644
index 0000000..3ac3b34
--- /dev/null
+++ b/awt/java/awt/peer/MenuComponentPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MenuComponentPeer {
+
+}
diff --git a/awt/java/awt/peer/MenuItemPeer.java b/awt/java/awt/peer/MenuItemPeer.java
new file mode 100644
index 0000000..b133897
--- /dev/null
+++ b/awt/java/awt/peer/MenuItemPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MenuItemPeer {
+
+}
diff --git a/awt/java/awt/peer/MenuPeer.java b/awt/java/awt/peer/MenuPeer.java
new file mode 100644
index 0000000..d643ce7
--- /dev/null
+++ b/awt/java/awt/peer/MenuPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MenuPeer {
+
+}
diff --git a/awt/java/awt/peer/MouseInfoPeer.java b/awt/java/awt/peer/MouseInfoPeer.java
new file mode 100644
index 0000000..9173a62
--- /dev/null
+++ b/awt/java/awt/peer/MouseInfoPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MouseInfoPeer {
+
+}
diff --git a/awt/java/awt/peer/PanelPeer.java b/awt/java/awt/peer/PanelPeer.java
new file mode 100644
index 0000000..1faa1fe
--- /dev/null
+++ b/awt/java/awt/peer/PanelPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface PanelPeer {
+
+}
diff --git a/awt/java/awt/peer/PopupMenuPeer.java b/awt/java/awt/peer/PopupMenuPeer.java
new file mode 100644
index 0000000..cf1ef61
--- /dev/null
+++ b/awt/java/awt/peer/PopupMenuPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface PopupMenuPeer {
+
+}
diff --git a/awt/java/awt/peer/ScrollPanePeer.java b/awt/java/awt/peer/ScrollPanePeer.java
new file mode 100644
index 0000000..df3de83
--- /dev/null
+++ b/awt/java/awt/peer/ScrollPanePeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ScrollPanePeer {
+
+}
diff --git a/awt/java/awt/peer/ScrollbarPeer.java b/awt/java/awt/peer/ScrollbarPeer.java
new file mode 100644
index 0000000..eec8961
--- /dev/null
+++ b/awt/java/awt/peer/ScrollbarPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ScrollbarPeer {
+
+}
diff --git a/awt/java/awt/peer/TextAreaPeer.java b/awt/java/awt/peer/TextAreaPeer.java
new file mode 100644
index 0000000..636707f
--- /dev/null
+++ b/awt/java/awt/peer/TextAreaPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface TextAreaPeer {
+
+}
diff --git a/awt/java/awt/peer/TextFieldPeer.java b/awt/java/awt/peer/TextFieldPeer.java
new file mode 100644
index 0000000..2b8232a
--- /dev/null
+++ b/awt/java/awt/peer/TextFieldPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface TextFieldPeer {
+
+}
diff --git a/awt/java/awt/peer/WindowPeer.java b/awt/java/awt/peer/WindowPeer.java
new file mode 100644
index 0000000..384646f
--- /dev/null
+++ b/awt/java/awt/peer/WindowPeer.java
@@ -0,0 +1,25 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface WindowPeer {
+
+}
diff --git a/awt/java/beans/FeatureDescriptor.java b/awt/java/beans/FeatureDescriptor.java
new file mode 100644
index 0000000..2945c65
--- /dev/null
+++ b/awt/java/beans/FeatureDescriptor.java
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ */
+
+package java.beans;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * Common base class for Descriptors.
+ */
+public class FeatureDescriptor {
+
+    private Map<String, Object> values;
+
+    boolean preferred, hidden, expert;
+
+    String shortDescription;
+
+    String name;
+
+    String displayName;
+
+    /**
+     * <p>
+     * Constructs an instance.
+     * </p>
+     */
+    public FeatureDescriptor() {
+        this.values = new HashMap<String, Object>();
+    }
+
+    /**
+     * <p>
+     * Sets the value for the named attribute.
+     * </p>
+     * 
+     * @param attributeName
+     *            The name of the attribute to set a value with.
+     * @param value
+     *            The value to set.
+     */
+    public void setValue(String attributeName, Object value) {
+        if (attributeName == null || value == null) {
+            throw new NullPointerException();
+        }
+        values.put(attributeName, value);
+    }
+
+    /**
+     * <p>
+     * Gets the value associated with the named attribute.
+     * </p>
+     * 
+     * @param attributeName
+     *            The name of the attribute to get a value for.
+     * @return The attribute's value.
+     */
+    public Object getValue(String attributeName) {
+        Object result = null;
+        if (attributeName != null) {
+            result = values.get(attributeName);
+        }
+        return result;
+    }
+
+    /**
+     * <p>
+     * Enumerates the attribute names.
+     * </p>
+     * 
+     * @return An instance of {@link Enumeration}.
+     */
+    public Enumeration<String> attributeNames() {
+        // Create a new list, so that the references are copied
+        return Collections.enumeration(new LinkedList<String>(values.keySet()));
+    }
+
+    /**
+     * <p>
+     * Sets the short description.
+     * </p>
+     * 
+     * @param text
+     *            The description to set.
+     */
+    public void setShortDescription(String text) {
+        this.shortDescription = text;
+    }
+
+    /**
+     * <p>
+     * Sets the name.
+     * </p>
+     * 
+     * @param name
+     *            The name to set.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * <p>
+     * Sets the display name.
+     * </p>
+     * 
+     * @param displayName
+     *            The display name to set.
+     */
+    public void setDisplayName(String displayName) {
+        this.displayName = displayName;
+    }
+
+    /**
+     * <p>
+     * Gets the short description or {@link #getDisplayName()} if not set.
+     * </p>
+     * 
+     * @return The description.
+     */
+    public String getShortDescription() {
+        return shortDescription == null ? getDisplayName() : shortDescription;
+    }
+
+    /**
+     * <p>
+     * Gets the name.
+     * </p>
+     * 
+     * @return The name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * <p>
+     * Gets the display name or {@link #getName()} if not set.
+     * </p>
+     * 
+     * @return The display name.
+     */
+    public String getDisplayName() {
+        return displayName == null ? getName() : displayName;
+    }
+
+    /**
+     * <p>
+     * Sets the preferred indicator.
+     * </p>
+     * 
+     * @param preferred
+     *            <code>true</code> if preferred, <code>false</code>
+     *            otherwise.
+     */
+    public void setPreferred(boolean preferred) {
+        this.preferred = preferred;
+    }
+
+    /**
+     * <p>
+     * Sets the hidden indicator.
+     * </p>
+     * 
+     * @param hidden
+     *            <code>true</code> if hidden, <code>false</code> otherwise.
+     */
+    public void setHidden(boolean hidden) {
+        this.hidden = hidden;
+    }
+
+    /**
+     * <p>
+     * Sets the expert indicator.
+     * </p>
+     * 
+     * @param expert
+     *            <code>true</code> if expert, <code>false</code> otherwise.
+     */
+    public void setExpert(boolean expert) {
+        this.expert = expert;
+    }
+
+    /**
+     * <p>
+     * Indicates if this feature is preferred.
+     * </p>
+     * 
+     * @return <code>true</code> if preferred, <code>false</code> otherwise.
+     */
+    public boolean isPreferred() {
+        return preferred;
+    }
+
+    /**
+     * <p>
+     * Indicates if this feature is hidden.
+     * </p>
+     * 
+     * @return <code>true</code> if hidden, <code>false</code> otherwise.
+     */
+    public boolean isHidden() {
+        return hidden;
+    }
+
+    /**
+     * <p>
+     * Indicates if this feature is an expert feature.
+     * </p>
+     * 
+     * @return <code>true</code> if hidden, <code>false</code> otherwise.
+     */
+    public boolean isExpert() {
+        return expert;
+    }
+}
diff --git a/awt/java/beans/IndexedPropertyDescriptor.java b/awt/java/beans/IndexedPropertyDescriptor.java
new file mode 100644
index 0000000..25667d9
--- /dev/null
+++ b/awt/java/beans/IndexedPropertyDescriptor.java
@@ -0,0 +1,227 @@
+/*
+ *  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.
+ */
+
+package java.beans;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class IndexedPropertyDescriptor extends PropertyDescriptor {
+    private Method indexedGetter;
+
+    private Method indexedSetter;
+
+    public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass,
+            String getterName, String setterName, String indexedGetterName,
+            String indexedSetterName) throws IntrospectionException {
+        super(propertyName, beanClass, getterName, setterName);
+
+        // RI behaves like this
+        if (indexedGetterName == null && indexedSetterName == null &&
+                (getterName != null || setterName != null)) {
+            throw new IntrospectionException(Messages.getString("beans.50"));
+        }
+        setIndexedReadMethod(beanClass, indexedGetterName);
+        setIndexedWriteMethod(beanClass, indexedSetterName);
+    }
+
+    public IndexedPropertyDescriptor(String propertyName, Method getter, Method setter,
+            Method indexedGetter, Method indexedSetter) throws IntrospectionException {
+        super(propertyName, getter, setter);
+        
+        // we need this in order to be compatible with RI
+        if (indexedGetter == null && indexedSetter == null &&
+                (getter != null || setter != null)) {
+            throw new IntrospectionException(Messages.getString("beans.50"));
+        }
+        setIndexedReadMethod(indexedGetter);
+        setIndexedWriteMethod(indexedSetter);
+    }
+
+    public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass)
+            throws IntrospectionException {
+        super(propertyName, beanClass, null, null);
+        String getterName;
+        String setterName;
+        String indexedGetterName;
+        String indexedSetterName;
+
+        // array getter
+        getterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$
+        if (hasMethod(beanClass, getterName)) {
+            setReadMethod(beanClass, getterName);
+        }
+        // array setter
+        setterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$
+        if (hasMethod(beanClass, setterName)) {
+            setWriteMethod(beanClass, setterName);
+        }
+        // indexed getter
+        indexedGetterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$
+        if (hasMethod(beanClass, indexedGetterName)) {
+            setIndexedReadMethod(beanClass, indexedGetterName);
+        }
+        // indexed setter
+        indexedSetterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$
+        if (hasMethod(beanClass, indexedSetterName)) {
+            setIndexedWriteMethod(beanClass, indexedSetterName);
+        }
+        // RI seems to behave a bit differently
+        if (indexedGetter == null && indexedSetter == null &&
+                getReadMethod() == null && getWriteMethod() == null) {
+            throw new IntrospectionException(
+                    Messages.getString("beans.01", propertyName)); //$NON-NLS-1$
+        }
+        if (indexedGetter == null && indexedSetter == null) {
+            // not an indexed property indeed
+            throw new IntrospectionException(Messages.getString("beans.50"));
+        }
+    }
+
+    public void setIndexedReadMethod(Method indexedGetter) throws IntrospectionException {
+        if (indexedGetter != null) {
+            int modifiers = indexedGetter.getModifiers();
+            Class<?>[] parameterTypes;
+            Class<?> returnType;
+            Class<?> indexedPropertyType;
+
+            if (!Modifier.isPublic(modifiers)) {
+                throw new IntrospectionException(Messages.getString("beans.21")); //$NON-NLS-1$
+            }
+            parameterTypes = indexedGetter.getParameterTypes();
+            if (parameterTypes.length != 1) {
+                throw new IntrospectionException(Messages.getString("beans.22")); //$NON-NLS-1$
+            }
+            if (!parameterTypes[0].equals(int.class)) {
+                throw new IntrospectionException(Messages.getString("beans.23")); //$NON-NLS-1$
+            }
+            returnType = indexedGetter.getReturnType();
+            indexedPropertyType = getIndexedPropertyType();
+            if ((indexedPropertyType != null) && !returnType.equals(indexedPropertyType)) {
+                throw new IntrospectionException(Messages.getString("beans.24")); //$NON-NLS-1$
+            }
+        }
+        this.indexedGetter = indexedGetter;
+    }
+
+    public void setIndexedWriteMethod(Method indexedSetter) throws IntrospectionException {
+        if (indexedSetter != null) {
+            int modifiers = indexedSetter.getModifiers();
+            Class<?>[] parameterTypes;
+            Class<?> firstParameterType;
+            Class<?> secondParameterType;
+            Class<?> propType;
+
+            if (!Modifier.isPublic(modifiers)) {
+                throw new IntrospectionException(Messages.getString("beans.25")); //$NON-NLS-1$
+            }
+            parameterTypes = indexedSetter.getParameterTypes();
+            if (parameterTypes.length != 2) {
+                throw new IntrospectionException(Messages.getString("beans.26")); //$NON-NLS-1$
+            }
+            firstParameterType = parameterTypes[0];
+            if (!firstParameterType.equals(int.class)) {
+                throw new IntrospectionException(Messages.getString("beans.27")); //$NON-NLS-1$
+            }
+            secondParameterType = parameterTypes[1];
+            propType = getIndexedPropertyType();
+            if (propType != null && !secondParameterType.equals(propType)) {
+                throw new IntrospectionException(Messages.getString("beans.28")); //$NON-NLS-1$
+            }
+        }
+        this.indexedSetter = indexedSetter;
+    }
+
+    public Method getIndexedWriteMethod() {
+        return indexedSetter;
+    }
+
+    public Method getIndexedReadMethod() {
+        return indexedGetter;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        boolean result = super.equals(obj);
+        
+        if (result) {
+            IndexedPropertyDescriptor pd = (IndexedPropertyDescriptor) obj;
+    
+            if (indexedGetter != null) {
+                result = indexedGetter.equals(pd.getIndexedReadMethod());
+            } else if (result && indexedGetter == null) {
+                result = pd.getIndexedReadMethod() == null;
+            }
+                
+            if (result) {
+                if (indexedSetter != null) {
+                    result = indexedSetter.equals(pd.getIndexedWriteMethod());
+                } else if (indexedSetter == null) {
+                    result = pd.getIndexedWriteMethod() == null;
+                }
+            }
+        }
+            
+        return result;
+    }
+
+    public Class<?> getIndexedPropertyType() {
+        Class<?> result = null;
+
+        if (indexedGetter != null) {
+            result = indexedGetter.getReturnType();
+        } else if (indexedSetter != null) {
+            Class<?>[] parameterTypes = indexedSetter.getParameterTypes();
+
+            result = parameterTypes[1];
+        }
+        return result;
+    }
+
+    private void setIndexedReadMethod(Class<?> beanClass, String indexedGetterName) {
+        Method[] getters = findMethods(beanClass, indexedGetterName);
+        boolean result = false;
+
+        for (Method element : getters) {
+            try {
+                setIndexedReadMethod(element);
+                result = true;
+            } catch (IntrospectionException ie) {}
+
+            if (result) {
+                break;
+            }
+        }
+    }
+
+    private void setIndexedWriteMethod(Class<?> beanClass, String indexedSetterName) {
+        Method[] setters = findMethods(beanClass, indexedSetterName);
+        boolean result = false;
+
+        for (Method element : setters) {
+            try {
+                setIndexedWriteMethod(element);
+                result = true;
+            } catch (IntrospectionException ie) {}
+
+            if (result) {
+                break;
+            }
+        }
+    }
+}
diff --git a/awt/java/beans/IntrospectionException.java b/awt/java/beans/IntrospectionException.java
new file mode 100644
index 0000000..c895afe
--- /dev/null
+++ b/awt/java/beans/IntrospectionException.java
@@ -0,0 +1,27 @@
+/*
+ *  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.
+ */
+
+package java.beans;
+
+public class IntrospectionException extends Exception {
+
+    static final long serialVersionUID = -3728150539969542619L;
+
+    public IntrospectionException(String message) {
+        super(message);
+    }
+}
diff --git a/awt/java/beans/PropertyDescriptor.java b/awt/java/beans/PropertyDescriptor.java
new file mode 100644
index 0000000..9389152
--- /dev/null
+++ b/awt/java/beans/PropertyDescriptor.java
@@ -0,0 +1,300 @@
+/*
+ *  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.
+ */
+
+package java.beans;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Vector;
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class PropertyDescriptor extends FeatureDescriptor {
+    private Method getter;
+
+    private Method setter;
+
+    private Class<?> propertyEditorClass;
+
+    private boolean constrained;
+
+    private boolean bound;
+
+    public PropertyDescriptor(String propertyName, Class<?> beanClass, String getterName,
+            String setterName) throws IntrospectionException {
+        super();
+        if (beanClass == null) {
+            throw new IntrospectionException(Messages.getString("beans.03")); //$NON-NLS-1$
+        }
+        if (propertyName == null || propertyName.length() == 0) {
+            throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$
+        }
+        this.setName(propertyName);
+        this.setDisplayName(propertyName);
+        if (setterName != null) {
+            if (hasMethod(beanClass, setterName)) {
+                setWriteMethod(beanClass, setterName);
+            } else {
+                throw new IntrospectionException(Messages.getString("beans.20")); //$NON-NLS-1$
+            }
+        }
+        if (getterName != null) {
+            if (hasMethod(beanClass, getterName)) {
+                setReadMethod(beanClass, getterName);
+            } else {
+                throw new IntrospectionException(Messages.getString("beans.1F")); //$NON-NLS-1$
+            }
+        }
+    }
+
+    public PropertyDescriptor(String propertyName, Method getter, Method setter)
+            throws IntrospectionException {
+        super();
+        if (propertyName == null || propertyName.length() == 0) {
+            throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$
+        }
+        this.setName(propertyName);
+        this.setDisplayName(propertyName);
+        setWriteMethod(setter);
+        setReadMethod(getter);
+    }
+
+    public PropertyDescriptor(String propertyName, Class<?> beanClass)
+            throws IntrospectionException {
+        String getterName;
+        String setterName;
+        if (beanClass == null) {
+            throw new IntrospectionException(Messages.getString("beans.03")); //$NON-NLS-1$
+        }
+        if (propertyName == null || propertyName.length() == 0) {
+            throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$
+        }
+        this.setName(propertyName);
+        this.setDisplayName(propertyName);
+        getterName = createDefaultMethodName(propertyName, "is"); //$NON-NLS-1$
+        if (hasMethod(beanClass, getterName)) {
+            setReadMethod(beanClass, getterName);
+        } else {
+            getterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$
+            if (hasMethod(beanClass, getterName)) {
+                setReadMethod(beanClass, getterName);
+            }
+        }
+        setterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$
+        if (hasMethod(beanClass, setterName)) {
+            setWriteMethod(beanClass, setterName);
+        }
+        if (getter == null && setter == null) {
+            throw new IntrospectionException(Messages.getString("beans.01", propertyName)); //$NON-NLS-1$
+        }
+    }
+
+    public void setWriteMethod(Method setter) throws IntrospectionException {
+        if (setter != null) {
+            int modifiers = setter.getModifiers();
+            if (!Modifier.isPublic(modifiers)) {
+                throw new IntrospectionException(Messages.getString("beans.05")); //$NON-NLS-1$
+            }
+            Class<?>[] parameterTypes = setter.getParameterTypes();
+            if (parameterTypes.length != 1) {
+                throw new IntrospectionException(Messages.getString("beans.06")); //$NON-NLS-1$
+            }
+            Class<?> parameterType = parameterTypes[0];
+            Class<?> propertyType = getPropertyType();
+            if (propertyType != null && !propertyType.equals(parameterType)) {
+                throw new IntrospectionException(Messages.getString("beans.07")); //$NON-NLS-1$
+            }
+        }
+        this.setter = setter;
+    }
+
+    public void setReadMethod(Method getter) throws IntrospectionException {
+        if (getter != null) {
+            int modifiers = getter.getModifiers();
+            if (!Modifier.isPublic(modifiers)) {
+                throw new IntrospectionException(Messages.getString("beans.0A")); //$NON-NLS-1$
+            }
+            Class<?>[] parameterTypes = getter.getParameterTypes();
+            if (parameterTypes.length != 0) {
+                throw new IntrospectionException(Messages.getString("beans.08")); //$NON-NLS-1$
+            }
+            Class<?> returnType = getter.getReturnType();
+            if (returnType.equals(Void.TYPE)) {
+                throw new IntrospectionException(Messages.getString("beans.33")); //$NON-NLS-1$
+            }
+            Class<?> propertyType = getPropertyType();
+            if ((propertyType != null) && !returnType.equals(propertyType)) {
+                throw new IntrospectionException(Messages.getString("beans.09")); //$NON-NLS-1$
+            }
+        }
+        this.getter = getter;
+    }
+
+    public Method getWriteMethod() {
+        return setter;
+    }
+
+    public Method getReadMethod() {
+        return getter;
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        boolean result = (object != null && object instanceof PropertyDescriptor);
+        if (result) {
+            PropertyDescriptor pd = (PropertyDescriptor) object;
+            boolean gettersAreEqual = (this.getter == null) && (pd.getReadMethod() == null)
+                    || (this.getter != null) && (this.getter.equals(pd.getReadMethod()));
+            boolean settersAreEqual = (this.setter == null) && (pd.getWriteMethod() == null)
+                    || (this.setter != null) && (this.setter.equals(pd.getWriteMethod()));
+            boolean propertyTypesAreEqual = this.getPropertyType() == pd.getPropertyType();
+            boolean propertyEditorClassesAreEqual = this.getPropertyEditorClass() == pd
+                    .getPropertyEditorClass();
+            boolean boundPropertyAreEqual = this.isBound() == pd.isBound();
+            boolean constrainedPropertyAreEqual = this.isConstrained() == pd.isConstrained();
+            result = gettersAreEqual && settersAreEqual && propertyTypesAreEqual
+                    && propertyEditorClassesAreEqual && boundPropertyAreEqual
+                    && constrainedPropertyAreEqual;
+        }
+        return result;
+    }
+
+    public void setPropertyEditorClass(Class<?> propertyEditorClass) {
+        this.propertyEditorClass = propertyEditorClass;
+    }
+
+    public Class<?> getPropertyType() {
+        Class<?> result = null;
+        if (getter != null) {
+            result = getter.getReturnType();
+        } else if (setter != null) {
+            Class<?>[] parameterTypes = setter.getParameterTypes();
+            result = parameterTypes[0];
+        }
+        return result;
+    }
+
+    public Class<?> getPropertyEditorClass() {
+        return propertyEditorClass;
+    }
+
+    public void setConstrained(boolean constrained) {
+        this.constrained = constrained;
+    }
+
+    public void setBound(boolean bound) {
+        this.bound = bound;
+    }
+
+    public boolean isConstrained() {
+        return constrained;
+    }
+
+    public boolean isBound() {
+        return bound;
+    }
+
+    boolean hasMethod(Class<?> beanClass, String methodName) {
+        Method[] methods = findMethods(beanClass, methodName);
+        return (methods.length > 0);
+    }
+
+    String createDefaultMethodName(String propertyName, String prefix) {
+        String result = null;
+        if (propertyName != null) {
+            String bos = propertyName.substring(0, 1).toUpperCase();
+            String eos = propertyName.substring(1, propertyName.length());
+            result = prefix + bos + eos;
+        }
+        return result;
+    }
+
+    Method[] findMethods(Class<?> aClass, String methodName) {
+        Method[] allMethods = aClass.getMethods();
+        Vector<Method> matchedMethods = new Vector<Method>();
+        Method[] result;
+        for (Method method : allMethods) {
+            if (method.getName().equals(methodName)) {
+                matchedMethods.add(method);
+            }
+        }
+        result = new Method[matchedMethods.size()];
+        for (int j = 0; j < matchedMethods.size(); ++j) {
+            result[j] = matchedMethods.elementAt(j);
+        }
+        return result;
+    }
+
+    void setReadMethod(Class<?> beanClass, String getterName) {
+        boolean result = false;
+        Method[] getters = findMethods(beanClass, getterName);
+        for (Method element : getters) {
+            try {
+                setReadMethod(element);
+                result = true;
+            } catch (IntrospectionException ie) {
+            }
+            if (result) {
+                break;
+            }
+        }
+    }
+
+    void setWriteMethod(Class<?> beanClass, String setterName) throws IntrospectionException {
+        boolean result = false;
+        Method[] setters = findMethods(beanClass, setterName);
+        for (Method element : setters) {
+            try {
+                setWriteMethod(element);
+                result = true;
+            } catch (IntrospectionException ie) {
+            }
+            if (result) {
+                break;
+            }
+        }
+    }
+
+    public PropertyEditor createPropertyEditor(Object bean) {
+        PropertyEditor editor;
+        if (propertyEditorClass == null) {
+            return null;
+        }
+        if (!PropertyEditor.class.isAssignableFrom(propertyEditorClass)) {
+            // beans.48=Property editor is not assignable from the
+            // PropertyEditor interface
+            throw new ClassCastException(Messages.getString("beans.48")); //$NON-NLS-1$
+        }
+        try {
+            Constructor<?> constr;
+            try {
+                // try to look for the constructor with single Object argument
+                constr = propertyEditorClass.getConstructor(Object.class);
+                editor = (PropertyEditor) constr.newInstance(bean);
+            } catch (NoSuchMethodException e) {
+                // try no-argument constructor
+                constr = propertyEditorClass.getConstructor();
+                editor = (PropertyEditor) constr.newInstance();
+            }
+        } catch (Exception e) {
+            // beans.47=Unable to instantiate property editor
+            RuntimeException re = new RuntimeException(Messages.getString("beans.47"), e); //$NON-NLS-1$
+            throw re;
+        }
+        return editor;
+    }
+}
diff --git a/awt/java/beans/PropertyEditor.java b/awt/java/beans/PropertyEditor.java
new file mode 100644
index 0000000..65bedea
--- /dev/null
+++ b/awt/java/beans/PropertyEditor.java
@@ -0,0 +1,49 @@
+/*
+ *  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.
+ */
+
+package java.beans;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+
+public interface PropertyEditor {
+
+    public void paintValue(Graphics gfx, Rectangle box);
+
+    public void setAsText(String text) throws IllegalArgumentException;
+
+    public String[] getTags();
+
+    public String getJavaInitializationString();
+
+    public String getAsText();
+
+    public void setValue(Object value);
+
+    public Object getValue();
+
+    public void removePropertyChangeListener(PropertyChangeListener listener);
+
+    public void addPropertyChangeListener(PropertyChangeListener listener);
+
+    public Component getCustomEditor();
+
+    public boolean supportsCustomEditor();
+
+    public boolean isPaintable();
+}
diff --git a/awt/java/beans/PropertyEditorManager.java b/awt/java/beans/PropertyEditorManager.java
new file mode 100644
index 0000000..ed55829
--- /dev/null
+++ b/awt/java/beans/PropertyEditorManager.java
@@ -0,0 +1,114 @@
+/*
+ *  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.
+ */
+
+package java.beans;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class PropertyEditorManager {
+
+    private static String[] path = { "org.apache.harmony.beans.editors" }; //$NON-NLS-1$
+
+    private static final Map<Class<?>, Class<?>> registeredEditors = new HashMap<Class<?>, Class<?>>();
+
+    public PropertyEditorManager() {
+    }
+
+    public static void registerEditor(Class<?> targetType, Class<?> editorClass) {
+        if (targetType == null) {
+            throw new NullPointerException();
+        }
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPropertiesAccess();
+        }
+        if (editorClass != null) {
+            registeredEditors.put(targetType, editorClass);
+        } else {
+            registeredEditors.remove(targetType);
+        }
+    }
+
+    public static synchronized PropertyEditor findEditor(Class<?> targetType) {
+        if (targetType == null) {
+            throw new NullPointerException();
+        }
+
+        Class<?> editorClass = null;
+        PropertyEditor editor = null;
+
+        editorClass = registeredEditors.get(targetType);
+
+        if (editorClass == null) {
+            String editorClassName = targetType.getName() + "Editor"; //$NON-NLS-1$
+            ClassLoader loader = targetType.getClassLoader();
+
+            if (loader == null) {
+                loader = Thread.currentThread().getContextClassLoader();
+            }
+
+            try {
+                editorClass = Class.forName(editorClassName, true, loader);
+            } catch (ClassNotFoundException cnfe) {
+                String shortEditorClassName = editorClassName
+                        .substring(editorClassName.lastIndexOf(".") + 1); //$NON-NLS-1$
+
+                if (targetType.isPrimitive()) {
+                    shortEditorClassName = shortEditorClassName.substring(0, 1)
+                            .toUpperCase()
+                            + shortEditorClassName.substring(1);
+                }
+
+                for (String element : path) {
+                    editorClassName = element + "." + shortEditorClassName; //$NON-NLS-1$
+
+                    try {
+                        editorClass = Class.forName(editorClassName, true,
+                                loader);
+                        break;
+                    } catch (Exception e) {
+                    }
+                }
+            } catch (Exception e) {
+            }
+        }
+
+        if (editorClass != null) {
+            try {
+                editor = (PropertyEditor) editorClass.newInstance();
+            } catch (Exception e) {
+            }
+        }
+
+        return editor;
+    }
+
+    public static synchronized void setEditorSearchPath(String[] apath) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPropertiesAccess();
+        }
+
+        path = apath;
+    }
+
+    public static synchronized String[] getEditorSearchPath() {
+        return path;
+    }
+}
diff --git a/awt/java/beans/PropertyEditorSupport.java b/awt/java/beans/PropertyEditorSupport.java
new file mode 100644
index 0000000..c3929a1
--- /dev/null
+++ b/awt/java/beans/PropertyEditorSupport.java
@@ -0,0 +1,129 @@
+/*
+ *  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.
+ */
+package java.beans;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class PropertyEditorSupport implements PropertyEditor {
+
+    Object source = null;
+
+    List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();
+
+    Object oldValue = null;
+
+    Object newValue = null;
+
+    public PropertyEditorSupport(Object source) {
+        if (source == null) {
+            throw new NullPointerException(Messages.getString("beans.0C")); //$NON-NLS-1$
+        }
+        this.source = source;
+    }
+
+    public PropertyEditorSupport() {
+        source = this;
+    }
+
+    public void paintValue(Graphics gfx, Rectangle box) {
+    }
+
+    public void setAsText(String text) throws IllegalArgumentException {
+        if (newValue instanceof String) {
+            setValue(text);
+        } else {
+            throw new IllegalArgumentException(text);
+        }
+    }
+
+    public String[] getTags() {
+        return null;
+    }
+
+    public String getJavaInitializationString() {
+        return "???"; //$NON-NLS-1$
+    }
+
+    public String getAsText() {
+        return newValue == null ? "null" : newValue.toString(); //$NON-NLS-1$
+    }
+
+    public void setValue(Object value) {
+        this.oldValue = this.newValue;
+        this.newValue = value;
+        firePropertyChange();
+    }
+
+    public Object getValue() {
+        return newValue;
+    }
+
+    public void setSource(Object source) {
+        if (source == null) {
+            throw new NullPointerException(Messages.getString("beans.0C")); //$NON-NLS-1$
+        }
+        this.source = source;
+    }
+
+    public Object getSource() {
+        return source;
+    }
+
+    public synchronized void removePropertyChangeListener(
+            PropertyChangeListener listener) {
+        if (listeners != null) {
+            listeners.remove(listener);
+        }
+    }
+
+    public synchronized void addPropertyChangeListener(
+            PropertyChangeListener listener) {
+        listeners.add(listener);
+    }
+
+    public Component getCustomEditor() {
+        return null;
+    }
+
+    public boolean supportsCustomEditor() {
+        return false;
+    }
+
+    public boolean isPaintable() {
+        return false;
+    }
+
+    public void firePropertyChange() {
+        if (listeners.size() > 0) {
+            PropertyChangeEvent event = new PropertyChangeEvent(source, null,
+                    oldValue, newValue);
+            Iterator<PropertyChangeListener> iterator = listeners.iterator();
+
+            while (iterator.hasNext()) {
+                PropertyChangeListener listener = iterator.next();
+                listener.propertyChange(event);
+            }
+        }
+    }
+}
diff --git a/awt/java/beans/PropertyVetoException.java b/awt/java/beans/PropertyVetoException.java
new file mode 100644
index 0000000..c7f092a
--- /dev/null
+++ b/awt/java/beans/PropertyVetoException.java
@@ -0,0 +1,54 @@
+/*
+ *  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.
+ */
+
+package java.beans;
+
+/**
+ * Indicates that a proposed property change is unacceptable.
+ */
+public class PropertyVetoException extends Exception {
+
+    private static final long serialVersionUID = 129596057694162164L;
+
+    private final PropertyChangeEvent evt;
+
+    /**
+     * <p>
+     * Constructs an instance with a message and the change event.
+     * </p>
+     * 
+     * @param message
+     *            A description of the veto.
+     * @param event
+     *            The event that was vetoed.
+     */
+    public PropertyVetoException(String message, PropertyChangeEvent event) {
+        super(message);
+        this.evt = event;
+    }
+
+    /**
+     * <p>
+     * Gets the property change event.
+     * </p>
+     * 
+     * @return An instance of {@link PropertyChangeEvent}
+     */
+    public PropertyChangeEvent getPropertyChangeEvent() {
+        return evt;
+    }
+}
diff --git a/awt/javax/imageio/IIOException.java b/awt/javax/imageio/IIOException.java
new file mode 100644
index 0000000..c77716c
--- /dev/null
+++ b/awt/javax/imageio/IIOException.java
@@ -0,0 +1,60 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio;
+
+import java.io.IOException;
+
+/**
+ * The IIOException class indicates errors in reading/writing operations.
+ * 
+ * @since Android 1.0
+ */
+public class IIOException extends IOException {
+
+    /**
+     * The Constant serialVersionUID.
+     */
+    private static final long serialVersionUID = -3216210718638985251L;
+
+    /**
+     * Instantiates a new IIOException.
+     * 
+     * @param message
+     *            the detailed message.
+     */
+    public IIOException(String message) {
+        super(message);
+    }
+
+    /**
+     * Instantiates a new IIOException.
+     * 
+     * @param message
+     *            the detailed message.
+     * @param cause
+     *            the cause of this exception.
+     */
+    public IIOException(String message, Throwable cause) {
+        super(message);
+        initCause(cause);
+    }
+}
diff --git a/awt/javax/imageio/IIOImage.java b/awt/javax/imageio/IIOImage.java
new file mode 100644
index 0000000..e9e5130
--- /dev/null
+++ b/awt/javax/imageio/IIOImage.java
@@ -0,0 +1,224 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio;
+
+import javax.imageio.metadata.IIOMetadata;
+import java.awt.image.RenderedImage;
+import java.awt.image.Raster;
+import java.awt.image.BufferedImage;
+import java.util.List;
+
+/**
+ * The IIOImage class combines the image, image's thumbnail and image's
+ * metadata. The image can be presented as RenderedImage or Raster object.
+ * 
+ * @since Android 1.0
+ */
+public class IIOImage {
+
+    /**
+     * The image of this IIOImage.
+     */
+    protected RenderedImage image;
+
+    /**
+     * The raster of this IIOImage.
+     */
+    protected Raster raster;
+
+    /**
+     * The list with thumbnails associated with the image.
+     */
+    protected List<? extends BufferedImage> thumbnails;
+
+    /**
+     * The metadata associated with the image.
+     */
+    protected IIOMetadata metadata;
+
+    /**
+     * Instantiates a new IIOImage with the specified RenderedImage, list of
+     * thumbnails and metadata.
+     * 
+     * @param image
+     *            the image specified by RenderedImage.
+     * @param thumbnails
+     *            the list of BufferedImage objects which represent the
+     *            thumbnails of the image.
+     * @param metadata
+     *            the metadata of the image.
+     */
+    public IIOImage(RenderedImage image, List<? extends BufferedImage> thumbnails,
+            IIOMetadata metadata) {
+        if (image == null) {
+            throw new IllegalArgumentException("image should not be NULL");
+        }
+        this.raster = null;
+        this.image = image;
+        this.thumbnails = thumbnails;
+        this.metadata = metadata;
+    }
+
+    /**
+     * Instantiates a new IIOImage with the specified Raster, list of thumbnails
+     * and metadata.
+     * 
+     * @param raster
+     *            the Raster.
+     * @param thumbnails
+     *            the list of BufferedImage objects which represent the
+     *            thumbnails of Raster data.
+     * @param metadata
+     *            the metadata.
+     */
+    public IIOImage(Raster raster, List<? extends BufferedImage> thumbnails, IIOMetadata metadata) {
+        if (raster == null) {
+            throw new IllegalArgumentException("raster should not be NULL");
+        }
+        this.image = null;
+        this.raster = raster;
+        this.thumbnails = thumbnails;
+        this.metadata = metadata;
+    }
+
+    /**
+     * Gets the RenderedImage object or returns null if this IIOImage object is
+     * associated with a Raster.
+     * 
+     * @return the RenderedImage object or null if this IIOImage object is
+     *         associated with a Raster.
+     */
+    public RenderedImage getRenderedImage() {
+        return image;
+    }
+
+    /**
+     * Sets the RenderedImage to this IIOImage object.
+     * 
+     * @param image
+     *            the RenderedImage to be set to this IIOImage.
+     */
+    public void setRenderedImage(RenderedImage image) {
+        if (image == null) {
+            throw new IllegalArgumentException("image should not be NULL");
+        }
+        raster = null;
+        this.image = image;
+    }
+
+    /**
+     * Returns true if the IIOImage object associated with a Raster, or false if
+     * it's associated with a RenderedImage.
+     * 
+     * @return true, if the IIOImage object associated with a Raster, or false
+     *         if it's associated with a RenderedImage.
+     */
+    public boolean hasRaster() {
+        return raster != null;
+    }
+
+    /**
+     * Gets the Raster object or returns null if this IIOImage object is
+     * associated with a RenderedImage.
+     * 
+     * @return the Raster or null if this IIOImage object is associated with a
+     *         RenderedImage.
+     */
+    public Raster getRaster() {
+        return raster;
+    }
+
+    /**
+     * Sets the Raster to the IIOImage.
+     * 
+     * @param raster
+     *            the new Raster to the IIOImage.
+     */
+    public void setRaster(Raster raster) {
+        if (raster == null) {
+            throw new IllegalArgumentException("raster should not be NULL");
+        }
+        image = null;
+        this.raster = raster;
+    }
+
+    /**
+     * Gets the number of thumbnails for this IIOImage.
+     * 
+     * @return the number of thumbnails for this IIOImage.
+     */
+    public int getNumThumbnails() {
+        return thumbnails != null ? thumbnails.size() : 0;
+    }
+
+    /**
+     * Gets the thumbnail with the specified index in the list.
+     * 
+     * @param index
+     *            the index of the thumbnail in the list.
+     * @return the thumbnail with the specified index in the list.
+     */
+    public BufferedImage getThumbnail(int index) {
+        if (thumbnails != null) {
+            return thumbnails.get(index);
+        }
+        throw new IndexOutOfBoundsException("no thumbnails were set");
+    }
+
+    /**
+     * Gets the list of thumbnails.
+     * 
+     * @return the list of thumbnails.
+     */
+    public List<? extends BufferedImage> getThumbnails() {
+        return thumbnails;
+    }
+
+    /**
+     * Sets the list of thumbnails images to this IIOImage object.
+     * 
+     * @param thumbnails
+     *            the list of BufferedImage which represent thumbnails.
+     */
+    public void setThumbnails(List<? extends BufferedImage> thumbnails) {
+        this.thumbnails = thumbnails;
+    }
+
+    /**
+     * Gets the metadata of this IIOImage.
+     * 
+     * @return the metadata of this IIOImage.
+     */
+    public IIOMetadata getMetadata() {
+        return metadata;
+    }
+
+    /**
+     * Sets the metadata to this IIOImage object.
+     * 
+     * @param metadata
+     *            the IIOMetadata, or null.
+     */
+    public void setMetadata(IIOMetadata metadata) {
+        this.metadata = metadata;
+    }
+}
diff --git a/awt/javax/imageio/IIOParam.java b/awt/javax/imageio/IIOParam.java
new file mode 100644
index 0000000..2ccc945
--- /dev/null
+++ b/awt/javax/imageio/IIOParam.java
@@ -0,0 +1,342 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio;
+
+import java.awt.*;
+
+/**
+ * The IIOParam abstract class is superclass for ImageReadParam and
+ * ImageWriteParam classes and provides methods and variables which they share.
+ * 
+ * @since Android 1.0
+ */
+public abstract class IIOParam {
+
+    /**
+     * The source region.
+     */
+    protected Rectangle sourceRegion;
+
+    /**
+     * The source x subsampling.
+     */
+    protected int sourceXSubsampling = 1;
+
+    /**
+     * The source y subsampling.
+     */
+    protected int sourceYSubsampling = 1;
+
+    /**
+     * The subsampling x offset.
+     */
+    protected int subsamplingXOffset;
+
+    /**
+     * The subsampling y offset.
+     */
+    protected int subsamplingYOffset;
+
+    /**
+     * The source bands.
+     */
+    protected int[] sourceBands;
+
+    /**
+     * The destination type.
+     */
+    protected ImageTypeSpecifier destinationType;
+
+    /**
+     * The destination offset.
+     */
+    protected Point destinationOffset = new Point(0, 0);
+
+    /**
+     * The default controller.
+     */
+    protected IIOParamController defaultController;
+
+    /**
+     * The controller.
+     */
+    protected IIOParamController controller;
+
+    /**
+     * Instantiates a new IIOParam.
+     */
+    protected IIOParam() {
+    }
+
+    /**
+     * Sets the source region as a Rectangle object.
+     * 
+     * @param sourceRegion
+     *            the Rectangle which specifies the source region.
+     */
+    public void setSourceRegion(Rectangle sourceRegion) {
+        if (sourceRegion != null) {
+            if (sourceRegion.x < 0) {
+                throw new IllegalArgumentException("x < 0");
+            }
+            if (sourceRegion.y < 0) {
+                throw new IllegalArgumentException("y < 0");
+            }
+            if (sourceRegion.width <= 0) {
+                throw new IllegalArgumentException("width <= 0");
+            }
+            if (sourceRegion.height <= 0) {
+                throw new IllegalArgumentException("height <= 0");
+            }
+
+            if (sourceRegion.width <= subsamplingXOffset) {
+                throw new IllegalArgumentException("width <= subsamplingXOffset");
+            }
+
+            if (sourceRegion.height <= subsamplingYOffset) {
+                throw new IllegalArgumentException("height <= subsamplingXOffset");
+            }
+            // -- clone it to avoid unexpected modifications
+            this.sourceRegion = (Rectangle)sourceRegion.clone();
+        } else {
+            this.sourceRegion = null;
+        }
+    }
+
+    /**
+     * Gets the source region.
+     * 
+     * @return the source region as Rectangle.
+     */
+    public Rectangle getSourceRegion() {
+        if (sourceRegion == null) {
+            return null;
+        }
+        // -- clone it to avoid unexpected modifications
+        return (Rectangle)sourceRegion.clone();
+    }
+
+    /**
+     * Sets the source subsampling. The sourceXSubsampling and
+     * sourceYSubsampling parameters specify the number of rows and columns to
+     * advance after every source pixel.
+     * 
+     * @param sourceXSubsampling
+     *            the source X subsampling.
+     * @param sourceYSubsampling
+     *            the source Y subsampling.
+     * @param subsamplingXOffset
+     *            the subsampling X offset.
+     * @param subsamplingYOffset
+     *            the subsampling Y offset.
+     */
+    public void setSourceSubsampling(int sourceXSubsampling, int sourceYSubsampling,
+            int subsamplingXOffset, int subsamplingYOffset) {
+
+        if (sourceXSubsampling <= 0) {
+            throw new IllegalArgumentException("sourceXSubsampling <= 0");
+        }
+        if (sourceYSubsampling <= 0) {
+            throw new IllegalArgumentException("sourceYSubsampling <= 0");
+        }
+
+        if (subsamplingXOffset <= 0 || subsamplingXOffset >= sourceXSubsampling) {
+            throw new IllegalArgumentException("subsamplingXOffset is wrong");
+        }
+
+        if (subsamplingYOffset <= 0 || subsamplingYOffset >= sourceYSubsampling) {
+            throw new IllegalArgumentException("subsamplingYOffset is wrong");
+        }
+
+        // -- does region contain pixels
+        if (sourceRegion != null) {
+            if (sourceRegion.width <= subsamplingXOffset
+                    || sourceRegion.height <= subsamplingYOffset) {
+                throw new IllegalArgumentException("there are no pixels in region");
+            }
+        }
+
+        this.sourceXSubsampling = sourceXSubsampling;
+        this.sourceYSubsampling = sourceYSubsampling;
+        this.subsamplingXOffset = subsamplingXOffset;
+        this.subsamplingYOffset = subsamplingYOffset;
+    }
+
+    /**
+     * Gets the source X subsampling - the number of source columns to advance
+     * for each pixel.
+     * 
+     * @return the source X subsampling.
+     */
+    public int getSourceXSubsampling() {
+        return sourceXSubsampling;
+    }
+
+    /**
+     * Gets the source Y subsampling - the number of source rows to advance for
+     * each pixel.
+     * 
+     * @return the source Y subsampling.
+     */
+    public int getSourceYSubsampling() {
+        return sourceYSubsampling;
+    }
+
+    /**
+     * Gets the horizontal offset of the subsampling grid.
+     * 
+     * @return the horizontal offset of the subsampling grid.
+     */
+    public int getSubsamplingXOffset() {
+        return subsamplingXOffset;
+    }
+
+    /**
+     * Gets the vertical offset of the subsampling grid.
+     * 
+     * @return the vertical offset of the subsampling grid.
+     */
+    public int getSubsamplingYOffset() {
+        return subsamplingYOffset;
+    }
+
+    /**
+     * Sets the indices of the source bands.
+     * 
+     * @param sourceBands
+     *            the indices of the source bands.
+     */
+    public void setSourceBands(int[] sourceBands) {
+        // TODO implement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    /**
+     * Gets the array of source bands.
+     * 
+     * @return the array of source bands.
+     */
+    public int[] getSourceBands() {
+        // TODO implement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    /**
+     * Sets the specified ImageTypeSpecifier for the destination image.
+     * 
+     * @param destinationType
+     *            the ImageTypeSpecifier.
+     */
+    public void setDestinationType(ImageTypeSpecifier destinationType) {
+        // TODO implement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    /**
+     * Gets the type of the destination image as an ImageTypeSpecifier. .
+     * 
+     * @return the ImageTypeSpecifier.
+     */
+    public ImageTypeSpecifier getDestinationType() {
+        // TODO implement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    /**
+     * Sets the offset in the destination image where the decoded pixels are
+     * placed as a result of reading, or specified an area to be written while
+     * writing operation.
+     * 
+     * @param destinationOffset
+     *            the destination offset.
+     */
+    public void setDestinationOffset(Point destinationOffset) {
+        if (destinationOffset == null) {
+            throw new IllegalArgumentException("destinationOffset == null!");
+        }
+
+        this.destinationOffset = (Point)destinationOffset.clone();
+    }
+
+    /**
+     * Gets the offset in the destination image for placing pixels.
+     * 
+     * @return the offset in the destination image.
+     */
+    public Point getDestinationOffset() {
+        return (Point)destinationOffset.clone();
+    }
+
+    /**
+     * Sets the IIOParamController to this IIOParam object for providing
+     * settings to this IIOParam.
+     * 
+     * @param controller
+     *            the new IIOParamController.
+     */
+    public void setController(IIOParamController controller) {
+        // TODO implement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    /**
+     * Gets the current IIOParamController controller for this IIOParam.
+     * 
+     * @return the current IIOParamController controller for this IIOParam.
+     */
+    public IIOParamController getController() {
+        // TODO implement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    /**
+     * Gets the default IIOParamController controller for this IIOParam.
+     * 
+     * @return the default IIOParamController controller for this IIOParam, or
+     *         null.
+     */
+    public IIOParamController getDefaultController() {
+        // TODO implement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    /**
+     * Returns true if IIOParamController is installed for this IIOParam.
+     * 
+     * @return true, if IIOParamController is installed for this IIOParam, false
+     *         otherwise.
+     */
+    public boolean hasController() {
+        // TODO implement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    /**
+     * Activates the controller.
+     * 
+     * @return true, if successful, false otherwise.
+     */
+    public boolean activateController() {
+        // TODO implement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+}
diff --git a/awt/javax/imageio/IIOParamController.java b/awt/javax/imageio/IIOParamController.java
new file mode 100644
index 0000000..338cb25
--- /dev/null
+++ b/awt/javax/imageio/IIOParamController.java
@@ -0,0 +1,45 @@
+/*
+ *  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.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+package javax.imageio;
+
+/* 
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The IIOParamController specifies an activate method that invokes the
+ * controller.
+ * 
+ * @since Android 1.0
+ */
+public interface IIOParamController {
+
+    /**
+     * Activates the controller.
+     * 
+     * @param param
+     *            the IIOParam.
+     * @return true, if the IIOParam has been modified, false otherwise.
+     */
+    boolean activate(IIOParam param);
+}
diff --git a/awt/javax/imageio/ImageIO.java b/awt/javax/imageio/ImageIO.java
new file mode 100644
index 0000000..e0d7ec9
--- /dev/null
+++ b/awt/javax/imageio/ImageIO.java
@@ -0,0 +1,800 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio;
+
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.spi.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.Arrays;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+import java.net.URL;
+
+/**
+ * The ImageIO class provides static methods to perform reading and writing
+ * operations using registered ImageReader and ImageWriter objects.
+ * 
+ * @since Android 1.0
+ */
+public final class ImageIO {
+
+    /**
+     * The constant registry.
+     */
+    private static final IIORegistry registry = IIORegistry.getDefaultInstance();
+
+    /**
+     * Instantiates a new ImageIO.
+     */
+    private ImageIO() {
+    }
+
+    /**
+     * Scans for plug-ins in the class path, loads spi classes, and registers
+     * them with the IIORegistry.
+     */
+    public static void scanForPlugins() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Sets flag which indicates whether a cache file is used when creating
+     * ImageInputStreams and ImageOutputStreams or not.
+     * 
+     * @param useCache
+     *            the use cache flag.
+     */
+    public static void setUseCache(boolean useCache) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the flag which indicates whether a cache file is used when creating
+     * ImageInputStreams and ImageOutputStreams or not. This method returns the
+     * current value which is set by setUseCache method.
+     * 
+     * @return the use cache flag.
+     */
+    public static boolean getUseCache() {
+        // TODO implement
+        return false;
+    }
+
+    /**
+     * Sets the cache directory.
+     * 
+     * @param cacheDirectory
+     *            the File which specifies a cache directory.
+     */
+    public static void setCacheDirectory(File cacheDirectory) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the directory where cache files are created, returned the file which
+     * is set by setCacheDirectory method, or null.
+     * 
+     * @return the File object which is set by setCacheDirectory method, or
+     *         null.
+     */
+    public static File getCacheDirectory() {
+        // TODO implement
+        // -- null indicates system-dep default temporary directory
+        return null;
+    }
+
+    /**
+     * Creates an ImageInputStream from the specified Object. The specified
+     * Object should obtain the input source such as File, or InputStream.
+     * 
+     * @param input
+     *            the input Object such as File, or InputStream.
+     * @return the ImageInputStream object, or null.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public static ImageInputStream createImageInputStream(Object input) throws IOException {
+
+        if (input == null) {
+            throw new IllegalArgumentException("input source cannot be NULL");
+        }
+
+        Iterator<ImageInputStreamSpi> it = registry.getServiceProviders(ImageInputStreamSpi.class,
+                true);
+
+        while (it.hasNext()) {
+            ImageInputStreamSpi spi = it.next();
+            if (spi.getInputClass().isInstance(input)) {
+                return spi.createInputStreamInstance(input);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Creates an ImageOutputStream using the specified Object. The specified
+     * Object should obtain the output source such as File, or OutputStream.
+     * 
+     * @param output
+     *            the output Object such as File, or OutputStream.
+     * @return the ImageOutputStream object, or null.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public static ImageOutputStream createImageOutputStream(Object output) throws IOException {
+        if (output == null) {
+            throw new IllegalArgumentException("output destination cannot be NULL");
+        }
+
+        Iterator<ImageOutputStreamSpi> it = registry.getServiceProviders(
+                ImageOutputStreamSpi.class, true);
+
+        while (it.hasNext()) {
+            ImageOutputStreamSpi spi = it.next();
+            if (spi.getOutputClass().isInstance(output)) {
+                // todo - use getUseCache and getCacheDir here
+                return spi.createOutputStreamInstance(output);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets the array of format names as String which can be decoded by
+     * registered ImageReader objects.
+     * 
+     * @return the array of format names.
+     */
+    public static String[] getReaderFormatNames() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the array of MIME types as String which can be decoded by registered
+     * ImageReader objects.
+     * 
+     * @return the array of MIME types.
+     */
+    public static String[] getReaderMIMETypes() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the Iterator of registered ImageReader which are able to decode an
+     * input data specified by input Object.
+     * 
+     * @param input
+     *            the input Object with encoded data such as ImageInputStream
+     *            object.
+     * @return the Iterator of registered ImageReader.
+     */
+    public static Iterator<ImageReader> getImageReaders(Object input) {
+        if (input == null) {
+            throw new NullPointerException("input cannot be NULL");
+        }
+
+        Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
+                new CanReadFilter(input), true);
+
+        return new SpiIteratorToReadersIteratorWrapper(it);
+    }
+
+    /**
+     * Gets the Iterator of registered ImageReader which are able to decode the
+     * specified format.
+     * 
+     * @param formatName
+     *            the format name such as "jpeg", or "gif".
+     * @return the Iterator of registered ImageReader.
+     */
+    public static Iterator<ImageReader> getImageReadersByFormatName(String formatName) {
+        if (formatName == null) {
+            throw new NullPointerException("format name cannot be NULL");
+        }
+
+        Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
+                new FormatFilter(formatName), true);
+
+        return new SpiIteratorToReadersIteratorWrapper(it);
+    }
+
+    /**
+     * Gets the Iterator which lists the registered ImageReader objects that are
+     * able to decode files with the specified suffix.
+     * 
+     * @param fileSuffix
+     *            the file suffix such as "jpg".
+     * @return the Iterator of registered ImageReaders.
+     */
+    public static Iterator<ImageReader> getImageReadersBySuffix(String fileSuffix) {
+        if (fileSuffix == null) {
+            throw new NullPointerException("suffix cannot be NULL");
+        }
+        Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
+                new SuffixFilter(fileSuffix), true);
+
+        return new SpiIteratorToReadersIteratorWrapper(it);
+    }
+
+    /**
+     * Gets the Iterator of registered ImageReader objects that are able to
+     * decode files with the specified MIME type.
+     * 
+     * @param MIMEType
+     *            the MIME type such as "image/jpeg".
+     * @return the Iterator of registered ImageReaders.
+     */
+    public static Iterator<ImageReader> getImageReadersByMIMEType(String MIMEType) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets an array of Strings giving the names of the formats supported by
+     * registered ImageWriter objects.
+     * 
+     * @return the array of format names.
+     */
+    public static String[] getWriterFormatNames() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets an array of Strings giving the MIME types of the formats supported
+     * by registered ImageWriter objects.
+     * 
+     * @return the array of MIME types.
+     */
+    public static String[] getWriterMIMETypes() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the Iterator which lists the registered ImageReader objects that are
+     * able to encode the specified image format.
+     * 
+     * @param formatName
+     *            the image format name such as "jpeg".
+     * @return the Iterator of registered ImageWriter.
+     */
+    public static Iterator<ImageWriter> getImageWritersByFormatName(String formatName) {
+        if (formatName == null) {
+            throw new NullPointerException("format name cannot be NULL");
+        }
+
+        Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
+                new FormatFilter(formatName), true);
+
+        return new SpiIteratorToWritersIteratorWrapper(it);
+    }
+
+    /**
+     * Gets the Iterator which lists the registered ImageReader objects that are
+     * able to encode the specified suffix.
+     * 
+     * @param fileSuffix
+     *            the file suffix such as "jpg".
+     * @return the Iterator of registered ImageWriter.
+     */
+    public static Iterator<ImageWriter> getImageWritersBySuffix(String fileSuffix) {
+        if (fileSuffix == null) {
+            throw new NullPointerException("suffix cannot be NULL");
+        }
+        Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
+                new SuffixFilter(fileSuffix), true);
+        return new SpiIteratorToWritersIteratorWrapper(it);
+    }
+
+    /**
+     * Gets the Iterator which lists the registered ImageReader objects that are
+     * able to encode the specified MIME type.
+     * 
+     * @param MIMEType
+     *            the MIME type such as "image/jpeg".
+     * @return the Iterator of registered ImageWriter.
+     */
+    public static Iterator<ImageWriter> getImageWritersByMIMEType(String MIMEType) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets an ImageWriter object which corresponds to the specified
+     * ImageReader, or returns null if the specified ImageReader is not
+     * registered.
+     * 
+     * @param reader
+     *            the specified ImageReader.
+     * @return the ImageWriter, or null.
+     */
+    public static ImageWriter getImageWriter(ImageReader reader) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets an ImageReader object which corresponds to the specified
+     * ImageWriter, or returns null if the specified ImageWriter is not
+     * registered.
+     * 
+     * @param writer
+     *            the registered ImageWriter object.
+     * @return the ImageReader.
+     */
+    public static ImageReader getImageReader(ImageWriter writer) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the Iterator of ImageWriter objects which are able to encode images
+     * with the specified ImageTypeSpecifier and format.
+     * 
+     * @param type
+     *            the ImageTypeSpecifier, which defines layout.
+     * @param formatName
+     *            the format name.
+     * @return the Iterator of ImageWriter objects.
+     */
+    public static Iterator<ImageWriter> getImageWriters(ImageTypeSpecifier type, String formatName) {
+        if (type == null) {
+            throw new NullPointerException("type cannot be NULL");
+        }
+
+        if (formatName == null) {
+            throw new NullPointerException("format name cannot be NULL");
+        }
+
+        Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
+                new FormatAndEncodeFilter(type, formatName), true);
+
+        return new SpiIteratorToWritersIteratorWrapper(it);
+    }
+
+    /**
+     * Gets the Iterator of registered ImageTranscoders which are able to
+     * transcode the metadata of the specified ImageReader object to a suitable
+     * object for encoding by the specified ImageWriter.
+     * 
+     * @param reader
+     *            the specified ImageReader.
+     * @param writer
+     *            the specified ImageWriter.
+     * @return the Iterator of registered ImageTranscoders.
+     */
+    public static Iterator<ImageTranscoder> getImageTranscoders(ImageReader reader,
+            ImageWriter writer) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Reads image data from the specified File and decodes it using the
+     * appropriate registered ImageReader object. The File is wrapped in an
+     * ImageInputStream.
+     * 
+     * @param input
+     *            the File to be read.
+     * @return the BufferedImage decoded from the specified File, or null.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public static BufferedImage read(File input) throws IOException {
+        if (input == null) {
+            throw new IllegalArgumentException("input == null!");
+        }
+
+        ImageInputStream stream = createImageInputStream(input);
+        return read(stream);
+    }
+
+    /**
+     * Reads image data from the specified InputStream and decodes it using an
+     * appropriate registered an ImageReader object.
+     * 
+     * @param input
+     *            the InputStream.
+     * @return the BufferedImage decoded from the specified InputStream, or
+     *         null.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public static BufferedImage read(InputStream input) throws IOException {
+        if (input == null) {
+            throw new IllegalArgumentException("input == null!");
+        }
+
+        ImageInputStream stream = createImageInputStream(input);
+        return read(stream);
+    }
+
+    /**
+     * Reads image data from the specified URL and decodes it using the
+     * appropriate registered ImageReader object.
+     * 
+     * @param input
+     *            the URL to be read.
+     * @return the BufferedImage decoded from the specified URL, or null.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public static BufferedImage read(URL input) throws IOException {
+        if (input == null) {
+            throw new IllegalArgumentException("input == null!");
+        }
+
+        InputStream stream = input.openStream();
+        BufferedImage res = read(stream);
+        stream.close();
+
+        return res;
+    }
+
+    /**
+     * Reads image data from the specified ImageInputStream and decodes it using
+     * appropriate registered an ImageReader object.
+     * 
+     * @param stream
+     *            the ImageInputStream.
+     * @return the BufferedImage decoded from the specified ImageInputStream, or
+     *         null.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public static BufferedImage read(ImageInputStream stream) throws IOException {
+        if (stream == null) {
+            throw new IllegalArgumentException("stream == null!");
+        }
+
+        Iterator<ImageReader> imageReaders = getImageReaders(stream);
+        if (!imageReaders.hasNext()) {
+            return null;
+        }
+
+        ImageReader reader = imageReaders.next();
+        reader.setInput(stream, false, true);
+        BufferedImage res = reader.read(0);
+        reader.dispose();
+
+        try {
+            stream.close();
+        } catch (IOException e) {
+            // Stream could be already closed, proceed silently in this case
+        }
+
+        return res;
+    }
+
+    /**
+     * Writes the specified image in the specified format (using an appropriate
+     * ImageWriter) to the specified ImageOutputStream.
+     * 
+     * @param im
+     *            the RenderedImage.
+     * @param formatName
+     *            the format name.
+     * @param output
+     *            the ImageOutputStream where Image to be written.
+     * @return true, if Image is written successfully, false otherwise.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public static boolean write(RenderedImage im, String formatName, ImageOutputStream output)
+            throws IOException {
+
+        if (im == null) {
+            throw new IllegalArgumentException("image cannot be NULL");
+        }
+        if (formatName == null) {
+            throw new IllegalArgumentException("format name cannot be NULL");
+        }
+        if (output == null) {
+            throw new IllegalArgumentException("output cannot be NULL");
+        }
+
+        Iterator<ImageWriter> it = getImageWriters(ImageTypeSpecifier.createFromRenderedImage(im),
+                formatName);
+        if (it.hasNext()) {
+            ImageWriter writer = it.next();
+            writer.setOutput(output);
+            writer.write(im);
+            output.flush();
+            writer.dispose();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Writes the specified image in the specified format (using an appropriate
+     * ImageWriter) to the specified File.
+     * 
+     * @param im
+     *            the RenderedImage.
+     * @param formatName
+     *            the format name.
+     * @param output
+     *            the output File where Image to be written.
+     * @return true, if Image is written successfully, false otherwise.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public static boolean write(RenderedImage im, String formatName, File output)
+            throws IOException {
+
+        if (output == null) {
+            throw new IllegalArgumentException("output cannot be NULL");
+        }
+
+        if (output.exists()) {
+            output.delete();
+        }
+
+        ImageOutputStream ios = createImageOutputStream(output);
+        boolean rt = write(im, formatName, ios);
+        ios.close();
+        return rt;
+    }
+
+    /**
+     * Writes the specified image in the specified format (using an appropriate
+     * ImageWriter) to the specified OutputStream.
+     * 
+     * @param im
+     *            the RenderedImage.
+     * @param formatName
+     *            the format name.
+     * @param output
+     *            the OutputStream where Image is to be written.
+     * @return true, if Image is written successfully, false otherwise.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public static boolean write(RenderedImage im, String formatName, OutputStream output)
+            throws IOException {
+
+        if (output == null) {
+            throw new IllegalArgumentException("output cannot be NULL");
+        }
+
+        ImageOutputStream ios = createImageOutputStream(output);
+        boolean rt = write(im, formatName, ios);
+        ios.close();
+        return rt;
+    }
+
+    /**
+     * Filter to match spi by format name.
+     */
+    static class FormatFilter implements ServiceRegistry.Filter {
+
+        /**
+         * The name.
+         */
+        private String name;
+
+        /**
+         * Instantiates a new format filter.
+         * 
+         * @param name
+         *            the name.
+         */
+        public FormatFilter(String name) {
+            this.name = name;
+        }
+
+        public boolean filter(Object provider) {
+            ImageReaderWriterSpi spi = (ImageReaderWriterSpi)provider;
+            return Arrays.asList(spi.getFormatNames()).contains(name);
+        }
+    }
+
+    /**
+     * Filter to match spi by format name and encoding possibility.
+     */
+    static class FormatAndEncodeFilter extends FormatFilter {
+
+        /**
+         * The type.
+         */
+        private ImageTypeSpecifier type;
+
+        /**
+         * Instantiates a new format and encode filter.
+         * 
+         * @param type
+         *            the type.
+         * @param name
+         *            the name.
+         */
+        public FormatAndEncodeFilter(ImageTypeSpecifier type, String name) {
+            super(name);
+            this.type = type;
+        }
+
+        @Override
+        public boolean filter(Object provider) {
+            ImageWriterSpi spi = (ImageWriterSpi)provider;
+            return super.filter(provider) && spi.canEncodeImage(type);
+        }
+    }
+
+    /**
+     * Filter to match spi by suffix.
+     */
+    static class SuffixFilter implements ServiceRegistry.Filter {
+
+        /**
+         * The suf.
+         */
+        private String suf;
+
+        /**
+         * Instantiates a new suffix filter.
+         * 
+         * @param suf
+         *            the suf.
+         */
+        public SuffixFilter(String suf) {
+            this.suf = suf;
+        }
+
+        public boolean filter(Object provider) {
+            ImageReaderWriterSpi spi = (ImageReaderWriterSpi)provider;
+            return Arrays.asList(spi.getFileSuffixes()).contains(suf);
+        }
+    }
+
+    /**
+     * Filter to match spi by decoding possibility.
+     */
+    static class CanReadFilter implements ServiceRegistry.Filter {
+
+        /**
+         * The input.
+         */
+        private Object input;
+
+        /**
+         * Instantiates a new can read filter.
+         * 
+         * @param input
+         *            the input.
+         */
+        public CanReadFilter(Object input) {
+            this.input = input;
+        }
+
+        public boolean filter(Object provider) {
+            ImageReaderSpi spi = (ImageReaderSpi)provider;
+            try {
+                return spi.canDecodeInput(input);
+            } catch (IOException e) {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Wraps Spi's iterator to ImageWriter iterator.
+     */
+    static class SpiIteratorToWritersIteratorWrapper implements Iterator<ImageWriter> {
+
+        /**
+         * The backend.
+         */
+        private Iterator<ImageWriterSpi> backend;
+
+        /**
+         * Instantiates a new spi iterator to writers iterator wrapper.
+         * 
+         * @param backend
+         *            the backend.
+         */
+        public SpiIteratorToWritersIteratorWrapper(Iterator<ImageWriterSpi> backend) {
+            this.backend = backend;
+        }
+
+        /**
+         * Next.
+         * 
+         * @return the image writer.
+         */
+        public ImageWriter next() {
+            try {
+                return backend.next().createWriterInstance();
+            } catch (IOException e) {
+                e.printStackTrace();
+                return null;
+            }
+        }
+
+        /**
+         * Checks for next.
+         * 
+         * @return true, if successful.
+         */
+        public boolean hasNext() {
+            return backend.hasNext();
+        }
+
+        /**
+         * Removes the.
+         */
+        public void remove() {
+            throw new UnsupportedOperationException(
+                    "Use deregisterServiceprovider instead of Iterator.remove()");
+        }
+    }
+
+    /**
+     * Wraps spi's iterator to ImageReader iterator.
+     */
+    static class SpiIteratorToReadersIteratorWrapper implements Iterator<ImageReader> {
+
+        /**
+         * The backend.
+         */
+        private Iterator<ImageReaderSpi> backend;
+
+        /**
+         * Instantiates a new spi iterator to readers iterator wrapper.
+         * 
+         * @param backend
+         *            the backend.
+         */
+        public SpiIteratorToReadersIteratorWrapper(Iterator<ImageReaderSpi> backend) {
+            this.backend = backend;
+        }
+
+        /**
+         * Next.
+         * 
+         * @return the image reader.
+         */
+        public ImageReader next() {
+            try {
+                return backend.next().createReaderInstance();
+            } catch (IOException e) {
+                e.printStackTrace();
+                return null;
+            }
+        }
+
+        /**
+         * Checks for next.
+         * 
+         * @return true, if successful.
+         */
+        public boolean hasNext() {
+            return backend.hasNext();
+        }
+
+        /**
+         * Removes the.
+         */
+        public void remove() {
+            throw new UnsupportedOperationException(
+                    "Use deregisterServiceprovider instead of Iterator.remove()");
+        }
+    }
+}
diff --git a/awt/javax/imageio/ImageReadParam.java b/awt/javax/imageio/ImageReadParam.java
new file mode 100644
index 0000000..9cc5c5f
--- /dev/null
+++ b/awt/javax/imageio/ImageReadParam.java
@@ -0,0 +1,201 @@
+/*
+ *  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.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+package javax.imageio;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+
+/*
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The ImageReadParam class provides information to the ImageReader about how an
+ * image is to be decoded.
+ * 
+ * @since Android 1.0
+ */
+public class ImageReadParam extends IIOParam {
+
+    /**
+     * This flag indicates if this ImageReadParam supports setting the source
+     * rendering size.
+     */
+    protected boolean canSetSourceRenderSize;
+
+    /**
+     * The destination BufferedImage.
+     */
+    protected BufferedImage destination;
+
+    /**
+     * The destination bands.
+     */
+    protected int[] destinationBands;
+
+    /**
+     * The minimum progressive pass.
+     */
+    protected int minProgressivePass;
+
+    /**
+     * The number of progressive passes.
+     */
+    protected int numProgressivePasses;
+
+    /**
+     * The source render size.
+     */
+    protected Dimension sourceRenderSize;
+
+    /**
+     * Returns true if this ImageReaderParam supports rendering a source image
+     * at an arbitrary size.
+     * 
+     * @return true, if this ImageReaderParam supports rendering a source image
+     *         at an arbitrary size, false otherwise.
+     */
+    public boolean canSetSourceRenderSize() {
+        return canSetSourceRenderSize;
+    }
+
+    /**
+     * Gets the current destination image as BufferedImage.
+     * 
+     * @return the BufferedImage which represents the destination.
+     */
+    public BufferedImage getDestination() {
+        return destination;
+    }
+
+    /**
+     * Gets the indices of destination bands.
+     * 
+     * @return the array of destination bands.
+     */
+    public int[] getDestinationBands() {
+        return destinationBands;
+    }
+
+    /**
+     * Gets the index of the maximum pass to be decoded. This method returns
+     * Integer.MAX_VALUE, if getSourceNumProgressivePasses() method returns
+     * value that is equal to Integer.MAX_VALUE. Otherwise this method returns
+     * getSourceMinProgressivePass() + getSourceNumProgressivePasses() - 1.
+     * 
+     * @return the index of the maximum pass to be decoded.
+     */
+    public int getSourceMaxProgressivePass() {
+        if (getSourceNumProgressivePasses() == Integer.MAX_VALUE) {
+            return Integer.MAX_VALUE;
+        }
+        return getSourceMinProgressivePass() + getSourceNumProgressivePasses() - 1;
+    }
+
+    /**
+     * Gets the index of the minimum progressive pass that is decoded, default
+     * is 0.
+     * 
+     * @return the index of the minimum progressive pass that is decoded,
+     *         default is 0.
+     */
+    public int getSourceMinProgressivePass() {
+        return minProgressivePass;
+    }
+
+    /**
+     * Gets the number of progressive passes. The default value is
+     * Integer.MAX_VALUE.
+     * 
+     * @return the number of progressive passes.
+     */
+    public int getSourceNumProgressivePasses() {
+        return numProgressivePasses;
+    }
+
+    /**
+     * Gets the dimension of source image which will be rendered during decoding
+     * process.
+     * 
+     * @return the source render size.
+     */
+    public Dimension getSourceRenderSize() {
+        return sourceRenderSize;
+    }
+
+    /**
+     * Sets the specified destination image. This image will be used by read,
+     * readAll, and readRaster methods, and a reference to it will be returned
+     * by those methods.
+     * 
+     * @param destination
+     *            the destination image.
+     */
+    public void setDestination(BufferedImage destination) {
+        this.destination = destination;
+    }
+
+    /**
+     * Sets the indices of the destination bands.
+     * 
+     * @param destinationBands
+     *            the indices of the destination bands.
+     */
+    public void setDestinationBands(int[] destinationBands) {
+        this.destinationBands = destinationBands;
+    }
+
+    @Override
+    public void setDestinationType(ImageTypeSpecifier destinationType) {
+        this.destinationType = destinationType;
+    }
+
+    /**
+     * Sets the source progressive passes.
+     * 
+     * @param minPass
+     *            the index of the minimum pass to be decoded.
+     * @param numPasses
+     *            the number of passes to be decoded.
+     */
+    public void setSourceProgressivePasses(int minPass, int numPasses) {
+        minProgressivePass = minPass;
+        numProgressivePasses = numPasses;
+    }
+
+    /**
+     * Sets the dimension size of source image if an image can be rendered at an
+     * arbitrary size.
+     * 
+     * @param size
+     *            the size of rendered image.
+     * @throws UnsupportedOperationException
+     *             the unsupported operation exception.
+     */
+    public void setSourceRenderSize(Dimension size) throws UnsupportedOperationException {
+        if (!canSetSourceRenderSize) {
+            throw new UnsupportedOperationException("can't set source renderer size");
+        }
+        sourceRenderSize = size;
+    }
+}
diff --git a/awt/javax/imageio/ImageReader.java b/awt/javax/imageio/ImageReader.java
new file mode 100644
index 0000000..cf282ed
--- /dev/null
+++ b/awt/javax/imageio/ImageReader.java
@@ -0,0 +1,1162 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio;
+
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.event.IIOReadWarningListener;
+import javax.imageio.event.IIOReadProgressListener;
+import javax.imageio.event.IIOReadUpdateListener;
+import java.util.Locale;
+import java.util.List;
+import java.util.Iterator;
+import java.util.Set;
+import java.io.IOException;
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.*;
+
+/**
+ * The ImageReader class is an abstract class for decoding images. ImageReader
+ * objects are instantiated by the service provider interface, ImageReaderSpi
+ * class, for the specific format. ImageReaderSpi class should be registered
+ * with the IIORegistry, which uses them for format recognition and presentation
+ * of available format readers and writers.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ImageReader {
+
+    /**
+     * The originating provider.
+     */
+    protected ImageReaderSpi originatingProvider;
+
+    /**
+     * The input object such as ImageInputStream.
+     */
+    protected Object input;
+
+    /**
+     * The seek forward only.
+     */
+    protected boolean seekForwardOnly;
+
+    /**
+     * The ignore metadata flag indicates whether current input source has been
+     * marked as metadata is allowed to be ignored by setInput.
+     */
+    protected boolean ignoreMetadata;
+
+    /**
+     * The minimum index.
+     */
+    protected int minIndex;
+
+    /**
+     * The available locales.
+     */
+    protected Locale[] availableLocales;
+
+    /**
+     * The locale.
+     */
+    protected Locale locale;
+
+    /**
+     * The list of warning listeners.
+     */
+    protected List<IIOReadWarningListener> warningListeners;
+
+    /**
+     * The list of warning locales.
+     */
+    protected List<Locale> warningLocales;
+
+    /**
+     * The list of progress listeners.
+     */
+    protected List<IIOReadProgressListener> progressListeners;
+
+    /**
+     * The list of update listeners.
+     */
+    protected List<IIOReadUpdateListener> updateListeners;
+
+    /**
+     * Instantiates a new ImageReader.
+     * 
+     * @param originatingProvider
+     *            the ImageReaderSpi which instantiates this ImageReader.
+     */
+    protected ImageReader(ImageReaderSpi originatingProvider) {
+        this.originatingProvider = originatingProvider;
+    }
+
+    /**
+     * Gets the format name of this input source.
+     * 
+     * @return the format name of this input source.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public String getFormatName() throws IOException {
+        return originatingProvider.getFormatNames()[0];
+    }
+
+    /**
+     * Gets the ImageReaderSpi which instantiated this ImageReader.
+     * 
+     * @return the ImageReaderSpi.
+     */
+    public ImageReaderSpi getOriginatingProvider() {
+        return originatingProvider;
+    }
+
+    /**
+     * Sets the specified Object as the input source of this ImageReader.
+     * 
+     * @param input
+     *            the input source, it can be an ImageInputStream or other
+     *            supported objects.
+     * @param seekForwardOnly
+     *            indicates whether the stream must be read sequentially from
+     *            its current starting point.
+     * @param ignoreMetadata
+     *            parameter which indicates if metadata may be ignored during
+     *            reads or not.
+     */
+    public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
+        if (input != null) {
+            if (!isSupported(input) && !(input instanceof ImageInputStream)) {
+                throw new IllegalArgumentException("input " + input + " is not supported");
+            }
+        }
+        this.minIndex = 0;
+        this.seekForwardOnly = seekForwardOnly;
+        this.ignoreMetadata = ignoreMetadata;
+        this.input = input;
+    }
+
+    /**
+     * Checks if is supported.
+     * 
+     * @param input
+     *            the input.
+     * @return true, if is supported.
+     */
+    private boolean isSupported(Object input) {
+        ImageReaderSpi spi = getOriginatingProvider();
+        if (null != spi) {
+            Class[] outTypes = spi.getInputTypes();
+            for (Class<?> element : outTypes) {
+                if (element.isInstance(input)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Sets the specified Object as the input source of this ImageReader.
+     * Metadata is not ignored.
+     * 
+     * @param input
+     *            the input source, it can be an ImageInputStream or other
+     *            supported objects.
+     * @param seekForwardOnly
+     *            indicates whether the stream must be read sequentially from
+     *            its current starting point.
+     */
+    public void setInput(Object input, boolean seekForwardOnly) {
+        setInput(input, seekForwardOnly, false);
+    }
+
+    /**
+     * Sets the specified Object as the input source of this ImageReader.
+     * Metadata is not ignored and forward seeking is not required.
+     * 
+     * @param input
+     *            the input source, it can be ImageInputStream or other objects.
+     */
+    public void setInput(Object input) {
+        setInput(input, false, false);
+    }
+
+    /**
+     * Gets the input source object of this ImageReader, or returns null.
+     * 
+     * @return the input source object such as ImageInputStream, or null.
+     */
+    public Object getInput() {
+        return input;
+    }
+
+    /**
+     * Checks if the input source supports only forward reading, or not.
+     * 
+     * @return true, if the input source supports only forward reading, false
+     *         otherwise.
+     */
+    public boolean isSeekForwardOnly() {
+        return seekForwardOnly;
+    }
+
+    /**
+     * Returns true if the current input source allows to metadata to be ignored
+     * by passing true as the ignoreMetadata argument to the setInput method.
+     * 
+     * @return true, if the current input source allows to metadata to be
+     *         ignored by passing true as the ignoreMetadata argument to the
+     *         setInput method.
+     */
+    public boolean isIgnoringMetadata() {
+        return ignoreMetadata;
+    }
+
+    /**
+     * Gets the minimum valid index for reading an image, thumbnail, or image
+     * metadata.
+     * 
+     * @return the minimum valid index for reading an image, thumbnail, or image
+     *         metadata.
+     */
+    public int getMinIndex() {
+        return minIndex;
+    }
+
+    /**
+     * Gets the available locales.
+     * 
+     * @return an array of the available locales.
+     */
+    public Locale[] getAvailableLocales() {
+        return availableLocales;
+    }
+
+    /**
+     * Sets the locale to this ImageReader.
+     * 
+     * @param locale
+     *            the Locale.
+     */
+    public void setLocale(Locale locale) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Gets the locale of this ImageReader.
+     * 
+     * @return the locale of this ImageReader.
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+    /**
+     * Gets the number of images available in the current input source.
+     * 
+     * @param allowSearch
+     *            the parameter which indicates what a search is required; if
+     *            false, the reader may return -1 without searching.
+     * @return the number of images.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public abstract int getNumImages(boolean allowSearch) throws IOException;
+
+    /**
+     * Gets the width of the specified image in input source.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @return the width in pixels.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public abstract int getWidth(int imageIndex) throws IOException;
+
+    /**
+     * Gets the height of the specified image in input source.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @return the height in pixels.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public abstract int getHeight(int imageIndex) throws IOException;
+
+    /**
+     * Checks if the storage format of the specified image places an impediment
+     * on random pixels access or not.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @return true, if the storage format of the specified image places an
+     *         impediment on random pixels access, false otherwise.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public boolean isRandomAccessEasy(int imageIndex) throws IOException {
+        return false; // def
+    }
+
+    /**
+     * Gets the aspect ratio (width devided by height) of the image.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @return the aspect ratio of the image.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public float getAspectRatio(int imageIndex) throws IOException {
+        return (float)getWidth(imageIndex) / getHeight(imageIndex);
+    }
+
+    /**
+     * Gets an ImageTypeSpecifier which indicates the type of the specified
+     * image.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @return the ImageTypeSpecifier.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public ImageTypeSpecifier getRawImageType(int imageIndex) throws IOException {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Gets an Iterator of ImageTypeSpecifier objects which are associated with
+     * image types that may be used when decoding specified image.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @return an Iterator of ImageTypeSpecifier objects.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public abstract Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException;
+
+    /**
+     * Gets the default ImageReadParam object.
+     * 
+     * @return the ImageReadParam object.
+     */
+    public ImageReadParam getDefaultReadParam() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Gets an IIOMetadata object for this input source.
+     * 
+     * @return the IIOMetadata.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public abstract IIOMetadata getStreamMetadata() throws IOException;
+
+    /**
+     * Gets an IIOMetadata object for this input source.
+     * 
+     * @param formatName
+     *            the desired metadata format to be used in the returned
+     *            IIOMetadata object.
+     * @param nodeNames
+     *            the node names of the document.
+     * @return the IIOMetadata.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public IIOMetadata getStreamMetadata(String formatName, Set<String> nodeNames)
+            throws IOException {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Gets the image metadata of the specified image in input source.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @return the IIOMetadata.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public abstract IIOMetadata getImageMetadata(int imageIndex) throws IOException;
+
+    /**
+     * Gets the image metadata of the specified image input source.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param formatName
+     *            the desired metadata format to be used in the returned
+     *            IIOMetadata object.
+     * @param nodeNames
+     *            the node names which can be contained in the document.
+     * @return the IIOMetadata.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public IIOMetadata getImageMetadata(int imageIndex, String formatName, Set<String> nodeNames)
+            throws IOException {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Reads the specified image and returns it as a BufferedImage using the
+     * default ImageReadParam.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @return the BufferedImage.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public BufferedImage read(int imageIndex) throws IOException {
+        return read(imageIndex, null);
+    }
+
+    /**
+     * Reads the specified image and returns it as a BufferedImage using the
+     * specified ImageReadParam.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param param
+     *            the ImageReadParam.
+     * @return the BufferedImage.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public abstract BufferedImage read(int imageIndex, ImageReadParam param) throws IOException;
+
+    /**
+     * Reads the specified image and returns an IIOImage with this image,
+     * thumbnails, and metadata for this image, using the specified
+     * ImageReadParam.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param param
+     *            the ImageReadParam.
+     * @return the IIOImage.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public IIOImage readAll(int imageIndex, ImageReadParam param) throws IOException {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Returns an Iterator of IIOImages from the input source.
+     * 
+     * @param params
+     *            the Iterator of ImageReadParam objects.
+     * @return the iterator of IIOImages.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public Iterator<IIOImage> readAll(Iterator<? extends ImageReadParam> params) throws IOException {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Checks whether or not this plug-in supports reading a Raster.
+     * 
+     * @return true, if this plug-in supports reading a Raster, false otherwise.
+     */
+    public boolean canReadRaster() {
+        return false; // def
+    }
+
+    /**
+     * Reads a new Raster object which contains the raw pixel data from the
+     * image.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param param
+     *            the ImageReadParam.
+     * @return the Raster.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public Raster readRaster(int imageIndex, ImageReadParam param) throws IOException {
+        throw new UnsupportedOperationException("Unsupported");
+    }
+
+    /**
+     * Checks if the specified image has tiles or not.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @return true, if the specified image has tiles, false otherwise.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public boolean isImageTiled(int imageIndex) throws IOException {
+        return false; // def
+    }
+
+    /**
+     * Gets the tile width in the specified image.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @return the tile width.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public int getTileWidth(int imageIndex) throws IOException {
+        return getWidth(imageIndex); // def
+    }
+
+    /**
+     * Gets the tile height in the specified image.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @return the tile height.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public int getTileHeight(int imageIndex) throws IOException {
+        return getHeight(imageIndex); // def
+    }
+
+    /**
+     * Gets the X coordinate of the upper left corner of the tile grid in the
+     * specified image.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @return the X coordinate of the upper left corner of the tile grid.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public int getTileGridXOffset(int imageIndex) throws IOException {
+        return 0; // def
+    }
+
+    /**
+     * Gets the Y coordinate of the upper left corner of the tile grid in the
+     * specified image.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @return the Y coordinate of the upper left corner of the tile grid.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public int getTileGridYOffset(int imageIndex) throws IOException {
+        return 0; // def
+    }
+
+    /**
+     * Reads the tile specified by the tileX and tileY parameters of the
+     * specified image and returns it as a BufferedImage.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param tileX
+     *            the X index of tile.
+     * @param tileY
+     *            the Y index of tile.
+     * @return the BufferedImage.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public BufferedImage readTile(int imageIndex, int tileX, int tileY) throws IOException {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Reads the tile specified by the tileX and tileY parameters of the
+     * specified image and returns it as a Raster.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param tileX
+     *            the X index of tile.
+     * @param tileY
+     *            the Y index of tile.
+     * @return the Raster.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public Raster readTileRaster(int imageIndex, int tileX, int tileY) throws IOException {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Reads the specified image using the specified ImageReadParam and returns
+     * it as a RenderedImage.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param param
+     *            the ImageReadParam.
+     * @return the RenderedImage.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public RenderedImage readAsRenderedImage(int imageIndex, ImageReadParam param)
+            throws IOException {
+        return read(imageIndex, param);
+    }
+
+    /**
+     * Returns true if the image format supported by this reader supports
+     * thumbnail preview images.
+     * 
+     * @return true, if the image format supported by this reader supports
+     *         thumbnail preview images, false otherwise.
+     */
+    public boolean readerSupportsThumbnails() {
+        return false; // def
+    }
+
+    /**
+     * Checks if the specified image has thumbnails or not.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @return true, if the specified image has thumbnails, false otherwise.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public boolean hasThumbnails(int imageIndex) throws IOException {
+        return getNumThumbnails(imageIndex) > 0; // def
+    }
+
+    /**
+     * Gets the number of thumbnails for the specified image.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @return the number of thumbnails.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public int getNumThumbnails(int imageIndex) throws IOException {
+        return 0; // def
+    }
+
+    /**
+     * Gets the width of the specified thumbnail for the specified image.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @param thumbnailIndex
+     *            the thumbnail's index.
+     * @return the thumbnail width.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public int getThumbnailWidth(int imageIndex, int thumbnailIndex) throws IOException {
+        return readThumbnail(imageIndex, thumbnailIndex).getWidth(); // def
+    }
+
+    /**
+     * Gets the height of the specified thumbnail for the specified image.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @param thumbnailIndex
+     *            the thumbnail's index.
+     * @return the thumbnail height.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public int getThumbnailHeight(int imageIndex, int thumbnailIndex) throws IOException {
+        return readThumbnail(imageIndex, thumbnailIndex).getHeight(); // def
+    }
+
+    /**
+     * Reads the thumbnail image for the specified image as a BufferedImage.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param thumbnailIndex
+     *            the thumbnail index.
+     * @return the BufferedImage.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException {
+        throw new UnsupportedOperationException("Unsupported"); // def
+    }
+
+    /**
+     * Requests an abort operation for current reading operation.
+     */
+    public void abort() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Checks whether or not a request to abort the current read operation has
+     * been made successfully.
+     * 
+     * @return true, if the request to abort the current read operation has been
+     *         made successfully, false otherwise.
+     */
+    protected boolean abortRequested() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Clears all previous abort request, and abortRequested returns false after
+     * calling this method.
+     */
+    protected void clearAbortRequest() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Adds the IIOReadWarningListener.
+     * 
+     * @param listener
+     *            the IIOReadWarningListener.
+     */
+    public void addIIOReadWarningListener(IIOReadWarningListener listener) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Removes the specified IIOReadWarningListener.
+     * 
+     * @param listener
+     *            the IIOReadWarningListener to be removed.
+     */
+    public void removeIIOReadWarningListener(IIOReadWarningListener listener) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Removes all registered IIOReadWarningListeners.
+     */
+    public void removeAllIIOReadWarningListeners() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Adds the IIOReadProgressListener.
+     * 
+     * @param listener
+     *            the IIOReadProgressListener.
+     */
+    public void addIIOReadProgressListener(IIOReadProgressListener listener) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Removes the specified IIOReadProgressListener.
+     * 
+     * @param listener
+     *            the IIOReadProgressListener to be removed.
+     */
+    public void removeIIOReadProgressListener(IIOReadProgressListener listener) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Removes registered IIOReadProgressListeners.
+     */
+    public void removeAllIIOReadProgressListeners() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Adds the IIOReadUpdateListener.
+     * 
+     * @param listener
+     *            the IIOReadUpdateListener.
+     */
+    public void addIIOReadUpdateListener(IIOReadUpdateListener listener) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Removes the specified IIOReadUpdateListener.
+     * 
+     * @param listener
+     *            the IIOReadUpdateListener to be removed.
+     */
+    public void removeIIOReadUpdateListener(IIOReadUpdateListener listener) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Removes registered IIOReadUpdateListeners.
+     */
+    public void removeAllIIOReadUpdateListeners() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the start of an sequence of image reads by calling the
+     * sequenceStarted method on all registered IIOReadProgressListeners.
+     * 
+     * @param minIndex
+     *            the minimum index.
+     */
+    protected void processSequenceStarted(int minIndex) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the completion of an sequence of image reads by calling
+     * sequenceComplete method on all registered IIOReadProgressListeners.
+     */
+    protected void processSequenceComplete() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the start of an image read by calling the imageStarted method
+     * on all registered IIOReadProgressListeners.
+     * 
+     * @param imageIndex
+     *            the image index.
+     */
+    protected void processImageStarted(int imageIndex) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the current percentage of image completion by calling the
+     * imageProgress method on all registered IIOReadProgressListeners.
+     * 
+     * @param percentageDone
+     *            the percentage done.
+     */
+    protected void processImageProgress(float percentageDone) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes image completion by calling the imageComplete method on all
+     * registered IIOReadProgressListeners.
+     */
+    protected void processImageComplete() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the start of a thumbnail read by calling the thumbnailStarted
+     * method on all registered IIOReadProgressListeners.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param thumbnailIndex
+     *            the thumbnail index.
+     */
+    protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the current percentage of thumbnail completion by calling the
+     * thumbnailProgress method on all registered IIOReadProgressListeners.
+     * 
+     * @param percentageDone
+     *            the percentage done.
+     */
+    protected void processThumbnailProgress(float percentageDone) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the completion of a thumbnail read by calling the
+     * thumbnailComplete method on all registered IIOReadProgressListeners.
+     */
+    protected void processThumbnailComplete() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes a read aborted event by calling the readAborted method on all
+     * registered IIOReadProgressListeners.
+     */
+    protected void processReadAborted() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the beginning of a progressive pass by calling the passStarted
+     * method on all registered IIOReadUpdateListeners.
+     * 
+     * @param theImage
+     *            the image to be updated.
+     * @param pass
+     *            the current pass index.
+     * @param minPass
+     *            the minimum pass index.
+     * @param maxPass
+     *            the maximum pass index.
+     * @param minX
+     *            the X coordinate of of the upper left pixel.
+     * @param minY
+     *            the Y coordinate of of the upper left pixel.
+     * @param periodX
+     *            the horizontal separation between pixels.
+     * @param periodY
+     *            the vertical separation between pixels.
+     * @param bands
+     *            the number of affected bands.
+     */
+    protected void processPassStarted(BufferedImage theImage, int pass, int minPass, int maxPass,
+            int minX, int minY, int periodX, int periodY, int[] bands) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the update of a set of samples by calling the imageUpdate
+     * method on all registered IIOReadUpdateListeners.
+     * 
+     * @param theImage
+     *            the image to be updated.
+     * @param minX
+     *            the X coordinate of the upper left pixel.
+     * @param minY
+     *            the Y coordinate of the upper left pixel.
+     * @param width
+     *            the width of updated area.
+     * @param height
+     *            the height of updated area.
+     * @param periodX
+     *            the horizontal separation between pixels.
+     * @param periodY
+     *            the vertical separation between pixels.
+     * @param bands
+     *            the number of affected bands.
+     */
+    protected void processImageUpdate(BufferedImage theImage, int minX, int minY, int width,
+            int height, int periodX, int periodY, int[] bands) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the end of a progressive pass by calling passComplete method of
+     * registered IIOReadUpdateListeners.
+     * 
+     * @param theImage
+     *            the image to be updated.
+     */
+    protected void processPassComplete(BufferedImage theImage) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the beginning of a thumbnail progressive pass by calling the
+     * thumbnailPassStarted method on all registered IIOReadUpdateListeners.
+     * 
+     * @param theThumbnail
+     *            the thumbnail to be updated.
+     * @param pass
+     *            the current pass index.
+     * @param minPass
+     *            the minimum pass index.
+     * @param maxPass
+     *            the maximum pass index.
+     * @param minX
+     *            the X coordinate of the upper left pixel.
+     * @param minY
+     *            the Y coordinate of the upper left pixel.
+     * @param periodX
+     *            the horizontal separation between pixels.
+     * @param periodY
+     *            the vertical separation between pixels.
+     * @param bands
+     *            the number of affected bands.
+     */
+    protected void processThumbnailPassStarted(BufferedImage theThumbnail, int pass, int minPass,
+            int maxPass, int minX, int minY, int periodX, int periodY, int[] bands) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the update of a set of samples in a thumbnail image by calling
+     * the thumbnailUpdate method on all registered IIOReadUpdateListeners.
+     * 
+     * @param theThumbnail
+     *            the thumbnail to be updated.
+     * @param minX
+     *            the X coordinate of the upper left pixel.
+     * @param minY
+     *            the Y coordinate of the upper left pixel.
+     * @param width
+     *            the total width of the updated area.
+     * @param height
+     *            the total height of the updated area.
+     * @param periodX
+     *            the horizontal separation between pixels.
+     * @param periodY
+     *            the vertical separation between pixels.
+     * @param bands
+     *            the number of affected bands.
+     */
+    protected void processThumbnailUpdate(BufferedImage theThumbnail, int minX, int minY,
+            int width, int height, int periodX, int periodY, int[] bands) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes the end of a thumbnail progressive pass by calling the
+     * thumbnailPassComplete method on all registered IIOReadUpdateListeners.
+     * 
+     * @param theThumbnail
+     *            the thumbnail to be updated.
+     */
+    protected void processThumbnailPassComplete(BufferedImage theThumbnail) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes a warning message by calling warningOccurred method of
+     * registered IIOReadWarningListeners.
+     * 
+     * @param warning
+     *            the warning.
+     */
+    protected void processWarningOccurred(String warning) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Processes a warning by calling the warningOccurred method of on all
+     * registered IIOReadWarningListeners.
+     * 
+     * @param baseName
+     *            the base name of ResourceBundles.
+     * @param keyword
+     *            the keyword to index the warning among ResourceBundles.
+     */
+    protected void processWarningOccurred(String baseName, String keyword) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Resets this ImageReader.
+     */
+    public void reset() {
+        // def
+        setInput(null, false);
+        setLocale(null);
+        removeAllIIOReadUpdateListeners();
+        removeAllIIOReadWarningListeners();
+        removeAllIIOReadProgressListeners();
+        clearAbortRequest();
+    }
+
+    /**
+     * Disposes of any resources.
+     */
+    public void dispose() {
+        // do nothing by def
+    }
+
+    /**
+     * Gets the region of source image that should be read with the specified
+     * width, height and ImageReadParam.
+     * 
+     * @param param
+     *            the ImageReadParam object, or null.
+     * @param srcWidth
+     *            the source image's width.
+     * @param srcHeight
+     *            the source image's height.
+     * @return the Rectangle of source region.
+     */
+    protected static Rectangle getSourceRegion(ImageReadParam param, int srcWidth, int srcHeight) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Computes the specified source region and the specified destination region
+     * with the specified the width and height of the source image, an optional
+     * destination image, and an ImageReadParam.
+     * 
+     * @param param
+     *            the an ImageReadParam object, or null.
+     * @param srcWidth
+     *            the source image's width.
+     * @param srcHeight
+     *            the source image's height.
+     * @param image
+     *            the destination image.
+     * @param srcRegion
+     *            the source region.
+     * @param destRegion
+     *            the destination region.
+     */
+    protected static void computeRegions(ImageReadParam param, int srcWidth, int srcHeight,
+            BufferedImage image, Rectangle srcRegion, Rectangle destRegion) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Checks the validity of the source and destination band and is called when
+     * the reader knows the number of bands of the source image and the number
+     * of bands of the destination image.
+     * 
+     * @param param
+     *            the ImageReadParam for reading the Image.
+     * @param numSrcBands
+     *            the number of bands in the source.
+     * @param numDstBands
+     *            the number of bands in the destination.
+     */
+    protected static void checkReadParamBandSettings(ImageReadParam param, int numSrcBands,
+            int numDstBands) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Gets the destination image where the decoded data is written.
+     * 
+     * @param param
+     *            the ImageReadParam.
+     * @param imageTypes
+     *            the iterator of ImageTypeSpecifier objects.
+     * @param width
+     *            the width of the image being decoded.
+     * @param height
+     *            the height of the image being decoded.
+     * @return the BufferedImage where decoded pixels should be written.
+     * @throws IIOException
+     *             the IIOException is thrown if there is no suitable
+     *             ImageTypeSpecifier.
+     */
+    protected static BufferedImage getDestination(ImageReadParam param,
+            Iterator<ImageTypeSpecifier> imageTypes, int width, int height) throws IIOException {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+}
diff --git a/awt/javax/imageio/ImageTranscoder.java b/awt/javax/imageio/ImageTranscoder.java
new file mode 100644
index 0000000..632d890
--- /dev/null
+++ b/awt/javax/imageio/ImageTranscoder.java
@@ -0,0 +1,67 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio;
+
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.ImageTypeSpecifier;
+
+/**
+ * The ImageTranscoder interface is to be implemented by classes that perform
+ * image transcoding operations, that is, take images written in one format and
+ * write them in another format using read/write operations. Some image data can
+ * be lost in such processes. The ImageTranscoder interface converts metadata
+ * objects (IIOMetadata) of ImageReader to appropriate metadata object for
+ * ImageWriter.
+ * 
+ * @since Android 1.0
+ */
+public interface ImageTranscoder {
+
+    /**
+     * Converts the specified IIOMetadata object using the specified
+     * ImageWriteParam for obtaining writer's metadata structure.
+     * 
+     * @param inData
+     *            the IIOMetadata.
+     * @param param
+     *            the ImageWriteParam.
+     * @return the IIOMetadata, or null.
+     */
+    IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param);
+
+    /**
+     * Converts the specified IIOMetadata object using the specified
+     * ImageWriteParam for obtaining writer's metadata structure and
+     * ImageTypeSpecifier object for obtaining the layout and color information
+     * of the image for this metadata.
+     * 
+     * @param inData
+     *            the IIOMetadata.
+     * @param imageType
+     *            the ImageTypeSpecifier.
+     * @param param
+     *            the ImageWriteParam.
+     * @return the IIOMetadata, or null.
+     */
+    IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType,
+            ImageWriteParam param);
+}
diff --git a/awt/javax/imageio/ImageTypeSpecifier.java b/awt/javax/imageio/ImageTypeSpecifier.java
new file mode 100644
index 0000000..505b1c4
--- /dev/null
+++ b/awt/javax/imageio/ImageTypeSpecifier.java
@@ -0,0 +1,347 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio;
+
+import java.awt.image.ColorModel;
+import java.awt.image.SampleModel;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+import java.awt.color.ColorSpace;
+
+/**
+ * The ImageTypeSpecifier class performs conversion operations on the
+ * SampleModel and the ColorModel of an image.
+ * 
+ * @since Android 1.0
+ */
+public class ImageTypeSpecifier {
+
+    /**
+     * The ColorModel of this ImageTypeSpecifier.
+     */
+    protected ColorModel colorModel;
+
+    /**
+     * The SampleModel of this ImageTypeSpecifier.
+     */
+    protected SampleModel sampleModel;
+
+    /**
+     * Instantiates a new ImageTypeSpecifier with the specified ColorModel and
+     * SampleModel objects.
+     * 
+     * @param colorModel
+     *            the ColorModel.
+     * @param sampleModel
+     *            the SampleModel.
+     */
+    public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) {
+        if (colorModel == null) {
+            throw new IllegalArgumentException("color model should not be NULL");
+        }
+        if (sampleModel == null) {
+            throw new IllegalArgumentException("sample model should not be NULL");
+        }
+        if (!colorModel.isCompatibleSampleModel(sampleModel)) {
+            throw new IllegalArgumentException("color and sample models are not compatible");
+        }
+
+        this.colorModel = colorModel;
+        this.sampleModel = sampleModel;
+    }
+
+    /**
+     * Instantiates a new ImageTypeSpecifier using the specified RenderedImage.
+     * 
+     * @param renderedImage
+     *            the RenderedImage.
+     */
+    public ImageTypeSpecifier(RenderedImage renderedImage) {
+        if (renderedImage == null) {
+            throw new IllegalArgumentException("image should not be NULL");
+        }
+        this.colorModel = renderedImage.getColorModel();
+        this.sampleModel = renderedImage.getSampleModel();
+    }
+
+    /**
+     * Creates an ImageTypeSpecifier with the specified DirectColorModel and a
+     * packed SampleModel.
+     * 
+     * @param colorSpace
+     *            the ColorSpace.
+     * @param redMask
+     *            the red mask.
+     * @param greenMask
+     *            the green mask.
+     * @param blueMask
+     *            the blue mask.
+     * @param alphaMask
+     *            the alpha mask.
+     * @param transferType
+     *            the transfer type.
+     * @param isAlphaPremultiplied
+     *            the parameter indicates if the color channel is pre-multiplied
+     *            by alpha.
+     * @return the ImageTypeSpecifier.
+     */
+    public static ImageTypeSpecifier createPacked(ColorSpace colorSpace, int redMask,
+            int greenMask, int blueMask, int alphaMask, int transferType,
+            boolean isAlphaPremultiplied) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Creates an ImageTypeSpecifier with specified ComponentColorModel and a
+     * PixelInterleavedSampleModel.
+     * 
+     * @param colorSpace
+     *            the ColorSpace.
+     * @param bandOffsets
+     *            the band offsets.
+     * @param dataType
+     *            the data type.
+     * @param hasAlpha
+     *            the parameter indicates if alpha channel is needed.
+     * @param isAlphaPremultiplied
+     *            the parameter indicates if the color channel is pre-multiplied
+     *            by alpha.
+     * @return the ImageTypeSpecifier.
+     */
+    public static ImageTypeSpecifier createInterleaved(ColorSpace colorSpace, int[] bandOffsets,
+            int dataType, boolean hasAlpha, boolean isAlphaPremultiplied) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Creates a ImageTypeSpecifier for a image with a BandedSampleModel and a
+     * ComponentColorModel.
+     * 
+     * @param colorSpace
+     *            the ColorSpace.
+     * @param bankIndices
+     *            the bank indices.
+     * @param bandOffsets
+     *            the band offsets.
+     * @param dataType
+     *            the data type.
+     * @param hasAlpha
+     *            the parameter indicates a presence of alpha channel.
+     * @param isAlphaPremultiplied
+     *            the parameter indicates whether or not color channel is alpha
+     *            pre-multiplied.
+     * @return the image type specifier
+     */
+    public static ImageTypeSpecifier createBanded(ColorSpace colorSpace, int[] bankIndices,
+            int[] bandOffsets, int dataType, boolean hasAlpha, boolean isAlphaPremultiplied) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Creates a ImageTypeSpecifier for a grayscale image.
+     * 
+     * @param bits
+     *            the number of bits per gray value.
+     * @param dataType
+     *            the data type.
+     * @param isSigned
+     *            a signed flag.
+     * @return the ImageTypeSpecifier.
+     */
+    public static ImageTypeSpecifier createGrayscale(int bits, int dataType, boolean isSigned) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Creates a ImageTypeSpecifier for a grayscale image.
+     * 
+     * @param bits
+     *            the number of bits per gray value.
+     * @param dataType
+     *            the data type.
+     * @param isSigned
+     *            a signed flag.
+     * @param isAlphaPremultiplied
+     *            the parameter indicates if color channel is pre-multiplied by
+     *            alpha, or not.
+     * @return the ImageTypeSpecifier.
+     */
+    public static ImageTypeSpecifier createGrayscale(int bits, int dataType, boolean isSigned,
+            boolean isAlphaPremultiplied) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Creates a ImageTypeSpecifier with the indexed image format.
+     * 
+     * @param redLUT
+     *            the red values of indices.
+     * @param greenLUT
+     *            the green values of indices.
+     * @param blueLUT
+     *            the blue values of indices.
+     * @param alphaLUT
+     *            the alpha values of indices.
+     * @param bits
+     *            the bits number for each index.
+     * @param dataType
+     *            the data type.
+     * @return the ImageTypeSpecifier.
+     */
+    public static ImageTypeSpecifier createIndexed(byte[] redLUT, byte[] greenLUT, byte[] blueLUT,
+            byte[] alphaLUT, int bits, int dataType) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Creates the ImageTypeSpecifier from the specified buffered image type.
+     * 
+     * @param bufferedImageType
+     *            the buffered image type.
+     * @return the ImageTypeSpecifier.
+     */
+    public static ImageTypeSpecifier createFromBufferedImageType(int bufferedImageType) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Creates the ImageTypeSpecifier from the specified RenderedImage.
+     * 
+     * @param image
+     *            the RenderedImage.
+     * @return the ImageTypeSpecifier.
+     */
+    public static ImageTypeSpecifier createFromRenderedImage(RenderedImage image) {
+        if (null == image) {
+            throw new IllegalArgumentException("image should not be NULL");
+        }
+        return new ImageTypeSpecifier(image);
+    }
+
+    /**
+     * Gets the BufferedImage type.
+     * 
+     * @return the BufferedImage type.
+     */
+    public int getBufferedImageType() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the number of components.
+     * 
+     * @return the number of components.
+     */
+    public int getNumComponents() {
+        return colorModel.getNumComponents();
+    }
+
+    /**
+     * Gets the number of bands.
+     * 
+     * @return the number of bands.
+     */
+    public int getNumBands() {
+        return sampleModel.getNumBands();
+    }
+
+    /**
+     * Gets the number of bits per the specified band.
+     * 
+     * @param band
+     *            the index of band.
+     * @return the number of bits per the specified band.
+     */
+    public int getBitsPerBand(int band) {
+        if (band < 0 || band >= getNumBands()) {
+            throw new IllegalArgumentException();
+        }
+        return sampleModel.getSampleSize(band);
+    }
+
+    /**
+     * Gets the SampleModel associated with this ImageTypeSpecifier.
+     * 
+     * @return the SampleModel associated with this ImageTypeSpecifier.
+     */
+    public SampleModel getSampleModel() {
+        return sampleModel;
+    }
+
+    /**
+     * Gets a compatible SampleModel with the specified width and height.
+     * 
+     * @param width
+     *            the width.
+     * @param height
+     *            the height.
+     * @return the SampleModel.
+     */
+    public SampleModel getSampleModel(int width, int height) {
+        if ((long)width * height > Integer.MAX_VALUE) {
+            throw new IllegalArgumentException("width * height > Integer.MAX_VALUE");
+        }
+        return sampleModel.createCompatibleSampleModel(width, height);
+    }
+
+    /**
+     * Gets the ColorModel associated with this ImageTypeSpecifier.
+     * 
+     * @return the ColorModel associated with this ImageTypeSpecifier.
+     */
+    public ColorModel getColorModel() {
+        return colorModel;
+    }
+
+    /**
+     * Creates the BufferedImage with the specified width and height and the
+     * ColorMadel and SampleModel which are specified by this
+     * ImageTypeSpecifier.
+     * 
+     * @param width
+     *            the width of the BufferedImage.
+     * @param height
+     *            the height of the BufferedImage.
+     * @return the BufferedImage.
+     */
+    public BufferedImage createBufferedImage(int width, int height) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Compares this ImageTypeSpecifier object with the specified object.
+     * 
+     * @param o
+     *            the Object to be compared.
+     * @return true, if the object is an ImageTypeSpecifier with the same data
+     *         as this ImageTypeSpecifier, false otherwise.
+     */
+    @Override
+    public boolean equals(Object o) {
+        boolean rt = false;
+        if (o instanceof ImageTypeSpecifier) {
+            ImageTypeSpecifier ts = (ImageTypeSpecifier)o;
+            rt = colorModel.equals(ts.colorModel) && sampleModel.equals(ts.sampleModel);
+        }
+        return rt;
+    }
+}
\ No newline at end of file
diff --git a/awt/javax/imageio/ImageWriteParam.java b/awt/javax/imageio/ImageWriteParam.java
new file mode 100644
index 0000000..d661889
--- /dev/null
+++ b/awt/javax/imageio/ImageWriteParam.java
@@ -0,0 +1,664 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio;
+
+import java.util.Locale;
+import java.awt.*;
+
+/**
+ * The ImageWriteParam class provides information to an ImageWriter about how an
+ * image is to be encoded.
+ * 
+ * @since Android 1.0
+ */
+public class ImageWriteParam extends IIOParam {
+
+    /**
+     * The Constant MODE_DISABLED indicates that stream is not tiled,
+     * progressive, or compressed.
+     */
+    public static final int MODE_DISABLED = 0;
+
+    /**
+     * The Constant MODE_DEFAULT indicates that the stream will be tiled,
+     * progressive, or compressed according to the plug-in's default.
+     */
+    public static final int MODE_DEFAULT = 1;
+
+    /**
+     * The Constant MODE_EXPLICIT indicates that the stream will be tiled,
+     * progressive, or compressed according to current settings which are
+     * defined by set methods.
+     */
+    public static final int MODE_EXPLICIT = 2;
+
+    /**
+     * The Constant MODE_COPY_FROM_METADATA indicates that the stream will be
+     * tiled, progressive, or compressed according to stream or image metadata.
+     */
+    public static final int MODE_COPY_FROM_METADATA = 3;
+
+    /**
+     * Whether the ImageWriter can write tiles.
+     */
+    protected boolean canWriteTiles = false;
+
+    /**
+     * The tiling mode.
+     */
+    protected int tilingMode = MODE_COPY_FROM_METADATA;
+
+    /**
+     * The preferred tile sizes.
+     */
+    protected Dimension[] preferredTileSizes = null;
+
+    /**
+     * The tiling set.
+     */
+    protected boolean tilingSet = false;
+
+    /**
+     * The tile width.
+     */
+    protected int tileWidth = 0;
+
+    /**
+     * The tile height.
+     */
+    protected int tileHeight = 0;
+
+    /**
+     * Whether the ImageWriter can offset tiles.
+     */
+    protected boolean canOffsetTiles = false;
+
+    /**
+     * The tile grid x offset.
+     */
+    protected int tileGridXOffset = 0;
+
+    /**
+     * The tile grid y offset.
+     */
+    protected int tileGridYOffset = 0;
+
+    /**
+     * Whether the ImageWriter can write in progressive mode.
+     */
+    protected boolean canWriteProgressive = false;
+
+    /**
+     * The progressive mode.
+     */
+    protected int progressiveMode = MODE_COPY_FROM_METADATA;
+
+    /**
+     * Whether the ImageWriter can write in compressed mode.
+     */
+    protected boolean canWriteCompressed = false;
+
+    /**
+     * The compression mode.
+     */
+    protected int compressionMode = MODE_COPY_FROM_METADATA;
+
+    /**
+     * The compression types.
+     */
+    protected String[] compressionTypes = null;
+
+    /**
+     * The compression type.
+     */
+    protected String compressionType = null;
+
+    /**
+     * The compression quality.
+     */
+    protected float compressionQuality = 1.0f;
+
+    /**
+     * The locale.
+     */
+    protected Locale locale = null;
+
+    /**
+     * Instantiates a new ImageWriteParam.
+     */
+    protected ImageWriteParam() {
+    }
+
+    /**
+     * Instantiates a new ImageWriteParam with the specified Locale.
+     * 
+     * @param locale
+     *            the Locale.
+     */
+    public ImageWriteParam(Locale locale) {
+        this.locale = locale;
+
+    }
+
+    /**
+     * Gets the mode for writing the stream in a progressive sequence.
+     * 
+     * @return the current progressive mode.
+     */
+    public int getProgressiveMode() {
+        if (canWriteProgressive()) {
+            return progressiveMode;
+        }
+        throw new UnsupportedOperationException("progressive mode is not supported");
+    }
+
+    /**
+     * Returns true if images can be written using increasing quality passes by
+     * progressive.
+     * 
+     * @return true if images can be written using increasing quality passes by
+     *         progressive, false otherwise.
+     */
+    public boolean canWriteProgressive() {
+        return canWriteProgressive;
+    }
+
+    /**
+     * Sets the progressive mode which defines whether the stream contains a
+     * progressive sequence of increasing quality during writing. The
+     * progressive mode should be one of the following values: MODE_DISABLED,
+     * MODE_DEFAULT, or MODE_COPY_FROM_METADATA.
+     * 
+     * @param mode
+     *            the new progressive mode.
+     */
+    public void setProgressiveMode(int mode) {
+        if (canWriteProgressive()) {
+            if (mode < MODE_DISABLED || mode > MODE_COPY_FROM_METADATA || mode == MODE_EXPLICIT) {
+                throw new IllegalArgumentException("mode is not supported");
+            }
+            this.progressiveMode = mode;
+        }
+        throw new UnsupportedOperationException("progressive mode is not supported");
+    }
+
+    /**
+     * Returns true if the writer can use tiles with non zero grid offsets while
+     * writing.
+     * 
+     * @return true, if the writer can use tiles with non zero grid offsets
+     *         while writing, false otherwise.
+     */
+    public boolean canOffsetTiles() {
+        return canOffsetTiles;
+    }
+
+    /**
+     * Returns true if this writer can write images with compression.
+     * 
+     * @return true, if this writer can write images with compression, false
+     *         otherwise.
+     */
+    public boolean canWriteCompressed() {
+        return canWriteCompressed;
+    }
+
+    /**
+     * Returns true if the writer can write tiles.
+     * 
+     * @return true, if the writer can write tiles, false otherwise.
+     */
+    public boolean canWriteTiles() {
+        return canWriteTiles;
+    }
+
+    /**
+     * Check write compressed.
+     */
+    private final void checkWriteCompressed() {
+        if (!canWriteCompressed()) {
+            throw new UnsupportedOperationException("Compression not supported.");
+        }
+    }
+
+    /**
+     * Check compression mode.
+     */
+    private final void checkCompressionMode() {
+        if (getCompressionMode() != MODE_EXPLICIT) {
+            throw new IllegalStateException("Compression mode not MODE_EXPLICIT!");
+        }
+    }
+
+    /**
+     * Check compression type.
+     */
+    private final void checkCompressionType() {
+        if (getCompressionTypes() != null && getCompressionType() == null) {
+            throw new IllegalStateException("No compression type set!");
+        }
+    }
+
+    /**
+     * Gets the compression mode.
+     * 
+     * @return the compression mode if it's supported.
+     */
+    public int getCompressionMode() {
+        checkWriteCompressed();
+        return compressionMode;
+    }
+
+    /**
+     * Gets the an array of supported compression types.
+     * 
+     * @return the an array of supported compression types.
+     */
+    public String[] getCompressionTypes() {
+        checkWriteCompressed();
+        if (compressionTypes != null) {
+            return compressionTypes.clone();
+        }
+        return null;
+    }
+
+    /**
+     * Gets the current compression type, or returns null.
+     * 
+     * @return the current compression type, or returns null if it is not set.
+     */
+    public String getCompressionType() {
+        checkWriteCompressed();
+        checkCompressionMode();
+        return compressionType;
+    }
+
+    /**
+     * Gets a bit rate which represents an estimate of the number of bits of
+     * output data for each bit of input image data with the specified quality.
+     * 
+     * @param quality
+     *            the quality.
+     * @return an estimate of the bit rate, or -1.0F if there is no estimate.
+     */
+    public float getBitRate(float quality) {
+        checkWriteCompressed();
+        checkCompressionMode();
+        checkCompressionType();
+        if (quality < 0 || quality > 1) {
+            throw new IllegalArgumentException("Quality out-of-bounds!");
+        }
+        return -1.0f;
+    }
+
+    /**
+     * Gets the compression quality.
+     * 
+     * @return the compression quality.
+     */
+    public float getCompressionQuality() {
+        checkWriteCompressed();
+        checkCompressionMode();
+        checkCompressionType();
+        return compressionQuality;
+    }
+
+    /**
+     * Gets the array of compression quality descriptions.
+     * 
+     * @return the string array of compression quality descriptions.
+     */
+    public String[] getCompressionQualityDescriptions() {
+        checkWriteCompressed();
+        checkCompressionMode();
+        checkCompressionType();
+        return null;
+    }
+
+    /**
+     * Gets an array of floats which describes compression quality levels.
+     * 
+     * @return the array of compression quality values.
+     */
+    public float[] getCompressionQualityValues() {
+        checkWriteCompressed();
+        checkCompressionMode();
+        checkCompressionType();
+        return null;
+    }
+
+    /**
+     * Gets the locale of this ImageWriteParam.
+     * 
+     * @return the locale of this ImageWriteParam.
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+    /**
+     * Gets the current compression type using the current Locale.
+     * 
+     * @return the current compression type using the current Locale.
+     */
+    public String getLocalizedCompressionTypeName() {
+        checkWriteCompressed();
+        checkCompressionMode();
+
+        String compressionType = getCompressionType();
+        if (compressionType == null) {
+            throw new IllegalStateException("No compression type set!");
+        }
+        return compressionType;
+
+    }
+
+    /**
+     * Check tiling.
+     */
+    private final void checkTiling() {
+        if (!canWriteTiles()) {
+            throw new UnsupportedOperationException("Tiling not supported!");
+        }
+    }
+
+    /**
+     * Check tiling mode.
+     */
+    private final void checkTilingMode() {
+        if (getTilingMode() != MODE_EXPLICIT) {
+            throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
+        }
+    }
+
+    /**
+     * Check tiling params.
+     */
+    private final void checkTilingParams() {
+        if (!tilingSet) {
+            throw new IllegalStateException("Tiling parameters not set!");
+        }
+    }
+
+    /**
+     * Gets the tiling mode if tiling is supported.
+     * 
+     * @return the tiling mode if tiling is supported.
+     */
+    public int getTilingMode() {
+        checkTiling();
+        return tilingMode;
+    }
+
+    /**
+     * Gets an array of Dimensions giving the sizes of the tiles as they are
+     * encoded in the output file or stream.
+     * 
+     * @return the preferred tile sizes.
+     */
+    public Dimension[] getPreferredTileSizes() {
+        checkTiling();
+        if (preferredTileSizes == null) {
+            return null;
+        }
+
+        Dimension[] retval = new Dimension[preferredTileSizes.length];
+        for (int i = 0; i < preferredTileSizes.length; i++) {
+            retval[i] = new Dimension(retval[i]);
+        }
+        return retval;
+    }
+
+    /**
+     * Gets the tile grid X offset for encoding.
+     * 
+     * @return the tile grid X offset for encoding.
+     */
+    public int getTileGridXOffset() {
+        checkTiling();
+        checkTilingMode();
+        checkTilingParams();
+        return tileGridXOffset;
+    }
+
+    /**
+     * Gets the tile grid Y offset for encoding.
+     * 
+     * @return the tile grid Y offset for encoding.
+     */
+    public int getTileGridYOffset() {
+        checkTiling();
+        checkTilingMode();
+        checkTilingParams();
+        return tileGridYOffset;
+    }
+
+    /**
+     * Gets the tile height in an image as it is written to the output stream.
+     * 
+     * @return the tile height in an image as it is written to the output
+     *         stream.
+     */
+    public int getTileHeight() {
+        checkTiling();
+        checkTilingMode();
+        checkTilingParams();
+        return tileHeight;
+    }
+
+    /**
+     * Gets the tile width in an image as it is written to the output stream.
+     * 
+     * @return the tile width in an image as it is written to the output stream.
+     */
+    public int getTileWidth() {
+        checkTiling();
+        checkTilingMode();
+        checkTilingParams();
+        return tileWidth;
+    }
+
+    /**
+     * Checks if the current compression type has lossless compression or not.
+     * 
+     * @return true, if the current compression type has lossless compression,
+     *         false otherwise.
+     */
+    public boolean isCompressionLossless() {
+        checkWriteCompressed();
+        checkCompressionMode();
+        checkCompressionType();
+        return true;
+    }
+
+    /**
+     * Removes current compression type.
+     */
+    public void unsetCompression() {
+        checkWriteCompressed();
+        checkCompressionMode();
+        compressionType = null;
+        compressionQuality = 1;
+    }
+
+    /**
+     * Sets the compression mode to the specified value. The specified mode can
+     * be one of the predefined constants: MODE_DEFAULT, MODE_DISABLED,
+     * MODE_EXPLICIT, or MODE_COPY_FROM_METADATA.
+     * 
+     * @param mode
+     *            the new compression mode to be set.
+     */
+    public void setCompressionMode(int mode) {
+        checkWriteCompressed();
+        switch (mode) {
+            case MODE_EXPLICIT: {
+                compressionMode = mode;
+                unsetCompression();
+                break;
+            }
+            case MODE_COPY_FROM_METADATA:
+            case MODE_DISABLED:
+            case MODE_DEFAULT: {
+                compressionMode = mode;
+                break;
+            }
+            default: {
+                throw new IllegalArgumentException("Illegal value for mode!");
+            }
+        }
+    }
+
+    /**
+     * Sets the compression quality. The value should be between 0 and 1.
+     * 
+     * @param quality
+     *            the new compression quality, float value between 0 and 1.
+     */
+    public void setCompressionQuality(float quality) {
+        checkWriteCompressed();
+        checkCompressionMode();
+        checkCompressionType();
+        if (quality < 0 || quality > 1) {
+            throw new IllegalArgumentException("Quality out-of-bounds!");
+        }
+        compressionQuality = quality;
+    }
+
+    /**
+     * Sets the compression type. The specified string should be one of the
+     * values returned by getCompressionTypes method.
+     * 
+     * @param compressionType
+     *            the new compression type.
+     */
+    public void setCompressionType(String compressionType) {
+        checkWriteCompressed();
+        checkCompressionMode();
+
+        if (compressionType == null) { // Don't check anything
+            this.compressionType = null;
+        } else {
+            String[] compressionTypes = getCompressionTypes();
+            if (compressionTypes == null) {
+                throw new UnsupportedOperationException("No settable compression types");
+            }
+
+            for (int i = 0; i < compressionTypes.length; i++) {
+                if (compressionTypes[i].equals(compressionType)) {
+                    this.compressionType = compressionType;
+                    return;
+                }
+            }
+
+            // Compression type is not in the list.
+            throw new IllegalArgumentException("Unknown compression type!");
+        }
+    }
+
+    /**
+     * Sets the instruction that tiling should be performed for the image in the
+     * output stream with the specified parameters.
+     * 
+     * @param tileWidth
+     *            the tile's width.
+     * @param tileHeight
+     *            the tile's height.
+     * @param tileGridXOffset
+     *            the tile grid's x offset.
+     * @param tileGridYOffset
+     *            the tile grid's y offset.
+     */
+    public void setTiling(int tileWidth, int tileHeight, int tileGridXOffset, int tileGridYOffset) {
+        checkTiling();
+        checkTilingMode();
+
+        if (!canOffsetTiles() && (tileGridXOffset != 0 || tileGridYOffset != 0)) {
+            throw new UnsupportedOperationException("Can't offset tiles!");
+        }
+
+        if (tileWidth <= 0 || tileHeight <= 0) {
+            throw new IllegalArgumentException("tile dimensions are non-positive!");
+        }
+
+        Dimension preferredTileSizes[] = getPreferredTileSizes();
+        if (preferredTileSizes != null) {
+            for (int i = 0; i < preferredTileSizes.length; i += 2) {
+                Dimension minSize = preferredTileSizes[i];
+                Dimension maxSize = preferredTileSizes[i + 1];
+                if (tileWidth < minSize.width || tileWidth > maxSize.width
+                        || tileHeight < minSize.height || tileHeight > maxSize.height) {
+                    throw new IllegalArgumentException("Illegal tile size!");
+                }
+            }
+        }
+
+        tilingSet = true;
+        this.tileWidth = tileWidth;
+        this.tileHeight = tileHeight;
+        this.tileGridXOffset = tileGridXOffset;
+        this.tileGridYOffset = tileGridYOffset;
+    }
+
+    /**
+     * Clears all tiling settings.
+     */
+    public void unsetTiling() {
+        checkTiling();
+        checkTilingMode();
+
+        tilingSet = false;
+        tileWidth = 0;
+        tileHeight = 0;
+        tileGridXOffset = 0;
+        tileGridYOffset = 0;
+    }
+
+    /**
+     * Sets the tiling mode. The specified mode should be one of the following
+     * values: MODE_DISABLED, MODE_DEFAULT, MODE_EXPLICIT, or
+     * MODE_COPY_FROM_METADATA.
+     * 
+     * @param mode
+     *            the new tiling mode.
+     */
+    public void setTilingMode(int mode) {
+        checkTiling();
+
+        switch (mode) {
+            case MODE_EXPLICIT: {
+                tilingMode = mode;
+                unsetTiling();
+                break;
+            }
+            case MODE_COPY_FROM_METADATA:
+            case MODE_DISABLED:
+            case MODE_DEFAULT: {
+                tilingMode = mode;
+                break;
+            }
+            default: {
+                throw new IllegalArgumentException("Illegal value for mode!");
+            }
+        }
+    }
+}
diff --git a/awt/javax/imageio/ImageWriter.java b/awt/javax/imageio/ImageWriter.java
new file mode 100644
index 0000000..86879e0
--- /dev/null
+++ b/awt/javax/imageio/ImageWriter.java
@@ -0,0 +1,1001 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.imageio.event.IIOWriteProgressListener;
+import javax.imageio.event.IIOWriteWarningListener;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.spi.ImageWriterSpi;
+
+/**
+ * The ImageWriter class is an abstract class for encoding images. ImageWriter
+ * objects are instantiated by the service provider interface, ImageWriterSpi
+ * class, for the specific format. ImageWriterSpi class should be registered
+ * with the IIORegistry, which uses them for format recognition and presentation
+ * of available format readers and writers.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ImageWriter implements ImageTranscoder {
+
+    /**
+     * The available locales.
+     */
+    protected Locale[] availableLocales;
+
+    /**
+     * The locale.
+     */
+    protected Locale locale;
+
+    /**
+     * The originating provider.
+     */
+    protected ImageWriterSpi originatingProvider;
+
+    /**
+     * The output.
+     */
+    protected Object output;
+
+    /**
+     * The progress listeners.
+     */
+    protected List<IIOWriteProgressListener> progressListeners;
+
+    /**
+     * The warning listeners.
+     */
+    protected List<IIOWriteWarningListener> warningListeners;
+
+    /**
+     * The warning locales.
+     */
+    protected List<Locale> warningLocales;
+
+    // Indicates that abort operation is requested
+    // Abort mechanism should be thread-safe
+    /** The aborted. */
+    private boolean aborted;
+
+    /**
+     * Instantiates a new ImageWriter.
+     * 
+     * @param originatingProvider
+     *            the ImageWriterSpi which instantiates this ImageWriter.
+     */
+    protected ImageWriter(ImageWriterSpi originatingProvider) {
+        this.originatingProvider = originatingProvider;
+    }
+
+    public abstract IIOMetadata convertStreamMetadata(IIOMetadata iioMetadata,
+            ImageWriteParam imageWriteParam);
+
+    public abstract IIOMetadata convertImageMetadata(IIOMetadata iioMetadata,
+            ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam);
+
+    /**
+     * Gets the ImageWriterSpi which instantiated this ImageWriter.
+     * 
+     * @return the ImageWriterSpi.
+     */
+    public ImageWriterSpi getOriginatingProvider() {
+        return originatingProvider;
+    }
+
+    /**
+     * Processes the start of an image read by calling their imageStarted method
+     * of registered IIOWriteProgressListeners.
+     * 
+     * @param imageIndex
+     *            the image index.
+     */
+    protected void processImageStarted(int imageIndex) {
+        if (null != progressListeners) {
+            for (IIOWriteProgressListener listener : progressListeners) {
+                listener.imageStarted(this, imageIndex);
+            }
+        }
+    }
+
+    /**
+     * Processes the current percentage of image completion by calling
+     * imageProgress method of registered IIOWriteProgressListener.
+     * 
+     * @param percentageDone
+     *            the percentage done.
+     */
+    protected void processImageProgress(float percentageDone) {
+        if (null != progressListeners) {
+            for (IIOWriteProgressListener listener : progressListeners) {
+                listener.imageProgress(this, percentageDone);
+            }
+        }
+    }
+
+    /**
+     * Processes image completion by calling imageComplete method of registered
+     * IIOWriteProgressListeners.
+     */
+    protected void processImageComplete() {
+        if (null != progressListeners) {
+            for (IIOWriteProgressListener listener : progressListeners) {
+                listener.imageComplete(this);
+            }
+        }
+    }
+
+    /**
+     * Processes a warning message by calling warningOccurred method of
+     * registered IIOWriteWarningListeners.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param warning
+     *            the warning.
+     */
+    protected void processWarningOccurred(int imageIndex, String warning) {
+        if (null == warning) {
+            throw new NullPointerException("warning message should not be NULL");
+        }
+        if (null != warningListeners) {
+            for (IIOWriteWarningListener listener : warningListeners) {
+                listener.warningOccurred(this, imageIndex, warning);
+            }
+        }
+    }
+
+    /**
+     * Processes a warning message by calling warningOccurred method of
+     * registered IIOWriteWarningListeners with string from ResourceBundle.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param bundle
+     *            the name of ResourceBundle.
+     * @param key
+     *            the keyword.
+     */
+    protected void processWarningOccurred(int imageIndex, String bundle, String key) {
+        if (warningListeners != null) { // Don't check the parameters
+            return;
+        }
+
+        if (bundle == null) {
+            throw new IllegalArgumentException("baseName == null!");
+        }
+        if (key == null) {
+            throw new IllegalArgumentException("keyword == null!");
+        }
+
+        // Get the context class loader and try to locate the bundle with it
+        // first
+        ClassLoader contextClassloader = AccessController
+                .doPrivileged(new PrivilegedAction<ClassLoader>() {
+                    public ClassLoader run() {
+                        return Thread.currentThread().getContextClassLoader();
+                    }
+                });
+
+        // Iterate through both listeners and locales
+        int n = warningListeners.size();
+        for (int i = 0; i < n; i++) {
+            IIOWriteWarningListener listener = warningListeners.get(i);
+            Locale locale = warningLocales.get(i);
+
+            // Now try to get the resource bundle
+            ResourceBundle rb;
+            try {
+                rb = ResourceBundle.getBundle(bundle, locale, contextClassloader);
+            } catch (MissingResourceException e) {
+                try {
+                    rb = ResourceBundle.getBundle(bundle, locale);
+                } catch (MissingResourceException e1) {
+                    throw new IllegalArgumentException("Bundle not found!");
+                }
+            }
+
+            try {
+                String warning = rb.getString(key);
+                listener.warningOccurred(this, imageIndex, warning);
+            } catch (MissingResourceException e) {
+                throw new IllegalArgumentException("Resource is missing!");
+            } catch (ClassCastException e) {
+                throw new IllegalArgumentException("Resource is not a String!");
+            }
+        }
+    }
+
+    /**
+     * Sets the specified Object to the output of this ImageWriter.
+     * 
+     * @param output
+     *            the Object which represents destination, it can be
+     *            ImageOutputStream or other objects.
+     */
+    public void setOutput(Object output) {
+        if (output != null) {
+            ImageWriterSpi spi = getOriginatingProvider();
+            if (null != spi) {
+                Class[] outTypes = spi.getOutputTypes();
+                boolean supported = false;
+                for (Class<?> element : outTypes) {
+                    if (element.isInstance(output)) {
+                        supported = true;
+                        break;
+                    }
+                }
+                if (!supported) {
+                    throw new IllegalArgumentException("output " + output + " is not supported");
+                }
+            }
+        }
+        this.output = output;
+    }
+
+    /**
+     * Writes a completed image stream that contains the specified image,
+     * default metadata, and thumbnails to the output.
+     * 
+     * @param image
+     *            the specified image to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred during writing.
+     */
+    public void write(IIOImage image) throws IOException {
+        write(null, image, null);
+    }
+
+    /**
+     * Writes a completed image stream that contains the specified rendered
+     * image, default metadata, and thumbnails to the output.
+     * 
+     * @param image
+     *            the specified RenderedImage to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred during writing.
+     */
+    public void write(RenderedImage image) throws IOException {
+        write(null, new IIOImage(image, null, null), null);
+    }
+
+    /**
+     * Writes a completed image stream that contains the specified image,
+     * metadata and thumbnails to the output.
+     * 
+     * @param streamMetadata
+     *            the stream metadata, or null.
+     * @param image
+     *            the specified image to be written, if canWriteRaster() method
+     *            returns false, then Image must contain only RenderedImage.
+     * @param param
+     *            the ImageWriteParam, or null.
+     * @throws IOException
+     *             if an error occurs during writing.
+     */
+    public abstract void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param)
+            throws IOException;
+
+    /**
+     * Disposes of any resources.
+     */
+    public void dispose() {
+        // def impl. does nothing according to the spec.
+    }
+
+    /**
+     * Requests an abort operation for current writing operation.
+     */
+    public synchronized void abort() {
+        aborted = true;
+    }
+
+    /**
+     * Checks whether or not a request to abort the current write operation has
+     * been made successfully.
+     * 
+     * @return true, if the request to abort the current write operation has
+     *         been made successfully, false otherwise.
+     */
+    protected synchronized boolean abortRequested() {
+        return aborted;
+    }
+
+    /**
+     * Clears all previous abort request, and abortRequested returns false after
+     * calling this method.
+     */
+    protected synchronized void clearAbortRequest() {
+        aborted = false;
+    }
+
+    /**
+     * Adds the IIOWriteProgressListener listener.
+     * 
+     * @param listener
+     *            the IIOWriteProgressListener listener.
+     */
+    public void addIIOWriteProgressListener(IIOWriteProgressListener listener) {
+        if (listener == null) {
+            return;
+        }
+
+        if (progressListeners == null) {
+            progressListeners = new ArrayList<IIOWriteProgressListener>();
+        }
+
+        progressListeners.add(listener);
+    }
+
+    /**
+     * Adds the IIOWriteWarningListener.
+     * 
+     * @param listener
+     *            the IIOWriteWarningListener listener.
+     */
+    public void addIIOWriteWarningListener(IIOWriteWarningListener listener) {
+        if (listener == null) {
+            return;
+        }
+
+        if (warningListeners == null) {
+            warningListeners = new ArrayList<IIOWriteWarningListener>();
+            warningLocales = new ArrayList<Locale>();
+        }
+
+        warningListeners.add(listener);
+        warningLocales.add(getLocale());
+    }
+
+    /**
+     * Gets the output object that was set by setOutput method.
+     * 
+     * @return the output object such as ImageOutputStream, or null if it is not
+     *         set.
+     */
+    public Object getOutput() {
+        return output;
+    }
+
+    /**
+     * Check output return false.
+     * 
+     * @return true, if successful.
+     */
+    private final boolean checkOutputReturnFalse() {
+        if (getOutput() == null) {
+            throw new IllegalStateException("getOutput() == null!");
+        }
+        return false;
+    }
+
+    /**
+     * Unsupported operation.
+     */
+    private final void unsupportedOperation() {
+        if (getOutput() == null) {
+            throw new IllegalStateException("getOutput() == null!");
+        }
+        throw new UnsupportedOperationException("Unsupported write variant!");
+    }
+
+    /**
+     * Returns true if a new empty image can be inserted at the specified index.
+     * 
+     * @param imageIndex
+     *            the specified index of image.
+     * @return true if a new empty image can be inserted at the specified index,
+     *         false otherwise.
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     */
+    public boolean canInsertEmpty(int imageIndex) throws IOException {
+        return checkOutputReturnFalse();
+    }
+
+    /**
+     * Returns true if a new image can be inserted at the specified index.
+     * 
+     * @param imageIndex
+     *            the specified index of image.
+     * @return true if a new image can be inserted at the specified index, false
+     *         otherwise.
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     */
+    public boolean canInsertImage(int imageIndex) throws IOException {
+        return checkOutputReturnFalse();
+    }
+
+    /**
+     * Returns true if the image with the specified index can be removed.
+     * 
+     * @param imageIndex
+     *            the specified index of image.
+     * @return true if the image with the specified index can be removed, false
+     *         otherwise.
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     */
+    public boolean canRemoveImage(int imageIndex) throws IOException {
+        return checkOutputReturnFalse();
+    }
+
+    /**
+     * Returns true if metadata of the image with the specified index can be
+     * replaced.
+     * 
+     * @param imageIndex
+     *            the specified image index.
+     * @return true if metadata of the image with the specified index can be
+     *         replaced, false otherwise.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public boolean canReplaceImageMetadata(int imageIndex) throws IOException {
+        return checkOutputReturnFalse();
+    }
+
+    /**
+     * Returns true if pixels of the image with the specified index can be
+     * replaced by the replacePixels methods.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @return true if pixels of the image with the specified index can be
+     *         replaced by the replacePixels methods, false otherwise.
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     */
+    public boolean canReplacePixels(int imageIndex) throws IOException {
+        return checkOutputReturnFalse();
+    }
+
+    /**
+     * Returns true if the stream metadata presented in the output can be
+     * removed.
+     * 
+     * @return true if the stream metadata presented in the output can be
+     *         removed, false otherwise.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public boolean canReplaceStreamMetadata() throws IOException {
+        return checkOutputReturnFalse();
+    }
+
+    /**
+     * Returns true if the writing of a complete image stream which contains a
+     * single image is supported with undefined pixel values and associated
+     * metadata and thumbnails to the output.
+     * 
+     * @return true if the writing of a complete image stream which contains a
+     *         single image is supported, false otherwise.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public boolean canWriteEmpty() throws IOException {
+        return checkOutputReturnFalse();
+    }
+
+    /**
+     * Returns true if the methods which taken an IIOImageParameter can deal
+     * with a Raster source image.
+     * 
+     * @return true if the methods which taken an IIOImageParameter can deal
+     *         with a Raster source image, false otherwise.
+     */
+    public boolean canWriteRasters() {
+        return false;
+    }
+
+    /**
+     * Returns true if the writer can add an image to stream that already
+     * contains header information.
+     * 
+     * @return if the writer can add an image to stream that already contains
+     *         header information, false otherwise.
+     */
+    public boolean canWriteSequence() {
+        return false;
+    }
+
+    /**
+     * Ends the insertion of a new image.
+     * 
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void endInsertEmpty() throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Ends the replace pixels operation.
+     * 
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void endReplacePixels() throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Ends an empty write operation.
+     * 
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void endWriteEmpty() throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Ends the sequence of write operations.
+     * 
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void endWriteSequence() throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Gets an array of available locales.
+     * 
+     * @return an of array available locales.
+     */
+    public Locale[] getAvailableLocales() {
+        if (availableLocales == null) {
+            return null;
+        }
+
+        return availableLocales.clone();
+    }
+
+    /**
+     * Gets an IIOMetadata object that contains default values for encoding an
+     * image with the specified type.
+     * 
+     * @param imageType
+     *            the ImageTypeSpecifier.
+     * @param param
+     *            the ImageWriteParam.
+     * @return the IIOMetadata object.
+     */
+    public abstract IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType,
+            ImageWriteParam param);
+
+    /**
+     * Gets an IIOMetadata object that contains default values for encoding a
+     * stream of images.
+     * 
+     * @param param
+     *            the ImageWriteParam.
+     * @return the IIOMetadata object.
+     */
+    public abstract IIOMetadata getDefaultStreamMetadata(ImageWriteParam param);
+
+    /**
+     * Gets the current locale of this ImageWriter.
+     * 
+     * @return the current locale of this ImageWriter.
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+    /**
+     * Gets the default write param. Gets a new ImageWriteParam object for this
+     * ImageWriter with the current Locale.
+     * 
+     * @return a new ImageWriteParam object for this ImageWriter.
+     */
+    public ImageWriteParam getDefaultWriteParam() {
+        return new ImageWriteParam(getLocale());
+    }
+
+    /**
+     * Gets the number of thumbnails supported by the format being written with
+     * supported image type, image write parameters, stream, and image metadata
+     * objects.
+     * 
+     * @param imageType
+     *            the ImageTypeSpecifier.
+     * @param param
+     *            the image's parameters.
+     * @param streamMetadata
+     *            the stream metadata.
+     * @param imageMetadata
+     *            the image metadata.
+     * @return the number of thumbnails supported.
+     */
+    public int getNumThumbnailsSupported(ImageTypeSpecifier imageType, ImageWriteParam param,
+            IIOMetadata streamMetadata, IIOMetadata imageMetadata) {
+        return 0;
+    }
+
+    /**
+     * Gets the preferred thumbnail sizes. Gets an array of Dimensions with the
+     * sizes for thumbnail images as they are encoded in the output file or
+     * stream.
+     * 
+     * @param imageType
+     *            the ImageTypeSpecifier.
+     * @param param
+     *            the ImageWriteParam.
+     * @param streamMetadata
+     *            the stream metadata.
+     * @param imageMetadata
+     *            the image metadata.
+     * @return the preferred thumbnail sizes.
+     */
+    public Dimension[] getPreferredThumbnailSizes(ImageTypeSpecifier imageType,
+            ImageWriteParam param, IIOMetadata streamMetadata, IIOMetadata imageMetadata) {
+        return null;
+    }
+
+    /**
+     * Prepares insertion of an empty image by requesting the insertion of a new
+     * image into an existing image stream.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param imageType
+     *            the image type.
+     * @param width
+     *            the width of the image.
+     * @param height
+     *            the height of the image.
+     * @param imageMetadata
+     *            the image metadata, or null.
+     * @param thumbnails
+     *            the array thumbnails for this image, or null.
+     * @param param
+     *            the ImageWriteParam, or null.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void prepareInsertEmpty(int imageIndex, ImageTypeSpecifier imageType, int width,
+            int height, IIOMetadata imageMetadata, List<? extends BufferedImage> thumbnails,
+            ImageWriteParam param) throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Prepares the writer to call the replacePixels method for the specified
+     * region.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @param region
+     *            the specified region.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void prepareReplacePixels(int imageIndex, Rectangle region) throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Prepares the writer for writing an empty image by beginning the process
+     * of writing a complete image stream that contains a single image with
+     * undefined pixel values, metadata and thumbnails, to the output.
+     * 
+     * @param streamMetadata
+     *            the stream metadata.
+     * @param imageType
+     *            the image type.
+     * @param width
+     *            the width of the image.
+     * @param height
+     *            the height of the image.
+     * @param imageMetadata
+     *            the image's metadata, or null.
+     * @param thumbnails
+     *            the image's thumbnails, or null.
+     * @param param
+     *            the image's parameters, or null.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void prepareWriteEmpty(IIOMetadata streamMetadata, ImageTypeSpecifier imageType,
+            int width, int height, IIOMetadata imageMetadata,
+            List<? extends BufferedImage> thumbnails, ImageWriteParam param) throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Prepares a stream to accept calls of writeToSequence method using the
+     * metadata object.
+     * 
+     * @param streamMetadata
+     *            the stream metadata.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void prepareWriteSequence(IIOMetadata streamMetadata) throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Processes the completion of a thumbnail read by calling their
+     * thumbnailComplete method of registered IIOWriteProgressListeners.
+     */
+    protected void processThumbnailComplete() {
+        if (progressListeners != null) {
+            for (IIOWriteProgressListener listener : progressListeners) {
+                listener.thumbnailComplete(this);
+            }
+        }
+    }
+
+    /**
+     * Processes the current percentage of thumbnail completion by calling their
+     * thumbnailProgress method of registered IIOWriteProgressListeners.
+     * 
+     * @param percentageDone
+     *            the percentage done.
+     */
+    protected void processThumbnailProgress(float percentageDone) {
+        if (progressListeners != null) {
+            for (IIOWriteProgressListener listener : progressListeners) {
+                listener.thumbnailProgress(this, percentageDone);
+            }
+        }
+    }
+
+    /**
+     * Processes the start of a thumbnail read by calling thumbnailStarted
+     * method of registered IIOWriteProgressListeners.
+     * 
+     * @param imageIndex
+     *            the image index.
+     * @param thumbnailIndex
+     *            the thumbnail index.
+     */
+    protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) {
+        if (progressListeners != null) {
+            for (IIOWriteProgressListener listener : progressListeners) {
+                listener.thumbnailStarted(this, imageIndex, thumbnailIndex);
+            }
+        }
+    }
+
+    /**
+     * Processes that the writing has been aborted by calling writeAborted
+     * method of registered IIOWriteProgressListeners.
+     */
+    protected void processWriteAborted() {
+        if (progressListeners != null) {
+            for (IIOWriteProgressListener listener : progressListeners) {
+                listener.writeAborted(this);
+            }
+        }
+    }
+
+    /**
+     * Removes the all IIOWriteProgressListener listeners.
+     */
+    public void removeAllIIOWriteProgressListeners() {
+        progressListeners = null;
+    }
+
+    /**
+     * Removes the all IIOWriteWarningListener listeners.
+     */
+    public void removeAllIIOWriteWarningListeners() {
+        warningListeners = null;
+        warningLocales = null;
+    }
+
+    /**
+     * Removes the specified IIOWriteProgressListener listener.
+     * 
+     * @param listener
+     *            the registered IIOWriteProgressListener to be removed.
+     */
+    public void removeIIOWriteProgressListener(IIOWriteProgressListener listener) {
+        if (progressListeners != null && listener != null) {
+            if (progressListeners.remove(listener) && progressListeners.isEmpty()) {
+                progressListeners = null;
+            }
+        }
+    }
+
+    /**
+     * Removes the specified IIOWriteWarningListener listener.
+     * 
+     * @param listener
+     *            the registered IIOWriteWarningListener listener to be removed.
+     */
+    public void removeIIOWriteWarningListener(IIOWriteWarningListener listener) {
+        if (warningListeners == null || listener == null) {
+            return;
+        }
+
+        int idx = warningListeners.indexOf(listener);
+        if (idx > -1) {
+            warningListeners.remove(idx);
+            warningLocales.remove(idx);
+
+            if (warningListeners.isEmpty()) {
+                warningListeners = null;
+                warningLocales = null;
+            }
+        }
+    }
+
+    /**
+     * Removes the image with the specified index from the stream.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void removeImage(int imageIndex) throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Replaces image metadata of the image with specified index.
+     * 
+     * @param imageIndex
+     *            the image's index.
+     * @param imageMetadata
+     *            the image metadata.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void replaceImageMetadata(int imageIndex, IIOMetadata imageMetadata) throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Replaces a part of an image presented in the output with the specified
+     * RenderedImage.
+     * 
+     * @param image
+     *            the RenderedImage.
+     * @param param
+     *            the ImageWriteParam.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void replacePixels(RenderedImage image, ImageWriteParam param) throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Replaces a part of an image presented in the output with the specified
+     * Raster.
+     * 
+     * @param raster
+     *            the Raster.
+     * @param param
+     *            the ImageWriteParam.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void replacePixels(Raster raster, ImageWriteParam param) throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Replaces the stream metadata of the output with new IIOMetadata.
+     * 
+     * @param streamMetadata
+     *            the new stream metadata.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void replaceStreamMetadata(IIOMetadata streamMetadata) throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Sets the locale of this ImageWriter.
+     * 
+     * @param locale
+     *            the new locale.
+     */
+    public void setLocale(Locale locale) {
+        if (locale == null) {
+            this.locale = null;
+            return;
+        }
+
+        Locale[] locales = getAvailableLocales();
+        boolean validLocale = false;
+        if (locales != null) {
+            for (int i = 0; i < locales.length; i++) {
+                if (locale.equals(locales[i])) {
+                    validLocale = true;
+                    break;
+                }
+            }
+        }
+
+        if (validLocale) {
+            this.locale = locale;
+        } else {
+            throw new IllegalArgumentException("Invalid locale!");
+        }
+    }
+
+    /**
+     * Resets this ImageWriter.
+     */
+    public void reset() {
+        setOutput(null);
+        setLocale(null);
+        removeAllIIOWriteWarningListeners();
+        removeAllIIOWriteProgressListeners();
+        clearAbortRequest();
+    }
+
+    /**
+     * Inserts image into existing output stream.
+     * 
+     * @param imageIndex
+     *            the image index where an image will be written.
+     * @param image
+     *            the specified image to be written.
+     * @param param
+     *            the ImageWriteParam, or null.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public void writeInsert(int imageIndex, IIOImage image, ImageWriteParam param)
+            throws IOException {
+        unsupportedOperation();
+    }
+
+    /**
+     * Writes the specified image to the sequence.
+     * 
+     * @param image
+     *            the image to be written.
+     * @param param
+     *            the ImageWriteParam, or null.
+     * @throws IOException
+     *             if an I/O exception has occurred during writing.
+     */
+    public void writeToSequence(IIOImage image, ImageWriteParam param) throws IOException {
+        unsupportedOperation();
+    }
+}
diff --git a/awt/javax/imageio/event/IIOReadProgressListener.java b/awt/javax/imageio/event/IIOReadProgressListener.java
new file mode 100644
index 0000000..2944896
--- /dev/null
+++ b/awt/javax/imageio/event/IIOReadProgressListener.java
@@ -0,0 +1,121 @@
+/*
+ *  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.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+package javax.imageio.event;
+
+import java.util.EventListener;
+import javax.imageio.ImageReader;
+
+/**
+ * The IIOReadProgressListener interface notifies callers about the progress of
+ * the image and thumbnail reading methods.
+ * 
+ * @since Android 1.0
+ */
+public interface IIOReadProgressListener extends EventListener {
+
+    /**
+     * Notifies this listener that the image reading has been completed.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     */
+    void imageComplete(ImageReader source);
+
+    /**
+     * Notifies this listener about the degree of completion of the read call.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     * @param percentageDone
+     *            the percentage of decoding done.
+     */
+    void imageProgress(ImageReader source, float percentageDone);
+
+    /**
+     * Notifies this listener that an image read operation has been started.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     * @param imageIndex
+     *            the index of the image in an input file or stream to be read.
+     */
+    void imageStarted(ImageReader source, int imageIndex);
+
+    /**
+     * Notifies this listener that a read operation has been aborted.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     */
+    void readAborted(ImageReader source);
+
+    /**
+     * Notifies this listener that a sequence of read operations has been
+     * completed.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     */
+    void sequenceComplete(ImageReader source);
+
+    /**
+     * Notifies this listener that a sequence of read operation has been
+     * started.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     * @param minIndex
+     *            the index of the first image to be read.
+     */
+    void sequenceStarted(ImageReader source, int minIndex);
+
+    /**
+     * Notifies that a thumbnail read operation has been completed.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     */
+    void thumbnailComplete(ImageReader source);
+
+    /**
+     * Notifies this listener about the degree of completion of the read call.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     * @param percentageDone
+     *            the percentage of decoding done.
+     */
+    void thumbnailProgress(ImageReader source, float percentageDone);
+
+    /**
+     * Notifies this listener that a thumbnail reading operation has been
+     * started.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     * @param imageIndex
+     *            the index of the image in an input file or stream to be read.
+     * @param thumbnailIndex
+     *            the index of the thumbnail to be read.
+     */
+    void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex);
+}
diff --git a/awt/javax/imageio/event/IIOReadUpdateListener.java b/awt/javax/imageio/event/IIOReadUpdateListener.java
new file mode 100644
index 0000000..49bdbcb
--- /dev/null
+++ b/awt/javax/imageio/event/IIOReadUpdateListener.java
@@ -0,0 +1,182 @@
+/*
+ *  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.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+package javax.imageio.event;
+
+import java.awt.image.BufferedImage;
+import java.util.EventListener;
+import javax.imageio.ImageReader;
+
+/*
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The IIOReadUpdateListener interface provides functionality to receive
+ * notification of pixel updates during image and thumbnail reading operations.
+ * 
+ * @since Android 1.0
+ */
+public interface IIOReadUpdateListener extends EventListener {
+
+    /**
+     * Notifies this listener that the specified area of the image has been
+     * updated.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     * @param theImage
+     *            the image to be updated.
+     * @param minX
+     *            the minimum X coordinate of the pixels in the updated area.
+     * @param minY
+     *            the minimum Y coordinate of the pixels in the updated area.
+     * @param width
+     *            the width of updated area.
+     * @param height
+     *            the height of updated area.
+     * @param periodX
+     *            the horizontal spacing period between updated pixels, if it
+     *            equals 1, there is no space between pixels.
+     * @param periodY
+     *            the vertical spacing period between updated pixels, if it
+     *            equals 1, there is no space between pixels.
+     * @param bands
+     *            the array of integer values indicating the bands being
+     *            updated.
+     */
+    void imageUpdate(ImageReader source, BufferedImage theImage, int minX, int minY, int width,
+            int height, int periodX, int periodY, int[] bands);
+
+    /**
+     * Notifies this listener that the current read operation has completed a
+     * progressive pass.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     * @param theImage
+     *            the image to be updated.
+     */
+    void passComplete(ImageReader source, BufferedImage theImage);
+
+    /**
+     * Notifies this listener that the current read operation has begun a
+     * progressive pass.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     * @param theImage
+     *            the image to be updated.
+     * @param pass
+     *            the number of the pass.
+     * @param minPass
+     *            the index of the first pass that will be decoded.
+     * @param maxPass
+     *            the index of the last pass that will be decoded.
+     * @param minX
+     *            the minimum X coordinate of the pixels in the updated area.
+     * @param minY
+     *            the minimum Y coordinate of the pixels in the updated area.
+     * @param periodX
+     *            the horizontal spacing period between updated pixels, if it
+     *            equals 1, there is no space between pixels.
+     * @param periodY
+     *            the vertical spacing period between updated pixels, if it
+     *            equals 1, there is no space between pixels.
+     * @param bands
+     *            the array of integer values indicating the bands being
+     *            updated.
+     */
+    void passStarted(ImageReader source, BufferedImage theImage, int pass, int minPass,
+            int maxPass, int minX, int minY, int periodX, int periodY, int[] bands);
+
+    /**
+     * Notifies this listener that the current thumbnail read operation has
+     * completed a progressive pass.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     * @param theImage
+     *            the thumbnail to be updated.
+     */
+    void thumbnailPassComplete(ImageReader source, BufferedImage theImage);
+
+    /**
+     * Notifies this listener that the current thumbnail read operation has
+     * begun a progressive pass.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     * @param theThumbnail
+     *            the thumbnail to be updated.
+     * @param pass
+     *            the number of the pass.
+     * @param minPass
+     *            the index of the first pass that will be decoded.
+     * @param maxPass
+     *            the index of the last pass that will be decoded.
+     * @param minX
+     *            the minimum X coordinate of the pixels in the updated area.
+     * @param minY
+     *            the minimum Y coordinate of the pixels in the updated area.
+     * @param periodX
+     *            the horizontal spacing period between updated pixels, if it
+     *            equals 1, there is no space between pixels.
+     * @param periodY
+     *            the vertical spacing period between updated pixels, if it
+     *            equals 1, there is no space between pixels.
+     * @param bands
+     *            the array of integer values indicating the bands being
+     *            updated.
+     */
+    void thumbnailPassStarted(ImageReader source, BufferedImage theThumbnail, int pass,
+            int minPass, int maxPass, int minX, int minY, int periodX, int periodY, int[] bands);
+
+    /**
+     * Notifies this listener that a specified area of a thumbnail image has
+     * been updated.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     * @param theThumbnail
+     *            the thumbnail to be updated.
+     * @param minX
+     *            the minimum X coordinate of the pixels in the updated area.
+     * @param minY
+     *            the minimum Y coordinate of the pixels in the updated area.
+     * @param width
+     *            the width of updated area.
+     * @param height
+     *            the height of updated area.
+     * @param periodX
+     *            the horizontal spacing period between updated pixels, if it
+     *            equals 1, there is no space between pixels.
+     * @param periodY
+     *            the vertical spacing period between updated pixels, if it
+     *            equals 1, there is no space between pixels.
+     * @param bands
+     *            the array of integer values indicating the bands being
+     *            updated.
+     */
+    void thumbnailUpdate(ImageReader source, BufferedImage theThumbnail, int minX, int minY,
+            int width, int height, int periodX, int periodY, int[] bands);
+}
diff --git a/awt/javax/imageio/event/IIOReadWarningListener.java b/awt/javax/imageio/event/IIOReadWarningListener.java
new file mode 100644
index 0000000..318a5df
--- /dev/null
+++ b/awt/javax/imageio/event/IIOReadWarningListener.java
@@ -0,0 +1,49 @@
+/*
+ *  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.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+package javax.imageio.event;
+
+import java.util.EventListener;
+import javax.imageio.ImageReader;
+
+/* 
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The IIOReadWarningListener provides methods to receive notification of
+ * warning messages generated by image and thumbnail reading methods.
+ * 
+ * @since Android 1.0
+ */
+public interface IIOReadWarningListener extends EventListener {
+
+    /**
+     * Notifies this listener about a warning (non-fatal error) during decoding.
+     * 
+     * @param source
+     *            the ImageReader object which calls this method.
+     * @param warning
+     *            the string describing the warning.
+     */
+    public void warningOccurred(ImageReader source, String warning);
+}
diff --git a/awt/javax/imageio/event/IIOWriteProgressListener.java b/awt/javax/imageio/event/IIOWriteProgressListener.java
new file mode 100644
index 0000000..4a2c595
--- /dev/null
+++ b/awt/javax/imageio/event/IIOWriteProgressListener.java
@@ -0,0 +1,101 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.event;
+
+import javax.imageio.ImageWriter;
+import java.util.EventListener;
+
+/**
+ * The IIOWriteProgressListener interface provides methods to receive
+ * notification about the progress of the image and thumbnail writing methods.
+ * 
+ * @since Android 1.0
+ */
+public interface IIOWriteProgressListener extends EventListener {
+
+    /**
+     * Notifies this listener that an image write operation has been started.
+     * 
+     * @param source
+     *            the ImageWriter object which calls this method.
+     * @param imageIndex
+     *            the index of the image being written.
+     */
+    void imageStarted(ImageWriter source, int imageIndex);
+
+    /**
+     * Notifies this listener about the degree of completion of the write call.
+     * 
+     * @param source
+     *            the ImageWriter object which calls this method.
+     * @param percentageDone
+     *            the percentage of encoding done.
+     */
+    void imageProgress(ImageWriter source, float percentageDone);
+
+    /**
+     * Notifies this listener that the image writing has been completed.
+     * 
+     * @param source
+     *            the ImageWriter object which calls this method.
+     */
+    void imageComplete(ImageWriter source);
+
+    /**
+     * Notifies this listener that a thumbnail write operation has been started.
+     * 
+     * @param source
+     *            the ImageWriter object which calls this method.
+     * @param imageIndex
+     *            the index of the image being written.
+     * @param thumbnailIndex
+     *            the index of the thumbnail being written.
+     */
+    void thumbnailStarted(ImageWriter source, int imageIndex, int thumbnailIndex);
+
+    /**
+     * Notifies this listener about the degree of completion of the write call.
+     * 
+     * @param source
+     *            the ImageWriter object which calls this method.
+     * @param percentageDone
+     *            the percentage of encoding done.
+     */
+    void thumbnailProgress(ImageWriter source, float percentageDone);
+
+    /**
+     * Notifies this listener that a thumbnail write operation has been
+     * completed.
+     * 
+     * @param source
+     *            the ImageWriter object which calls this method.
+     */
+    void thumbnailComplete(ImageWriter source);
+
+    /**
+     * Notifies this listener that writing operation has been aborted.
+     * 
+     * @param source
+     *            the ImageWriter object which calls this method.
+     */
+    void writeAborted(ImageWriter source);
+}
diff --git a/awt/javax/imageio/event/IIOWriteWarningListener.java b/awt/javax/imageio/event/IIOWriteWarningListener.java
new file mode 100644
index 0000000..8ee41cd
--- /dev/null
+++ b/awt/javax/imageio/event/IIOWriteWarningListener.java
@@ -0,0 +1,46 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.event;
+
+import javax.imageio.ImageWriter;
+import java.util.EventListener;
+
+/**
+ * The IIOWriteWarningListener provides methods to receive notification of
+ * warnings generated by image and thumbnail writing methods.
+ * 
+ * @since Android 1.0
+ */
+public interface IIOWriteWarningListener extends EventListener {
+
+    /**
+     * Notifies this listener about a warning (non-fatal error) during encoding.
+     * 
+     * @param source
+     *            the ImageWriter object which calls this method.
+     * @param imageIndex
+     *            the index of the image generating the warning.
+     * @param warning
+     *            the string describing the warning.
+     */
+    void warningOccurred(ImageWriter source, int imageIndex, String warning);
+}
diff --git a/awt/javax/imageio/event/package.html b/awt/javax/imageio/event/package.html
new file mode 100644
index 0000000..c2fe39f
--- /dev/null
+++ b/awt/javax/imageio/event/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      This package provides interfaces to handle events which can be fired during the reading or writing of images.
+    </p>
+  @since Android 1.0
+  </body>
+</html>
diff --git a/awt/javax/imageio/metadata/IIOInvalidTreeException.java b/awt/javax/imageio/metadata/IIOInvalidTreeException.java
new file mode 100644
index 0000000..ba90657
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOInvalidTreeException.java
@@ -0,0 +1,74 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.metadata;
+
+import org.w3c.dom.Node;
+import javax.imageio.IIOException;
+
+/**
+ * The IIOInvalidTreeException provides notification about fails of
+ * IIOMetadataNodes tree parsing by IIOMetadata object.
+ * 
+ * @since Android 1.0
+ */
+public class IIOInvalidTreeException extends IIOException {
+
+    /**
+     * The offending node.
+     */
+    protected Node offendingNode = null;
+
+    /**
+     * Instantiates an IIOInvalidTreeException with the specified detailed
+     * message and specified offending Node.
+     * 
+     * @param message
+     *            the detailed message.
+     * @param offendingNode
+     *            the offending node.
+     */
+    public IIOInvalidTreeException(String message, Node offendingNode) {
+        super(message);
+        this.offendingNode = offendingNode;
+    }
+
+    /**
+     * Instantiates a new IIOInvalidTreeException with the specified detailed
+     * message and specified offending Node.
+     * 
+     * @param message
+     *            the detailed message.
+     * @param cause
+     *            the cause of this exception.
+     * @param offendingNode
+     *            the offending node.
+     */
+    public IIOInvalidTreeException(String message, Throwable cause, Node offendingNode) {
+        super(message, cause);
+        this.offendingNode = offendingNode;
+    }
+
+    /**
+     * Gets the offending node.
+     * 
+     * @return the offending node.
+     */
+    public Node getOffendingNode() {
+        return offendingNode;
+    }
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadata.java b/awt/javax/imageio/metadata/IIOMetadata.java
new file mode 100644
index 0000000..96cebf9
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadata.java
@@ -0,0 +1,391 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.metadata;
+
+import java.util.ArrayList;
+
+import org.apache.harmony.x.imageio.metadata.IIOMetadataUtils;
+import org.w3c.dom.Node;
+
+/**
+ * The class IIOMetadata represents the metadata (bundled with an image) as a
+ * Dom-type tree.
+ * 
+ * @since Android 1.0
+ */
+public abstract class IIOMetadata {
+
+    /**
+     * Whether the standard metadata format is supported.
+     */
+    protected boolean standardFormatSupported;
+
+    /**
+     * The native metadata format name.
+     */
+    protected String nativeMetadataFormatName;
+
+    /**
+     * The native metadata format class name.
+     */
+    protected String nativeMetadataFormatClassName;
+
+    /**
+     * The extra metadata format names.
+     */
+    protected String[] extraMetadataFormatNames;
+
+    /**
+     * The extra metadata format class names.
+     */
+    protected String[] extraMetadataFormatClassNames;
+
+    /**
+     * The default controller.
+     */
+    protected IIOMetadataController defaultController;
+
+    /**
+     * The controller.
+     */
+    protected IIOMetadataController controller;
+
+    /**
+     * Instantiates a new IIOMetadata with no data set.
+     */
+    protected IIOMetadata() {
+    }
+
+    /**
+     * Instantiates a new IIOMetadata with the specified data parameters.
+     * 
+     * @param standardMetadataFormatSupported
+     *            whether the standard metadata format is supported.
+     * @param nativeMetadataFormatName
+     *            the native metadata format name.
+     * @param nativeMetadataFormatClassName
+     *            the native metadata format class name.
+     * @param extraMetadataFormatNames
+     *            the extra metadata format names.
+     * @param extraMetadataFormatClassNames
+     *            the extra metadata format class names.
+     */
+    protected IIOMetadata(boolean standardMetadataFormatSupported, String nativeMetadataFormatName,
+            String nativeMetadataFormatClassName, String[] extraMetadataFormatNames,
+            String[] extraMetadataFormatClassNames) {
+        standardFormatSupported = standardMetadataFormatSupported;
+        this.nativeMetadataFormatName = nativeMetadataFormatName;
+        this.nativeMetadataFormatClassName = nativeMetadataFormatClassName;
+        if (extraMetadataFormatNames == null) {
+            if (extraMetadataFormatClassNames != null) {
+                throw new IllegalArgumentException(
+                        "extraMetadataFormatNames == null && extraMetadataFormatClassNames != null!");
+            }
+        } else {
+            if (extraMetadataFormatClassNames == null) {
+                throw new IllegalArgumentException(
+                        "extraMetadataFormatNames != null && extraMetadataFormatClassNames == null!");
+            }
+            if (extraMetadataFormatNames.length == 0) {
+                throw new IllegalArgumentException("extraMetadataFormatNames.length == 0!");
+            }
+            if (extraMetadataFormatClassNames.length != extraMetadataFormatNames.length) {
+                throw new IllegalArgumentException(
+                        "extraMetadataFormatClassNames.length != extraMetadataFormatNames.length!");
+            }
+            this.extraMetadataFormatNames = extraMetadataFormatNames.clone();
+            this.extraMetadataFormatClassNames = extraMetadataFormatClassNames.clone();
+        }
+    }
+
+    /**
+     * Gets the metadata as tree-type document.
+     * 
+     * @param formatName
+     *            the format name.
+     * @return the node in tree format.
+     */
+    public abstract Node getAsTree(String formatName);
+
+    /**
+     * Checks if the metadata is read only.
+     * 
+     * @return true, if the metadata is read only.
+     */
+    public abstract boolean isReadOnly();
+
+    /**
+     * Merges the specified tree with this metadata tree.
+     * 
+     * @param formatName
+     *            the format of the specified tree.
+     * @param root
+     *            the root node of the metadata tree.
+     * @throws IIOInvalidTreeException
+     *             if the specified tree is incompatible with the this metadata
+     *             tree.
+     */
+    public abstract void mergeTree(String formatName, Node root) throws IIOInvalidTreeException;
+
+    /**
+     * Resets the controller.
+     */
+    public abstract void reset();
+
+    /**
+     * Gets the controller associated with this metadata document.
+     * 
+     * @return the controller.
+     */
+    public IIOMetadataController getController() {
+        return controller;
+    }
+
+    /**
+     * Checks whether this metadata has a controller.
+     * 
+     * @return true, if this metadata has a controller.
+     */
+    public boolean hasController() {
+        return getController() != null;
+    }
+
+    /**
+     * Activate the controller.
+     * 
+     * @return true, if successful.
+     */
+    public boolean activateController() {
+        if (!hasController()) {
+            throw new IllegalStateException("hasController() == false!");
+        }
+        return getController().activate(this);
+    }
+
+    /**
+     * Gets the default controller.
+     * 
+     * @return the default controller.
+     */
+    public IIOMetadataController getDefaultController() {
+        return defaultController;
+    }
+
+    /**
+     * Gets the extra metadata format names.
+     * 
+     * @return the extra metadata format names.
+     */
+    public String[] getExtraMetadataFormatNames() {
+        return extraMetadataFormatNames == null ? null : extraMetadataFormatNames.clone();
+    }
+
+    /**
+     * Gets the metadata format.
+     * 
+     * @param formatName
+     *            the format name.
+     * @return the metadata format.
+     */
+    public IIOMetadataFormat getMetadataFormat(String formatName) {
+        return IIOMetadataUtils.instantiateMetadataFormat(formatName, standardFormatSupported,
+                nativeMetadataFormatName, nativeMetadataFormatClassName, extraMetadataFormatNames,
+                extraMetadataFormatClassNames);
+    }
+
+    /**
+     * Gets the native metadata format name.
+     * 
+     * @return the native metadata format name.
+     */
+    public String getNativeMetadataFormatName() {
+        return nativeMetadataFormatName;
+    }
+
+    /**
+     * Checks if the standard metadata format is supported.
+     * 
+     * @return true, if the standard metadata format is supported.
+     */
+    public boolean isStandardMetadataFormatSupported() {
+        return standardFormatSupported;
+    }
+
+    /**
+     * Gets the metadata format names.
+     * 
+     * @return the metadata format names.
+     */
+    public String[] getMetadataFormatNames() {
+        ArrayList<String> res = new ArrayList<String>();
+
+        String nativeMetadataFormatName = getNativeMetadataFormatName();
+        boolean standardFormatSupported = isStandardMetadataFormatSupported();
+        String extraMetadataFormatNames[] = getExtraMetadataFormatNames();
+
+        if (standardFormatSupported) {
+            res.add(IIOMetadataFormatImpl.standardMetadataFormatName);
+        }
+        if (nativeMetadataFormatName != null) {
+            res.add(nativeMetadataFormatName);
+        }
+        if (extraMetadataFormatNames != null) {
+            for (String extraMetadataFormatName : extraMetadataFormatNames) {
+                res.add(extraMetadataFormatName);
+            }
+        }
+
+        return res.size() > 0 ? res.toArray(new String[0]) : null;
+    }
+
+    /**
+     * Gets the standard chroma node.
+     * 
+     * @return the standard chroma node.
+     */
+    protected IIOMetadataNode getStandardChromaNode() {
+        return null;
+    }
+
+    /**
+     * Gets the standard compression node.
+     * 
+     * @return the standard compression node.
+     */
+    protected IIOMetadataNode getStandardCompressionNode() {
+        return null;
+    }
+
+    /**
+     * Gets the standard data node.
+     * 
+     * @return the standard data node.
+     */
+    protected IIOMetadataNode getStandardDataNode() {
+        return null;
+    }
+
+    /**
+     * Gets the standard dimension node.
+     * 
+     * @return the standard dimension node.
+     */
+    protected IIOMetadataNode getStandardDimensionNode() {
+        return null;
+    }
+
+    /**
+     * Gets the standard document node.
+     * 
+     * @return the standard document node.
+     */
+    protected IIOMetadataNode getStandardDocumentNode() {
+        return null;
+    }
+
+    /**
+     * Gets the standard text node.
+     * 
+     * @return the standard text node.
+     */
+    protected IIOMetadataNode getStandardTextNode() {
+        return null;
+    }
+
+    /**
+     * Gets the standard tile node.
+     * 
+     * @return the standard tile node.
+     */
+    protected IIOMetadataNode getStandardTileNode() {
+        return null;
+    }
+
+    /**
+     * Gets the standard transparency node.
+     * 
+     * @return the standard transparency node.
+     */
+    protected IIOMetadataNode getStandardTransparencyNode() {
+        return null;
+    }
+
+    /**
+     * Gets the metadata as a tree in standard format.
+     * 
+     * @return the metadata as a tree in standard format.
+     */
+    protected final IIOMetadataNode getStandardTree() {
+        // Create root node
+        IIOMetadataNode root = new IIOMetadataNode(IIOMetadataFormatImpl.standardMetadataFormatName);
+
+        Node node;
+        if ((node = getStandardChromaNode()) != null) {
+            root.appendChild(node);
+        }
+        if ((node = getStandardCompressionNode()) != null) {
+            root.appendChild(node);
+        }
+        if ((node = getStandardDataNode()) != null) {
+            root.appendChild(node);
+        }
+        if ((node = getStandardDimensionNode()) != null) {
+            root.appendChild(node);
+        }
+        if ((node = getStandardDocumentNode()) != null) {
+            root.appendChild(node);
+        }
+        if ((node = getStandardTextNode()) != null) {
+            root.appendChild(node);
+        }
+        if ((node = getStandardTileNode()) != null) {
+            root.appendChild(node);
+        }
+        if ((node = getStandardTransparencyNode()) != null) {
+            root.appendChild(node);
+        }
+
+        return root;
+    }
+
+    /**
+     * Sets the controller.
+     * 
+     * @param controller
+     *            the new controller.
+     */
+    public void setController(IIOMetadataController controller) {
+        this.controller = controller;
+    }
+
+    /**
+     * Sets the from tree.
+     * 
+     * @param formatName
+     *            the name of the metatdata format of the from tree.
+     * @param root
+     *            the root node of the from tree.
+     * @throws IIOInvalidTreeException
+     *             if the tree or its format is not compatible with this
+     *             metadata.
+     */
+    public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException {
+        reset();
+        mergeTree(formatName, root);
+    }
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadataController.java b/awt/javax/imageio/metadata/IIOMetadataController.java
new file mode 100644
index 0000000..1405948
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadataController.java
@@ -0,0 +1,46 @@
+/*
+ *  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.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+package javax.imageio.metadata;
+
+/* 
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The IIOMetadataController interface provides a method for implementing
+ * objects to activate the controller without defining how the controller
+ * obtains values.
+ * 
+ * @since Android 1.0
+ */
+public interface IIOMetadataController {
+
+    /**
+     * Activates a controller.
+     * 
+     * @param metadata
+     *            the metadata to be modified.
+     * @return true, if the IIOMetadata has been modified, false otherwise.
+     */
+    public boolean activate(IIOMetadata metadata);
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadataFormat.java b/awt/javax/imageio/metadata/IIOMetadataFormat.java
new file mode 100644
index 0000000..0e7e697
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadataFormat.java
@@ -0,0 +1,404 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.metadata;
+
+import javax.imageio.ImageTypeSpecifier;
+import java.util.Locale;
+
+/**
+ * The Interface IIOMetadataFormat is implemented by classes that describe the
+ * rules and allowed elements for a metadata document tree.
+ * 
+ * @since Android 1.0
+ */
+public interface IIOMetadataFormat {
+
+    /**
+     * The CHILD_POLICY_EMPTY.
+     */
+    int CHILD_POLICY_EMPTY = 0;
+
+    /**
+     * The CHILD_POLICY_ALL.
+     */
+    int CHILD_POLICY_ALL = 1;
+
+    /**
+     * The CHILD_POLICY_SOME.
+     */
+    int CHILD_POLICY_SOME = 2;
+
+    /**
+     * The CHILD_POLICY_CHOICE.
+     */
+    int CHILD_POLICY_CHOICE = 3;
+
+    /**
+     * The CHILD_POLICY_SEQUENCE.
+     */
+    int CHILD_POLICY_SEQUENCE = 4;
+
+    /**
+     * The CHILD_POLICY_REPEAT.
+     */
+    int CHILD_POLICY_REPEAT = 5;
+
+    /**
+     * The maximum value for the child policy.
+     */
+    int CHILD_POLICY_MAX = CHILD_POLICY_REPEAT;
+
+    /**
+     * The DATATYPE_STRING.
+     */
+    int DATATYPE_STRING = 0;
+
+    /**
+     * The DATATYPE_BOOLEAN.
+     */
+    int DATATYPE_BOOLEAN = 1;
+
+    /**
+     * The DATATYPE_INTEGER.
+     */
+    int DATATYPE_INTEGER = 2;
+
+    /**
+     * The DATATYPE_FLOAT.
+     */
+    int DATATYPE_FLOAT = 3;
+
+    /**
+     * The DATATYPE_DOUBLE.
+     */
+    int DATATYPE_DOUBLE = 4;
+
+    /**
+     * The VALUE_NONE.
+     */
+    int VALUE_NONE = 0;
+
+    /**
+     * The VALUE_ARBITRARY.
+     */
+    int VALUE_ARBITRARY = 1;
+
+    /**
+     * The VALUE_RANGE.
+     */
+    int VALUE_RANGE = 2;
+
+    /**
+     * The VALUE_RANGE_MIN_INCLUSIVE_MASK.
+     */
+    int VALUE_RANGE_MIN_INCLUSIVE_MASK = 4;
+
+    /**
+     * The VALUE_RANGE_MAX_INCLUSIVE_MASK.
+     */
+    int VALUE_RANGE_MAX_INCLUSIVE_MASK = 8;
+
+    /**
+     * The VALUE_ENUMERATION.
+     */
+    int VALUE_ENUMERATION = 16;
+
+    /**
+     * The VALUE_LIST.
+     */
+    int VALUE_LIST = 32;
+
+    /**
+     * The VALUE_RANGE_MIN_INCLUSIVE.
+     */
+    int VALUE_RANGE_MIN_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MIN_INCLUSIVE_MASK;
+
+    /**
+     * The VALUE_RANGE_MAX_INCLUSIVE.
+     */
+    int VALUE_RANGE_MAX_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MAX_INCLUSIVE_MASK;
+
+    /**
+     * The VALUE_RANGE_MIN_MAX_INCLUSIVE.
+     */
+    int VALUE_RANGE_MIN_MAX_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MIN_INCLUSIVE_MASK
+            | VALUE_RANGE_MAX_INCLUSIVE_MASK;
+
+    /**
+     * Tells whether the specified element is allowed for the specified image
+     * type.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param imageType
+     *            the image type.
+     * @return true, if the specified element is allowed for the specified image
+     *         type.
+     */
+    boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType);
+
+    /**
+     * Gets data type of the specified attribute of the specified element.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param attrName
+     *            the attribute name.
+     * @return the attribute's data type.
+     */
+    int getAttributeDataType(String elementName, String attrName);
+
+    /**
+     * Gets the default value of the specified attribute of the specified
+     * element.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param attrName
+     *            the attribute name.
+     * @return the attribute's default value.
+     */
+    String getAttributeDefaultValue(String elementName, String attrName);
+
+    /**
+     * Gets the user-friendly description of the attribute.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param attrName
+     *            the attribute name.
+     * @param locale
+     *            the locale giving the desired language for the description.
+     * @return the attribute description.
+     */
+    String getAttributeDescription(String elementName, String attrName, Locale locale);
+
+    /**
+     * Gets the attribute enumerations.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param attrName
+     *            the attribute name.
+     * @return the attribute enumerations.
+     */
+    String[] getAttributeEnumerations(String elementName, String attrName);
+
+    /**
+     * Gets the maximum length of the attribute list.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param attrName
+     *            the attribute name.
+     * @return the maximum length of the attribute list.
+     */
+    int getAttributeListMaxLength(String elementName, String attrName);
+
+    /**
+     * Gets the minimum length of the attribute list.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param attrName
+     *            the attribute name.
+     * @return the minimum length of the attribute list.
+     */
+    int getAttributeListMinLength(String elementName, String attrName);
+
+    /**
+     * Gets the maximum value allowed for the attribute.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param attrName
+     *            the attribute name.
+     * @return the maximum value allowed for the attribute.
+     */
+    String getAttributeMaxValue(String elementName, String attrName);
+
+    /**
+     * Gets the minimum value allowed for the attribute.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param attrName
+     *            the attribute name.
+     * @return the minimum value allowed for the attribute.
+     */
+    String getAttributeMinValue(String elementName, String attrName);
+
+    /**
+     * Gets the attribute names allowed for the specified element.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the attribute names.
+     */
+    String[] getAttributeNames(String elementName);
+
+    /**
+     * Gets the attribute value type.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param attrName
+     *            the attribute name.
+     * @return the attribute value type.
+     */
+    int getAttributeValueType(String elementName, String attrName);
+
+    /**
+     * Checks whether the specified attribute is required for the specified
+     * element.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param attrName
+     *            the attribute name.
+     * @return true, if the specified attribute is required for the specified
+     *         element.
+     */
+    boolean isAttributeRequired(String elementName, String attrName);
+
+    /**
+     * Gets the names of the possible child elements for the given element.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the child names.
+     */
+    String[] getChildNames(String elementName);
+
+    /**
+     * Gets the constant describing the element's child policy.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the child policy.
+     */
+    int getChildPolicy(String elementName);
+
+    /**
+     * Gets the user-friendly description of the element.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param locale
+     *            the locale giving the desired language for the description.
+     * @return the element description.
+     */
+    String getElementDescription(String elementName, Locale locale);
+
+    /**
+     * Gets the maximum number of children allowed for the element.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the maximum number of children allowed for the element.
+     */
+    int getElementMaxChildren(String elementName);
+
+    /**
+     * Gets the minimum number of children allowed for the element.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the minimum number of children allowed for the element.
+     */
+    int getElementMinChildren(String elementName);
+
+    /**
+     * Gets the maximum object array length allowed for the element.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the maximum object array length allowed for the element.
+     */
+    int getObjectArrayMaxLength(String elementName);
+
+    /**
+     * Gets the minimum object array length allowed for the element.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the minimum object array length allowed for the element.
+     */
+    int getObjectArrayMinLength(String elementName);
+
+    /**
+     * Gets the object class corresponding to the specified element.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the object class corresponding to the specified element.
+     */
+    Class<?> getObjectClass(String elementName);
+
+    /**
+     * Gets the object default value for the element.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the object default value for the element.
+     */
+    Object getObjectDefaultValue(String elementName);
+
+    /**
+     * Gets the object enumerations.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the object enumerations.
+     */
+    Object[] getObjectEnumerations(String elementName);
+
+    /**
+     * Gets the maximum value allowed for the element's object.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the maximum value allowed for the element's object.
+     */
+    Comparable<?> getObjectMaxValue(String elementName);
+
+    /**
+     * Gets the minimum value allowed for the element's object.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the minimum value allowed for the element's object.
+     */
+    Comparable<?> getObjectMinValue(String elementName);
+
+    /**
+     * Gets the constant that indicates the type of the element's value.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the constant that indicates the type of the element's value.
+     */
+    int getObjectValueType(String elementName);
+
+    /**
+     * Gets the name of the root element.
+     * 
+     * @return the name of the root element.
+     */
+    String getRootName();
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java b/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java
new file mode 100644
index 0000000..1a6e568
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java
@@ -0,0 +1,1056 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.metadata;
+
+import javax.imageio.ImageTypeSpecifier;
+import java.util.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * The IIOMetadataFormatImpl class provides an implementation of the
+ * IIOMetadataFormat interface.
+ * 
+ * @since Android 1.0
+ */
+public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat {
+
+    /**
+     * The Constant standardMetadataFormatName.
+     */
+    @SuppressWarnings( {
+        "ConstantDeclaredInAbstractClass"
+    })
+    public static final String standardMetadataFormatName = "javax_imageio_1.0";
+
+    /**
+     * The standard format.
+     */
+    @SuppressWarnings( {
+        "StaticNonFinalField"
+    })
+    private static IIOMetadataFormatImpl standardFormat;
+
+    /**
+     * The root name.
+     */
+    private String rootName;
+
+    /**
+     * The element hash.
+     */
+    private HashMap<String, Element> elementHash = new HashMap<String, Element>();
+
+    /**
+     * The resource base name.
+     */
+    private String resourceBaseName = getClass().getName() + "Resources";
+
+    /**
+     * Instantiates an IIOMetadataFormatImpl with the specified root name and
+     * child policy (not CHILD_POLICY_REPEAT).
+     * 
+     * @param rootName
+     *            the name of root element.
+     * @param childPolicy
+     *            the child policy defined by one of the CHILD_POLICY_*
+     *            constants (except CHILD_POLICY_REPEAT).
+     */
+    public IIOMetadataFormatImpl(String rootName, int childPolicy) {
+        if (rootName == null) {
+            throw new IllegalArgumentException("rootName is null");
+        }
+        if (childPolicy < CHILD_POLICY_EMPTY || childPolicy > CHILD_POLICY_MAX
+                || childPolicy == CHILD_POLICY_REPEAT) {
+            throw new IllegalArgumentException("childPolicy is not one of the predefined constants");
+        }
+
+        this.rootName = rootName;
+        Element root = new Element();
+        root.name = rootName;
+        root.childPolicy = childPolicy;
+        elementHash.put(rootName, root);
+    }
+
+    /**
+     * Instantiates an IIOMetadataFormatImpl with the specified root name and
+     * CHILD_POLICY_REPEAT child policy.
+     * 
+     * @param rootName
+     *            the name of root element.
+     * @param minChildren
+     *            the minimum number of children.
+     * @param maxChildren
+     *            the maximum number of children
+     */
+    public IIOMetadataFormatImpl(String rootName, int minChildren, int maxChildren) {
+        if (rootName == null) {
+            throw new IllegalArgumentException("rootName is null");
+        }
+        if (minChildren < 0) {
+            throw new IllegalArgumentException("minChildren < 0!");
+        }
+        if (minChildren > maxChildren) {
+            throw new IllegalArgumentException("minChildren > maxChildren!");
+        }
+
+        this.rootName = rootName;
+        Element root = new Element();
+        root.name = rootName;
+        root.minChildren = minChildren;
+        root.maxChildren = maxChildren;
+        root.childPolicy = CHILD_POLICY_REPEAT;
+        elementHash.put(rootName, root);
+    }
+
+    @SuppressWarnings( {
+        "AbstractMethodOverridesAbstractMethod"
+    })
+    public abstract boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType);
+
+    /**
+     * Adds a new attribute to an existing element.
+     * 
+     * @param elementName
+     *            the name of the element to which the new attribute will be
+     *            added.
+     * @param attrName
+     *            the attribute name.
+     * @param dataType
+     *            the data type of the new attribute.
+     * @param required
+     *            the flag which indicates whether this attribute must be
+     *            present.
+     * @param listMinLength
+     *            the minimum legal number of list items.
+     * @param listMaxLength
+     *            the the maximum legal number of list items.
+     */
+    protected void addAttribute(String elementName, String attrName, int dataType,
+            boolean required, int listMinLength, int listMaxLength) {
+        if (attrName == null) {
+            throw new IllegalArgumentException("attrName == null!");
+        }
+        if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
+            throw new IllegalArgumentException("Invalid value for dataType!");
+        }
+        if (listMinLength < 0 || listMinLength > listMaxLength) {
+            throw new IllegalArgumentException("Invalid list bounds!");
+        }
+
+        Element element = findElement(elementName);
+        Attlist attr = new Attlist();
+        attr.name = attrName;
+        attr.dataType = dataType;
+        attr.required = required;
+        attr.listMinLength = listMinLength;
+        attr.listMaxLength = listMaxLength;
+        attr.valueType = VALUE_LIST;
+
+        element.attributes.put(attrName, attr);
+    }
+
+    /**
+     * Adds a new attribute to an existing element.
+     * 
+     * @param elementName
+     *            the name of the element to which the new attribute will be
+     *            added.
+     * @param attrName
+     *            the attribute name.
+     * @param dataType
+     *            the data type of the new attribute.
+     * @param required
+     *            the flag which indicates whether this attribute must be
+     *            present.
+     * @param defaultValue
+     *            the default value of the attribute.
+     */
+    protected void addAttribute(String elementName, String attrName, int dataType,
+            boolean required, String defaultValue) {
+        if (attrName == null) {
+            throw new IllegalArgumentException("attrName == null!");
+        }
+        if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
+            throw new IllegalArgumentException("Invalid value for dataType!");
+        }
+
+        Element element = findElement(elementName);
+        Attlist attr = new Attlist();
+        attr.name = attrName;
+        attr.dataType = dataType;
+        attr.required = required;
+        attr.defaultValue = defaultValue;
+        attr.valueType = VALUE_ARBITRARY;
+
+        element.attributes.put(attrName, attr);
+    }
+
+    /**
+     * Adds a new attribute to an existing element.
+     * 
+     * @param elementName
+     *            the name of the element to which the new attribute will be
+     *            added.
+     * @param attrName
+     *            the attribute name.
+     * @param dataType
+     *            the data type of the new attribute.
+     * @param required
+     *            the flag which indicates whether this attribute must be
+     *            present.
+     * @param defaultValue
+     *            the default value of the attribute.
+     * @param enumeratedValues
+     *            the legal values for the attribute as a list of strings.
+     */
+    protected void addAttribute(String elementName, String attrName, int dataType,
+            boolean required, String defaultValue, List<String> enumeratedValues) {
+        if (attrName == null) {
+            throw new IllegalArgumentException("attrName == null!");
+        }
+        if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
+            throw new IllegalArgumentException("Invalid value for dataType!");
+        }
+        if (enumeratedValues == null || enumeratedValues.isEmpty()) {
+            throw new IllegalArgumentException("enumeratedValues is empty or null");
+        }
+
+        try {
+            for (String enumeratedValue : enumeratedValues) {
+                if (enumeratedValue == null) {
+                    throw new IllegalArgumentException("enumeratedValues contains a null!");
+                }
+            }
+        } catch (ClassCastException e) {
+            throw new IllegalArgumentException("enumeratedValues contains a non-String value!");
+        }
+
+        Element element = findElement(elementName);
+        Attlist attr = new Attlist();
+        attr.name = attrName;
+        attr.dataType = dataType;
+        attr.required = required;
+        attr.defaultValue = defaultValue;
+        attr.enumeratedValues = enumeratedValues;
+        attr.valueType = VALUE_ENUMERATION;
+
+        element.attributes.put(attrName, attr);
+    }
+
+    /**
+     * Adds a new attribute to an existing element.
+     * 
+     * @param elementName
+     *            the name of the element to which the new attribute will be
+     *            added.
+     * @param attrName
+     *            the attribute name.
+     * @param dataType
+     *            the data type of the new attribute.
+     * @param required
+     *            the flag which indicates whether this attribute must be
+     *            present.
+     * @param defaultValue
+     *            the default value of attribute.
+     * @param minValue
+     *            the minimum legal value of an attribute.
+     * @param maxValue
+     *            the maximum legal value of an attribute.
+     * @param minInclusive
+     *            the flag which indicates whether the minValue is inclusive.
+     * @param maxInclusive
+     *            the flag which indicates whether the maxValue is inclusive.
+     */
+    protected void addAttribute(String elementName, String attrName, int dataType,
+            boolean required, String defaultValue, String minValue, String maxValue,
+            boolean minInclusive, boolean maxInclusive) {
+        if (attrName == null) {
+            throw new IllegalArgumentException("attrName == null!");
+        }
+        if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
+            throw new IllegalArgumentException("Invalid value for dataType!");
+        }
+
+        Element element = findElement(elementName);
+        Attlist attr = new Attlist();
+        attr.name = attrName;
+        attr.dataType = dataType;
+        attr.required = required;
+        attr.defaultValue = defaultValue;
+        attr.minValue = minValue;
+        attr.maxValue = maxValue;
+        attr.minInclusive = minInclusive;
+        attr.maxInclusive = maxInclusive;
+
+        attr.valueType = VALUE_RANGE;
+        attr.valueType |= minInclusive ? VALUE_RANGE_MIN_INCLUSIVE_MASK : 0;
+        attr.valueType |= maxInclusive ? VALUE_RANGE_MAX_INCLUSIVE_MASK : 0;
+
+        element.attributes.put(attrName, attr);
+    }
+
+    /**
+     * Adds a new attribute with boolean data type to an existing element.
+     * 
+     * @param elementName
+     *            the name of the element to which the new attribute will be
+     *            added.
+     * @param attrName
+     *            the attribute name.
+     * @param hasDefaultValue
+     *            the flag which indicates whether this attribute must have a
+     *            default value.
+     * @param defaultValue
+     *            the default value.
+     */
+    protected void addBooleanAttribute(String elementName, String attrName,
+            boolean hasDefaultValue, boolean defaultValue) {
+        String defaultVal = hasDefaultValue ? (defaultValue ? "TRUE" : "FALSE") : null;
+        ArrayList<String> values = new ArrayList<String>(2);
+        values.add("TRUE");
+        values.add("FALSE");
+
+        addAttribute(elementName, attrName, DATATYPE_BOOLEAN, true, defaultVal, values);
+    }
+
+    /**
+     * Adds an existing element to the list of child elements of the specified
+     * parent element.
+     * 
+     * @param elementName
+     *            the name of the element to be added.
+     * @param parentName
+     *            the parent element name.
+     */
+    protected void addChildElement(String elementName, String parentName) {
+        Element parent = findElement(parentName);
+        Element element = findElement(elementName);
+        parent.children.add(element.name);
+    }
+
+    /**
+     * Adds a new element type to this IIOMetadataFormat with a child policy (if
+     * policy is not CHILD_POLICY_REPEAT).
+     * 
+     * @param elementName
+     *            the name of the element to be added.
+     * @param parentName
+     *            the parent element name.
+     * @param childPolicy
+     *            one of the CHILD_POLICY_* constants defined by
+     *            IIOMetadataFormat.
+     */
+    protected void addElement(String elementName, String parentName, int childPolicy) {
+        if (childPolicy < CHILD_POLICY_EMPTY || childPolicy > CHILD_POLICY_MAX
+                || childPolicy == CHILD_POLICY_REPEAT) {
+            throw new IllegalArgumentException("childPolicy is not one of the predefined constants");
+        }
+
+        Element parent = findElement(parentName);
+        Element element = new Element();
+        element.name = elementName;
+        element.childPolicy = childPolicy;
+        elementHash.put(elementName, element);
+        parent.children.add(elementName);
+    }
+
+    /**
+     * Adds a new element type to this IIOMetadataFormat with
+     * CHILD_POLICY_REPEAT and the specified minimum and maximum number of child
+     * elements.
+     * 
+     * @param elementName
+     *            the element name to be added.
+     * @param parentName
+     *            the parent element name.
+     * @param minChildren
+     *            the minimum number of child elements.
+     * @param maxChildren
+     *            the maximum number of child elements.
+     */
+    protected void addElement(String elementName, String parentName, int minChildren,
+            int maxChildren) {
+        if (minChildren < 0) {
+            throw new IllegalArgumentException("minChildren < 0!");
+        }
+        if (minChildren > maxChildren) {
+            throw new IllegalArgumentException("minChildren > maxChildren!");
+        }
+
+        Element parent = findElement(parentName);
+        Element element = new Element();
+        element.name = elementName;
+        element.childPolicy = CHILD_POLICY_REPEAT;
+        element.minChildren = minChildren;
+        element.maxChildren = maxChildren;
+        elementHash.put(elementName, element);
+        parent.children.add(elementName);
+    }
+
+    /**
+     * Adds an Object reference with the specified class type to be stored as
+     * element's value.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param classType
+     *            the class indicates the legal types for the object's value.
+     * @param arrayMinLength
+     *            the minimum legal length for the array.
+     * @param arrayMaxLength
+     *            the maximum legal length for the array.
+     */
+    protected void addObjectValue(String elementName, Class<?> classType, int arrayMinLength,
+            int arrayMaxLength) {
+        Element element = findElement(elementName);
+
+        ObjectValue objVal = new ObjectValue();
+        objVal.classType = classType;
+        objVal.arrayMaxLength = arrayMaxLength;
+        objVal.arrayMinLength = arrayMinLength;
+        objVal.valueType = VALUE_LIST;
+
+        element.objectValue = objVal;
+    }
+
+    /**
+     * Adds an Object reference with the specified class type to be stored as an
+     * element's value.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param classType
+     *            the class indicates the legal types for the object's value.
+     * @param required
+     *            a flag indicated that this object value must be present.
+     * @param defaultValue
+     *            the default value, or null.
+     */
+    protected <T> void addObjectValue(String elementName, Class<T> classType, boolean required,
+            T defaultValue) {
+        // note: reqired is an unused parameter
+        Element element = findElement(elementName);
+
+        ObjectValue<T> objVal = new ObjectValue<T>();
+        objVal.classType = classType;
+        objVal.defaultValue = defaultValue;
+        objVal.valueType = VALUE_ARBITRARY;
+
+        element.objectValue = objVal;
+    }
+
+    /**
+     * Adds an Object reference with the specified class type to be stored as
+     * the element's value.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param classType
+     *            the class indicates the legal types for the object value.
+     * @param required
+     *            a flag indicated that this object value must be present.
+     * @param defaultValue
+     *            the default value, or null.
+     * @param enumeratedValues
+     *            the list of legal values for the object.
+     */
+    protected <T> void addObjectValue(String elementName, Class<T> classType, boolean required,
+            T defaultValue, List<? extends T> enumeratedValues) {
+        // note: reqired is an unused parameter
+        if (enumeratedValues == null || enumeratedValues.isEmpty()) {
+            throw new IllegalArgumentException("enumeratedValues is empty or null");
+        }
+
+        try {
+            for (T enumeratedValue : enumeratedValues) {
+                if (enumeratedValue == null) {
+                    throw new IllegalArgumentException("enumeratedValues contains a null!");
+                }
+            }
+        } catch (ClassCastException e) {
+            throw new IllegalArgumentException(
+                    "enumeratedValues contains a value not of class classType!");
+        }
+
+        Element element = findElement(elementName);
+
+        ObjectValue<T> objVal = new ObjectValue<T>();
+        objVal.classType = classType;
+        objVal.defaultValue = defaultValue;
+        objVal.enumeratedValues = enumeratedValues;
+        objVal.valueType = VALUE_ENUMERATION;
+
+        element.objectValue = objVal;
+    }
+
+    /**
+     * Adds an Object reference with the specified class type to be stored as
+     * the element's value.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param classType
+     *            the class indicates the legal types for the object value.
+     * @param defaultValue
+     *            the default value, or null.
+     * @param minValue
+     *            the minimum legal value for the object value.
+     * @param maxValue
+     *            the maximum legal value for the object value.
+     * @param minInclusive
+     *            the flag which indicates whether the minValue is inclusive.
+     * @param maxInclusive
+     *            the flag which indicates whether the maxValue is inclusive.
+     */
+    protected <T extends Object & Comparable<? super T>> void addObjectValue(String elementName,
+            Class<T> classType, T defaultValue, Comparable<? super T> minValue,
+            Comparable<? super T> maxValue, boolean minInclusive, boolean maxInclusive) {
+        Element element = findElement(elementName);
+
+        ObjectValue<T> objVal = new ObjectValue<T>();
+        objVal.classType = classType;
+        objVal.defaultValue = defaultValue;
+        objVal.minValue = minValue;
+        objVal.maxValue = maxValue;
+        objVal.minInclusive = minInclusive;
+        objVal.maxInclusive = maxInclusive;
+
+        objVal.valueType = VALUE_RANGE;
+        objVal.valueType |= minInclusive ? VALUE_RANGE_MIN_INCLUSIVE_MASK : 0;
+        objVal.valueType |= maxInclusive ? VALUE_RANGE_MAX_INCLUSIVE_MASK : 0;
+
+        element.objectValue = objVal;
+    }
+
+    public int getAttributeDataType(String elementName, String attrName) {
+        Attlist attr = findAttribute(elementName, attrName);
+        return attr.dataType;
+    }
+
+    public String getAttributeDefaultValue(String elementName, String attrName) {
+        Attlist attr = findAttribute(elementName, attrName);
+        return attr.defaultValue;
+    }
+
+    public String getAttributeDescription(String elementName, String attrName, Locale locale) {
+        findAttribute(elementName, attrName);
+        return getResourceString(elementName + "/" + attrName, locale);
+    }
+
+    public String[] getAttributeEnumerations(String elementName, String attrName) {
+        Attlist attr = findAttribute(elementName, attrName);
+        if (attr.valueType != VALUE_ENUMERATION) {
+            throw new IllegalArgumentException("Attribute is not an enumeration!");
+        }
+
+        return attr.enumeratedValues.toArray(new String[attr.enumeratedValues.size()]);
+    }
+
+    public int getAttributeListMaxLength(String elementName, String attrName) {
+        Attlist attr = findAttribute(elementName, attrName);
+        if (attr.valueType != VALUE_LIST) {
+            throw new IllegalArgumentException("Attribute is not a list!");
+        }
+        return attr.listMaxLength;
+    }
+
+    public int getAttributeListMinLength(String elementName, String attrName) {
+        Attlist attr = findAttribute(elementName, attrName);
+        if (attr.valueType != VALUE_LIST) {
+            throw new IllegalArgumentException("Attribute is not a list!");
+        }
+        return attr.listMinLength;
+    }
+
+    public String getAttributeMaxValue(String elementName, String attrName) {
+        Attlist attr = findAttribute(elementName, attrName);
+        if ((attr.valueType & VALUE_RANGE) == 0) {
+            throw new IllegalArgumentException("Attribute is not a range!");
+        }
+        return attr.maxValue;
+    }
+
+    public String getAttributeMinValue(String elementName, String attrName) {
+        Attlist attr = findAttribute(elementName, attrName);
+        if ((attr.valueType & VALUE_RANGE) == 0) {
+            throw new IllegalArgumentException("Attribute is not a range!");
+        }
+        return attr.minValue;
+    }
+
+    public String[] getAttributeNames(String elementName) {
+        Element element = findElement(elementName);
+        return element.attributes.keySet().toArray(new String[element.attributes.size()]);
+    }
+
+    public int getAttributeValueType(String elementName, String attrName) {
+        Attlist attr = findAttribute(elementName, attrName);
+        return attr.valueType;
+    }
+
+    public String[] getChildNames(String elementName) {
+        Element element = findElement(elementName);
+        if (element.childPolicy == CHILD_POLICY_EMPTY) { // Element cannot have
+            // children
+            return null;
+        }
+        return element.children.toArray(new String[element.children.size()]);
+    }
+
+    public int getChildPolicy(String elementName) {
+        Element element = findElement(elementName);
+        return element.childPolicy;
+    }
+
+    public String getElementDescription(String elementName, Locale locale) {
+        findElement(elementName); // Check if there is such element
+        return getResourceString(elementName, locale);
+    }
+
+    public int getElementMaxChildren(String elementName) {
+        Element element = findElement(elementName);
+        if (element.childPolicy != CHILD_POLICY_REPEAT) {
+            throw new IllegalArgumentException("Child policy is not CHILD_POLICY_REPEAT!");
+        }
+        return element.maxChildren;
+    }
+
+    public int getElementMinChildren(String elementName) {
+        Element element = findElement(elementName);
+        if (element.childPolicy != CHILD_POLICY_REPEAT) {
+            throw new IllegalArgumentException("Child policy is not CHILD_POLICY_REPEAT!");
+        }
+        return element.minChildren;
+    }
+
+    public int getObjectArrayMaxLength(String elementName) {
+        Element element = findElement(elementName);
+        ObjectValue v = element.objectValue;
+        if (v == null || v.valueType != VALUE_LIST) {
+            throw new IllegalArgumentException("Not a list!");
+        }
+        return v.arrayMaxLength;
+    }
+
+    public int getObjectArrayMinLength(String elementName) {
+        Element element = findElement(elementName);
+        ObjectValue v = element.objectValue;
+        if (v == null || v.valueType != VALUE_LIST) {
+            throw new IllegalArgumentException("Not a list!");
+        }
+        return v.arrayMinLength;
+    }
+
+    public Class<?> getObjectClass(String elementName) {
+        ObjectValue v = findObjectValue(elementName);
+        return v.classType;
+    }
+
+    public Object getObjectDefaultValue(String elementName) {
+        ObjectValue v = findObjectValue(elementName);
+        return v.defaultValue;
+    }
+
+    public Object[] getObjectEnumerations(String elementName) {
+        Element element = findElement(elementName);
+        ObjectValue v = element.objectValue;
+        if (v == null || v.valueType != VALUE_ENUMERATION) {
+            throw new IllegalArgumentException("Not an enumeration!");
+        }
+        return v.enumeratedValues.toArray();
+    }
+
+    public Comparable<?> getObjectMaxValue(String elementName) {
+        Element element = findElement(elementName);
+        ObjectValue v = element.objectValue;
+        if (v == null || (v.valueType & VALUE_RANGE) == 0) {
+            throw new IllegalArgumentException("Not a range!");
+        }
+        return v.maxValue;
+    }
+
+    public Comparable<?> getObjectMinValue(String elementName) {
+        Element element = findElement(elementName);
+        ObjectValue v = element.objectValue;
+        if (v == null || (v.valueType & VALUE_RANGE) == 0) {
+            throw new IllegalArgumentException("Not a range!");
+        }
+        return v.minValue;
+    }
+
+    public int getObjectValueType(String elementName) {
+        Element element = findElement(elementName);
+        if (element.objectValue == null) {
+            return VALUE_NONE;
+        }
+        return element.objectValue.valueType;
+    }
+
+    /**
+     * Gets the resource base name for locating ResourceBundles.
+     * 
+     * @return the current resource base name.
+     */
+    protected String getResourceBaseName() {
+        return resourceBaseName;
+    }
+
+    public String getRootName() {
+        return rootName;
+    }
+
+    /**
+     * Gets the standard format instance.
+     * 
+     * @return the IIOMetadataFormat instance.
+     */
+    public static IIOMetadataFormat getStandardFormatInstance() {
+        if (standardFormat == null) {
+            standardFormat = new IIOStandardMetadataFormat();
+        }
+
+        return standardFormat;
+    }
+
+    public boolean isAttributeRequired(String elementName, String attrName) {
+        return findAttribute(elementName, attrName).required;
+    }
+
+    /**
+     * Removes the specified attribute from the specified element.
+     * 
+     * @param elementName
+     *            the specified element name.
+     * @param attrName
+     *            the specified attribute name.
+     */
+    protected void removeAttribute(String elementName, String attrName) {
+        Element element = findElement(elementName);
+        element.attributes.remove(attrName);
+    }
+
+    /**
+     * Removes the specified element from this format.
+     * 
+     * @param elementName
+     *            the specified element name.
+     */
+    protected void removeElement(String elementName) {
+        Element element;
+        if ((element = elementHash.get(elementName)) != null) {
+            elementHash.remove(elementName);
+            for (Element e : elementHash.values()) {
+                e.children.remove(element.name);
+            }
+        }
+    }
+
+    /**
+     * Removes the object value from the specified element.
+     * 
+     * @param elementName
+     *            the element name.
+     */
+    protected void removeObjectValue(String elementName) {
+        Element element = findElement(elementName);
+        element.objectValue = null;
+    }
+
+    /**
+     * Sets a new base name for ResourceBundles containing descriptions of
+     * elements and attributes for this format.
+     * 
+     * @param resourceBaseName
+     *            the new resource base name.
+     */
+    protected void setResourceBaseName(String resourceBaseName) {
+        if (resourceBaseName == null) {
+            throw new IllegalArgumentException("resourceBaseName == null!");
+        }
+        this.resourceBaseName = resourceBaseName;
+    }
+
+    /**
+     * The Class Element.
+     */
+    @SuppressWarnings( {
+        "ClassWithoutConstructor"
+    })
+    private class Element {
+
+        /**
+         * The name.
+         */
+        String name;
+
+        /**
+         * The children.
+         */
+        ArrayList<String> children = new ArrayList<String>();
+
+        /**
+         * The attributes.
+         */
+        HashMap<String, Attlist> attributes = new HashMap<String, Attlist>();
+
+        /**
+         * The min children.
+         */
+        int minChildren;
+
+        /**
+         * The max children.
+         */
+        int maxChildren;
+
+        /**
+         * The child policy.
+         */
+        int childPolicy;
+
+        /**
+         * The object value.
+         */
+        ObjectValue objectValue;
+    }
+
+    /**
+     * The Class Attlist.
+     */
+    @SuppressWarnings( {
+        "ClassWithoutConstructor"
+    })
+    private class Attlist {
+
+        /**
+         * The name.
+         */
+        String name;
+
+        /**
+         * The data type.
+         */
+        int dataType;
+
+        /**
+         * The required.
+         */
+        boolean required;
+
+        /**
+         * The list min length.
+         */
+        int listMinLength;
+
+        /**
+         * The list max length.
+         */
+        int listMaxLength;
+
+        /**
+         * The default value.
+         */
+        String defaultValue;
+
+        /**
+         * The enumerated values.
+         */
+        List<String> enumeratedValues;
+
+        /**
+         * The min value.
+         */
+        String minValue;
+
+        /**
+         * The max value.
+         */
+        String maxValue;
+
+        /**
+         * The min inclusive.
+         */
+        boolean minInclusive;
+
+        /**
+         * The max inclusive.
+         */
+        boolean maxInclusive;
+
+        /**
+         * The value type.
+         */
+        int valueType;
+    }
+
+    /**
+     * The Class ObjectValue.
+     */
+    @SuppressWarnings( {
+        "ClassWithoutConstructor"
+    })
+    private class ObjectValue<T> {
+
+        /**
+         * The class type.
+         */
+        Class<T> classType;
+
+        /**
+         * The array min length.
+         */
+        int arrayMinLength;
+
+        /**
+         * The array max length.
+         */
+        int arrayMaxLength;
+
+        /**
+         * The default value.
+         */
+        T defaultValue;
+
+        /**
+         * The enumerated values.
+         */
+        List<? extends T> enumeratedValues;
+
+        /**
+         * The min value.
+         */
+        Comparable<? super T> minValue;
+
+        /**
+         * The max value.
+         */
+        Comparable<? super T> maxValue;
+
+        /**
+         * The min inclusive.
+         */
+        boolean minInclusive;
+
+        /**
+         * The max inclusive.
+         */
+        boolean maxInclusive;
+
+        /**
+         * The value type.
+         */
+        int valueType;
+    }
+
+    /**
+     * Find element.
+     * 
+     * @param name
+     *            the name.
+     * @return the element.
+     */
+    private Element findElement(String name) {
+        Element element;
+        if ((element = elementHash.get(name)) == null) {
+            throw new IllegalArgumentException("element name is null or no such element: " + name);
+        }
+
+        return element;
+    }
+
+    /**
+     * Find attribute.
+     * 
+     * @param elementName
+     *            the element name.
+     * @param attributeName
+     *            the attribute name.
+     * @return the attlist.
+     */
+    private Attlist findAttribute(String elementName, String attributeName) {
+        Element element = findElement(elementName);
+        Attlist attribute;
+        if ((attribute = element.attributes.get(attributeName)) == null) {
+            throw new IllegalArgumentException("attribute name is null or no such attribute: "
+                    + attributeName);
+        }
+
+        return attribute;
+    }
+
+    /**
+     * Find object value.
+     * 
+     * @param elementName
+     *            the element name.
+     * @return the object value.
+     */
+    private ObjectValue findObjectValue(String elementName) {
+        Element element = findElement(elementName);
+        ObjectValue v = element.objectValue;
+        if (v == null) {
+            throw new IllegalArgumentException("No object within element");
+        }
+        return v;
+    }
+
+    /**
+     * Gets the resource string.
+     * 
+     * @param key
+     *            the key.
+     * @param locale
+     *            the locale.
+     * @return the resource string.
+     */
+    private String getResourceString(String key, Locale locale) {
+        if (locale == null) {
+            locale = Locale.getDefault();
+        }
+
+        // Get the context class loader and try to locate the bundle with it
+        // first
+        ClassLoader contextClassloader = AccessController
+                .doPrivileged(new PrivilegedAction<ClassLoader>() {
+                    public ClassLoader run() {
+                        return Thread.currentThread().getContextClassLoader();
+                    }
+                });
+
+        // Now try to get the resource bundle
+        ResourceBundle rb;
+        try {
+            rb = ResourceBundle.getBundle(resourceBaseName, locale, contextClassloader);
+        } catch (MissingResourceException e) {
+            try {
+                rb = ResourceBundle.getBundle(resourceBaseName, locale);
+            } catch (MissingResourceException e1) {
+                return null;
+            }
+        }
+
+        try {
+            return rb.getString(key);
+        } catch (MissingResourceException e) {
+            return null;
+        } catch (ClassCastException e) {
+            return null; // Not a string resource
+        }
+    }
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadataNode.java b/awt/javax/imageio/metadata/IIOMetadataNode.java
new file mode 100644
index 0000000..adc6d67
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadataNode.java
@@ -0,0 +1,1070 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.metadata;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+//???AWT
+//import org.w3c.dom.TypeInfo;
+//import org.w3c.dom.UserDataHandler;
+
+/**
+ * The Class IIOMetadataNode represents a node of the (DOM-style) metadata tree.
+ * 
+ * @since Android 1.0
+ */
+public class IIOMetadataNode implements Element, NodeList {
+
+    /**
+     * The node name.
+     */
+    private String nodeName;
+
+    /**
+     * The node value.
+     */
+    private String nodeValue;
+
+    /**
+     * The attributes.
+     */
+    private IIOMetadataNodeList attrs = new IIOMetadataNodeList(new ArrayList<IIOMetadataNode>());
+
+    /**
+     * The parent node.
+     */
+    private IIOMetadataNode parent;
+
+    /**
+     * The first child node.
+     */
+    private IIOMetadataNode firstChild;
+
+    /**
+     * The last child node.
+     */
+    private IIOMetadataNode lastChild;
+
+    /**
+     * The previous sibling.
+     */
+    private IIOMetadataNode previousSibling;
+
+    /**
+     * The next sibling.
+     */
+    private IIOMetadataNode nextSibling;
+
+    /**
+     * The number of children.
+     */
+    private int nChildren;
+
+    /**
+     * The user object associated with this node.
+     */
+    private Object userObject;
+
+    /**
+     * The text content of this node.
+     */
+    private String textContent;
+
+    /**
+     * Instantiates a new empty node.
+     */
+    public IIOMetadataNode() {
+    }
+
+    /**
+     * Instantiates a new empty node with the specified name.
+     * 
+     * @param nodeName
+     *            the node name.
+     */
+    public IIOMetadataNode(String nodeName) {
+        this.nodeName = nodeName;
+    }
+
+    /**
+     * Instantiates a new IIOMetadataNode with the specified name and value.
+     * 
+     * @param nodeName
+     *            the node name.
+     * @param nodeValue
+     *            the node value.
+     */
+    private IIOMetadataNode(String nodeName, String nodeValue) {
+        this.nodeName = nodeName;
+        this.nodeValue = nodeValue;
+    }
+
+    public String getTagName() {
+        return nodeName;
+    }
+
+    public String getAttribute(String name) {
+        Attr attrNode = (Attr)attrs.getNamedItem(name);
+        return (attrNode == null) ? "" : attrNode.getValue();
+    }
+
+    public void setAttribute(String name, String value) throws DOMException {
+        Attr attr = (Attr)attrs.getNamedItem(name);
+        if (attr != null) {
+            attr.setValue(value);
+        } else {
+            attrs.list.add(new IIOMetadataAttr(name, value, this));
+        }
+    }
+
+    public void removeAttribute(String name) throws DOMException {
+        IIOMetadataAttr attr = (IIOMetadataAttr)attrs.getNamedItem(name);
+        if (attr != null) {
+            attr.setOwnerElement(null);
+            attrs.list.remove(attr);
+        }
+    }
+
+    public Attr getAttributeNode(String name) {
+        return (Attr)attrs.getNamedItem(name);
+    }
+
+    public Attr setAttributeNode(Attr newAttr) throws DOMException {
+        // Check if this attribute is already in use.
+        Element owner = newAttr.getOwnerElement();
+        if (owner != null) {
+            if (owner == this) { // Replacing an attribute node by itself has no
+                // effect
+                return null;
+            } else {
+                throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR,
+                        "Attribute is already in use");
+            }
+        }
+
+        String name = newAttr.getName();
+        Attr oldAttr = getAttributeNode(name);
+        if (oldAttr != null) {
+            removeAttributeNode(oldAttr);
+        }
+
+        IIOMetadataAttr iioAttr;
+        if (newAttr instanceof IIOMetadataAttr) {
+            iioAttr = (IIOMetadataAttr)newAttr;
+            iioAttr.setOwnerElement(this);
+        } else {
+            iioAttr = new IIOMetadataAttr(name, newAttr.getValue(), this);
+        }
+
+        attrs.list.add(iioAttr);
+
+        return oldAttr;
+    }
+
+    public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
+        if (!attrs.list.remove(oldAttr)) { // Not found
+            throw new DOMException(DOMException.NOT_FOUND_ERR, "No such attribute!");
+        }
+
+        ((IIOMetadataAttr)oldAttr).setOwnerElement(null);
+
+        return oldAttr;
+    }
+
+    public NodeList getElementsByTagName(String name) {
+        ArrayList<IIOMetadataNode> nodes = new ArrayList<IIOMetadataNode>();
+
+        // Non-recursive tree walk
+        Node pos = this;
+
+        while (pos != null) {
+            if (pos.getNodeName().equals(name)) {
+                nodes.add((IIOMetadataNode)pos);
+            }
+
+            Node nextNode = pos.getFirstChild();
+
+            while (nextNode == null) {
+                if (pos == this) {
+                    break;
+                }
+
+                nextNode = pos.getNextSibling();
+
+                if (nextNode == null) {
+                    pos = pos.getParentNode();
+
+                    if (pos == null || pos == this) {
+                        nextNode = null;
+                        break;
+                    }
+                }
+            }
+            pos = nextNode;
+        }
+
+        return new IIOMetadataNodeList(nodes);
+    }
+
+    public String getAttributeNS(String namespaceURI, String localName) throws DOMException {
+        return getAttribute(localName);
+    }
+
+    public void setAttributeNS(String namespaceURI, String qualifiedName, String value)
+            throws DOMException {
+        setAttribute(qualifiedName, value);
+    }
+
+    public void removeAttributeNS(String namespaceURI, String localName) throws DOMException {
+        removeAttribute(localName);
+    }
+
+    public Attr getAttributeNodeNS(String namespaceURI, String localName) throws DOMException {
+        return getAttributeNode(localName);
+    }
+
+    public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
+        return setAttributeNode(newAttr);
+    }
+
+    public NodeList getElementsByTagNameNS(String namespaceURI, String localName)
+            throws DOMException {
+        return getElementsByTagName(localName);
+    }
+
+    public boolean hasAttribute(String name) {
+        return attrs.getNamedItem(name) != null;
+    }
+
+    public boolean hasAttributeNS(String namespaceURI, String localName) throws DOMException {
+        return hasAttribute(localName);
+    }
+
+    // ???AWT
+    /*
+     * public TypeInfo getSchemaTypeInfo() { throw new
+     * DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); }
+     */
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Element (DOM Level
+     * 3)</i>
+     * <p>
+     * If the parameter isId is true, this method declares the specified
+     * attribute to be a user-determined ID attribute . This affects the value
+     * of Attr.isId and the behavior of Document.getElementById, but does not
+     * change any schema that may be in use, in particular this does not affect
+     * the Attr.schemaTypeInfo of the specified Attr node. Use the value false
+     * for the parameter isId to undeclare an attribute for being a
+     * user-determined ID attribute. To specify an attribute by local name and
+     * namespace URI, use the setIdAttributeNS method.
+     * </p>
+     * 
+     * @param name
+     *            the name of the attribute.
+     * @param isId
+     *            the flag which determines whether this attribute is of type
+     *            ID.
+     * @throws DOMException
+     *             if a DOM error occurred while setting the attribute type.
+     *             <p>
+     *             NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     *             <br>
+     *             NOT_FOUND_ERR: Raised if the specified node is not an
+     *             attribute of this element.
+     *             </p>
+     */
+    public void setIdAttribute(String name, boolean isId) throws DOMException {
+        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+    }
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Element (DOM Level
+     * 3)</i>
+     * <p>
+     * If the parameter isId is true, this method declares the specified
+     * attribute to be a user-determined ID attribute . This affects the value
+     * of Attr.isId and the behavior of Document.getElementById, but does not
+     * change any schema that may be in use, in particular this does not affect
+     * the Attr.schemaTypeInfo of the specified Attr node. Use the value false
+     * for the parameter isId to undeclare an attribute for being a
+     * user-determined ID attribute.
+     * </p>
+     * 
+     * @param namespaceURI
+     *            the namespace URI of the attribute.
+     * @param localName
+     *            the local name of the attribute.
+     * @param isId
+     *            the flag which determines whether this attribute is of type
+     *            ID.
+     * @throws DOMException
+     *             if a DOM error occurred while setting the attribute type.
+     *             <p>
+     *             NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     *             <br>
+     *             NOT_FOUND_ERR: Raised if the specified node is not an
+     *             attribute of this element.
+     *             </p>
+     */
+    public void setIdAttributeNS(String namespaceURI, String localName, boolean isId)
+            throws DOMException {
+        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+    }
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Element (DOM Level
+     * 3)</i>
+     * <p>
+     * If the parameter isId is true, this method declares the specified
+     * attribute to be a user-determined ID attribute . This affects the value
+     * of Attr.isId and the behavior of Document.getElementById, but does not
+     * change any schema that may be in use, in particular this does not affect
+     * the Attr.schemaTypeInfo of the specified Attr node. Use the value false
+     * for the parameter isId to undeclare an attribute for being a
+     * user-determined ID attribute.
+     * </p>
+     * 
+     * @param idAttr
+     *            the attribute node.
+     * @param isId
+     *            the flag which determines whether this attribute is of type
+     *            ID.
+     * @throws DOMException
+     *             if a DOM error occurred while setting the attribute type.
+     *             <p>
+     *             NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     *             <br>
+     *             NOT_FOUND_ERR: Raised if the specified node is not an
+     *             attribute of this element.
+     *             </p>
+     */
+    public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException {
+        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+    }
+
+    public String getNodeName() {
+        return nodeName;
+    }
+
+    public String getNodeValue() throws DOMException {
+        return nodeValue;
+    }
+
+    public void setNodeValue(String nodeValue) throws DOMException {
+        this.nodeValue = nodeValue;
+    }
+
+    public short getNodeType() {
+        return ELEMENT_NODE;
+    }
+
+    public Node getParentNode() {
+        return parent;
+    }
+
+    public NodeList getChildNodes() {
+        return this;
+    }
+
+    public Node getFirstChild() {
+        return firstChild;
+    }
+
+    public Node getLastChild() {
+        return lastChild;
+    }
+
+    public Node getPreviousSibling() {
+        return previousSibling;
+    }
+
+    public Node getNextSibling() {
+        return nextSibling;
+    }
+
+    public NamedNodeMap getAttributes() {
+        return attrs;
+    }
+
+    public Document getOwnerDocument() {
+        return null;
+    }
+
+    public Node insertBefore(Node newChild, Node refChild) throws DOMException {
+        if (newChild == null) {
+            throw new IllegalArgumentException("newChild == null!");
+        }
+
+        IIOMetadataNode newIIOChild = (IIOMetadataNode)newChild;
+        IIOMetadataNode refIIOChild = (IIOMetadataNode)refChild;
+
+        newIIOChild.parent = this;
+
+        if (refIIOChild == null) {
+            newIIOChild.nextSibling = null;
+            newIIOChild.previousSibling = lastChild;
+
+            // Fix this node
+            lastChild = newIIOChild;
+            if (firstChild == null) {
+                firstChild = newIIOChild;
+            }
+        } else {
+            newIIOChild.nextSibling = refIIOChild;
+            newIIOChild.previousSibling = refIIOChild.previousSibling;
+
+            // Fix this node
+            if (firstChild == refIIOChild) {
+                firstChild = newIIOChild;
+            }
+
+            // Fix next node
+            if (refIIOChild != null) {
+                refIIOChild.previousSibling = newIIOChild;
+            }
+        }
+
+        // Fix prev node
+        if (newIIOChild.previousSibling != null) {
+            newIIOChild.previousSibling.nextSibling = newIIOChild;
+        }
+
+        nChildren++;
+
+        return newIIOChild;
+    }
+
+    public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
+        if (newChild == null) {
+            throw new IllegalArgumentException("newChild == null!");
+        }
+
+        IIOMetadataNode newIIOChild = (IIOMetadataNode)newChild;
+        IIOMetadataNode oldIIOChild = (IIOMetadataNode)oldChild;
+
+        IIOMetadataNode next = oldIIOChild.nextSibling;
+        IIOMetadataNode previous = oldIIOChild.previousSibling;
+
+        // Fix new node
+        newIIOChild.parent = this;
+        newIIOChild.nextSibling = next;
+        newIIOChild.previousSibling = previous;
+
+        // Fix this node
+        if (lastChild == oldIIOChild) {
+            lastChild = newIIOChild;
+        }
+        if (firstChild == oldIIOChild) {
+            firstChild = newIIOChild;
+        }
+
+        // Fix siblings
+        if (next != null) {
+            next.previousSibling = newIIOChild;
+        }
+        if (previous != null) {
+            previous.nextSibling = newIIOChild;
+        }
+
+        // Fix old child
+        oldIIOChild.parent = null;
+        oldIIOChild.nextSibling = next;
+        oldIIOChild.previousSibling = previous;
+
+        return oldIIOChild;
+    }
+
+    public Node removeChild(Node oldChild) throws DOMException {
+        if (oldChild == null) {
+            throw new IllegalArgumentException("oldChild == null!");
+        }
+
+        IIOMetadataNode oldIIOChild = (IIOMetadataNode)oldChild;
+
+        // Fix next and previous
+        IIOMetadataNode previous = oldIIOChild.previousSibling;
+        IIOMetadataNode next = oldIIOChild.nextSibling;
+
+        if (previous != null) {
+            previous.nextSibling = next;
+        }
+        if (next != null) {
+            next.previousSibling = previous;
+        }
+
+        // Fix this node
+        if (lastChild == oldIIOChild) {
+            lastChild = previous;
+        }
+        if (firstChild == oldIIOChild) {
+            firstChild = next;
+        }
+        nChildren--;
+
+        // Fix old child
+        oldIIOChild.parent = null;
+        oldIIOChild.previousSibling = null;
+        oldIIOChild.nextSibling = null;
+
+        return oldIIOChild;
+    }
+
+    public Node appendChild(Node newChild) throws DOMException {
+        return insertBefore(newChild, null);
+    }
+
+    public boolean hasChildNodes() {
+        return nChildren != 0;
+    }
+
+    public Node cloneNode(boolean deep) {
+        IIOMetadataNode cloned = new IIOMetadataNode(nodeName);
+        cloned.setUserObject(getUserObject());
+
+        if (deep) { // Clone recursively
+            IIOMetadataNode c = firstChild;
+            while (c != null) {
+                cloned.insertBefore(c.cloneNode(true), null);
+                c = c.nextSibling;
+            }
+        }
+
+        return cloned; // To change body of implemented methods use File |
+        // Settings | File Templates.
+    }
+
+    public void normalize() {
+        // Do nothing
+    }
+
+    public boolean isSupported(String feature, String version) {
+        return false;
+    }
+
+    public String getNamespaceURI() {
+        return null;
+    }
+
+    public String getPrefix() {
+        return null;
+    }
+
+    public void setPrefix(String prefix) throws DOMException {
+        // Do nothing
+    }
+
+    public String getLocalName() {
+        return nodeName;
+    }
+
+    public boolean hasAttributes() {
+        return attrs.list.size() > 0;
+    }
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
+     * <p>
+     * The absolute base URI of this node or null if the implementation wasn't
+     * able to obtain an absolute URI. This value is computed as described in.
+     * However, when the Document supports the feature "HTML" [DOM Level 2
+     * HTML], the base URI is computed using first the value of the href
+     * attribute of the HTML BASE element if any, and the value of the
+     * documentURI attribute from the Document interface otherwise.
+     * </p>
+     * 
+     * @return the string representation of the absolute base URI.
+     */
+    public String getBaseURI() {
+        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+    }
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
+     * <p>
+     * Compares the reference node, i.e. the node on which this method is being
+     * called, with a node, i.e. the one passed as a parameter, with regard to
+     * their position in the document and according to the document order.
+     * </p>
+     * 
+     * @param other
+     *            the node to compare against the reference node.
+     * @return Returns how the node is positioned relatively to the reference
+     *         node.
+     * @throws DOMException
+     *             NOT_SUPPORTED_ERR: when the compared nodes are from different
+     *             DOM implementations that do not coordinate to return
+     *             consistent implementation-specific results.
+     */
+    public short compareDocumentPosition(Node other) throws DOMException {
+        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+    }
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
+     * <p>
+     * This attribute returns the text content of this node and its descendants.
+     * When it is defined to be null, setting it has no effect. On setting, any
+     * possible children this node may have are removed and, if it the new
+     * string is not empty or null, replaced by a single Text node containing
+     * the string this attribute is set to. On getting, no serialization is
+     * performed, the returned string does not contain any markup. No whitespace
+     * normalization is performed and the returned string does not contain the
+     * white spaces in element content (see the attribute
+     * Text.isElementContentWhitespace). Similarly, on setting, no parsing is
+     * performed either, the input string is taken as pure textual content. The
+     * string returned is made of the text content of this node depending on its
+     * type, as defined below:
+     * <table>
+     * <tr>
+     * <td><strong>Node type</strong></td>
+     * <td><strong>Content</strong></td>
+     * </tr>
+     * <tr>
+     * <td>ELEMENT_NODE, ATTRIBUTE_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
+     * DOCUMENT_FRAGMENT_NODE</td>
+     * <td>concatenation of the textContent attribute value of every child node,
+     * excluding COMMENT_NODE and PROCESSING_INSTRUCTION_NODE nodes. This is the
+     * empty string if the node has no children.</td>
+     * </tr>
+     * <tr>
+     * <td>TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE,
+     * PROCESSING_INSTRUCTION_NODE</td>
+     * <td>nodeValue</td>
+     * </tr>
+     * <tr>
+     * <td>DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
+     * <td>null</td>
+     * </tr>
+     * </table>
+     * </p>
+     * 
+     * @return the text content depending on the type of this node.
+     * @throws DOMException
+     *             DOMSTRING_SIZE_ERR: Raised when it would return more
+     *             characters than fit in a DOMString variable on the
+     *             implementation platform.
+     */
+    public String getTextContent() throws DOMException {
+        return textContent;
+    }
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
+     * <p>
+     * This attribute returns the text content of this node and its descendants.
+     * When it is defined to be null, setting it has no effect. On setting, any
+     * possible children this node may have are removed and, if it the new
+     * string is not empty or null, replaced by a single Text node containing
+     * the string this attribute is set to. On getting, no serialization is
+     * performed, the returned string does not contain any markup. No whitespace
+     * normalization is performed and the returned string does not contain the
+     * white spaces in element content (see the attribute
+     * Text.isElementContentWhitespace). Similarly, on setting, no parsing is
+     * performed either, the input string is taken as pure textual content. The
+     * string returned is made of the text content of this node depending on its
+     * type, as defined below:
+     * <table>
+     * <tr>
+     * <td><strong>Node type</strong></td>
+     * <td><strong>Content</strong></td>
+     * </tr>
+     * <tr>
+     * <td>ELEMENT_NODE, ATTRIBUTE_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
+     * DOCUMENT_FRAGMENT_NODE</td>
+     * <td>concatenation of the textContent attribute value of every child node,
+     * excluding COMMENT_NODE and PROCESSING_INSTRUCTION_NODE nodes. This is the
+     * empty string if the node has no children.</td>
+     * </tr>
+     * <tr>
+     * <td>TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE,
+     * PROCESSING_INSTRUCTION_NODE</td>
+     * <td>nodeValue</td>
+     * </tr>
+     * <tr>
+     * <td>DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
+     * <td>null</td>
+     * </tr>
+     * </table>
+     * </p>
+     * 
+     * @param textContent
+     *            the text content for this node.
+     * @throws DOMException
+     *             NO_MODIFICATION_ALLOWED_ERR: Raised when the node is
+     *             readonly.
+     */
+    public void setTextContent(String textContent) throws DOMException {
+        this.textContent = textContent;
+    }
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
+     * <p>
+     * Returns whether this node is the same node as the given one. This method
+     * provides a way to determine whether two Node references returned by the
+     * implementation reference the same object. When two Node references are
+     * references to the same object, even if through a proxy, the references
+     * may be used completely interchangeably, such that all attributes have the
+     * same values and calling the same DOM method on either reference always
+     * has exactly the same effect.
+     * </p>
+     * 
+     * @param other
+     *            the node to test against.
+     * @return true, if the nodes are the same, false otherwise.
+     */
+    public boolean isSameNode(Node other) {
+        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+    }
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
+     * <p>
+     * Look up the prefix associated to the given namespace URI, starting from
+     * this node. The default namespace declarations are ignored by this method.
+     * See for details on the algorithm used by this method.
+     * </p>
+     * 
+     * @param namespaceURI
+     *            the namespace URI to look for.
+     * @return the associated namespace prefix if found or null if none is
+     *         found. If more than one prefix are associated to the namespace
+     *         prefix, the returned namespace prefix is implementation
+     *         dependent.
+     */
+    public String lookupPrefix(String namespaceURI) {
+        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+    }
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
+     * <p>
+     * This method checks if the specified namespaceURI is the default namespace
+     * or not.
+     * </p>
+     * 
+     * @param namespaceURI
+     *            the namespace URI to look for.
+     * @return true, if the specified namespaceURI is the default namespace,
+     *         false otherwise.
+     */
+    public boolean isDefaultNamespace(String namespaceURI) {
+        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+    }
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
+     * <p>
+     * Look up the namespace URI associated to the given prefix, starting from
+     * this node. See for details on the algorithm used by this method.
+     * </p>
+     * 
+     * @param prefix
+     *            the prefix to look for. If this parameter is null, the method
+     *            will return the default namespace URI if any.
+     * @return the associated namespace URI or null if none is found.
+     */
+    public String lookupNamespaceURI(String prefix) {
+        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+    }
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
+     * <p>
+     * Tests whether two nodes are equal. This method tests for equality of
+     * nodes, not sameness (i.e., whether the two nodes are references to the
+     * same object) which can be tested with Node.isSameNode(). All nodes that
+     * are the same will also be equal, though the reverse may not be true. Two
+     * nodes are equal if and only if the following conditions are satisfied:
+     * <p>
+     * <li>The two nodes are of the same type.</li>
+     * <li>The following string attributes are equal: nodeName, localName,
+     * namespaceURI, prefix, nodeValue . This is: they are both null, or they
+     * have the same length and are character for character identical.</li>
+     * <li>The attributes NamedNodeMaps are equal. This is: they are both null,
+     * or they have the same length and for each node that exists in one map
+     * there is a node that exists in the other map and is equal, although not
+     * necessarily at the same index.</li>
+     * <li>The childNodes NodeLists are equal. This is: they are both null, or
+     * they have the same length and contain equal nodes at the same index. Note
+     * that normalization can affect equality; to avoid this, nodes should be
+     * normalized before being compared.</li>
+     * </p>
+     * For two DocumentType nodes to be equal, the following conditions must
+     * also be satisfied:
+     * <p>
+     * <li>The following string attributes are equal: publicId, systemId,
+     * internalSubset.</li>
+     * <li>The entities NamedNodeMaps are equal.</li>
+     * <li>The notations NamedNodeMaps are equal.</li>
+     * </p>
+     * On the other hand, the following do not affect equality: the
+     * ownerDocument, baseURI, and parentNode attributes, the specified
+     * attribute for Attr nodes, the schemaTypeInfo attribute for Attr and
+     * Element nodes, the Text.isElementContentWhitespace attribute for Text
+     * nodes, as well as any user data or event listeners registered on the
+     * nodes. </p>
+     * <p>
+     * Note: As a general rule, anything not mentioned in the description above
+     * is not significant in consideration of equality checking. Note that
+     * future versions of this specification may take into account more
+     * attributes and implementations conform to this specification are expected
+     * to be updated accordingly.
+     * </p>
+     * 
+     * @param arg
+     *            the node to compare equality with.
+     * @return true, if the nodes are equal, false otherwise.
+     */
+    public boolean isEqualNode(Node arg) {
+        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+    }
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
+     * <p>
+     * This method returns a specialized object which implements the specialized
+     * APIs of the specified feature and version, as specified in. The
+     * specialized object may also be obtained by using binding-specific casting
+     * methods but is not necessarily expected to, as discussed in. This method
+     * also allow the implementation to provide specialized objects which do not
+     * support the Node interface.
+     * </p>
+     * 
+     * @param feature
+     *            the name of the feature requested. Note that any plus sign "+"
+     *            prepended to the name of the feature will be ignored since it
+     *            is not significant in the context of this method.
+     * @param version
+     *            this is the version number of the feature to test.
+     * @return the object which implements the specialized APIs of the specified
+     *         feature and version, if any, or null if there is no object which
+     *         implements interfaces associated with that feature. If the
+     *         DOMObject returned by this method implements the Node interface,
+     *         it must delegate to the primary core Node and not return results
+     *         inconsistent with the primary core Node such as attributes,
+     *         childNodes, etc.
+     */
+    public Object getFeature(String feature, String version) {
+        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+    }
+
+    // ???AWT
+    /*
+     * public Object setUserData(String key, Object data, UserDataHandler
+     * handler) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+     * "Method not supported"); }
+     */
+
+    /**
+     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
+     * <p>
+     * Retrieves the object associated to a key on a this node. The object must
+     * first have been set to this node by calling setUserData with the same
+     * key.
+     * </p>
+     * 
+     * @param key
+     *            the key the object is associated to.
+     * @return the DOMUserData associated to the given key on this node, or null
+     *         if there was none.
+     */
+    public Object getUserData(String key) {
+        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+    }
+
+    public Node item(int index) {
+        if (index < 0 || index >= nChildren) {
+            return null;
+        }
+
+        Node n;
+        for (n = getFirstChild(); index > 0; index--) {
+            n = n.getNextSibling();
+        }
+
+        return n;
+    }
+
+    public int getLength() {
+        return nChildren;
+    }
+
+    /**
+     * Gets the user object associated with this node.
+     * 
+     * @return the user object associated with this node.
+     */
+    public Object getUserObject() {
+        return userObject;
+    }
+
+    /**
+     * Sets the user object associated with this node.
+     * 
+     * @param userObject
+     *            the new user object associated with this node.
+     */
+    public void setUserObject(Object userObject) {
+        this.userObject = userObject;
+    }
+
+    /**
+     * The Class IIOMetadataAttr.
+     */
+    private class IIOMetadataAttr extends IIOMetadataNode implements Attr {
+
+        /**
+         * The owner element.
+         */
+        private Element ownerElement;
+
+        /**
+         * Instantiates a new iIO metadata attr.
+         * 
+         * @param name
+         *            the name.
+         * @param value
+         *            the value.
+         * @param owner
+         *            the owner.
+         */
+        public IIOMetadataAttr(String name, String value, Element owner) {
+            super(name, value);
+            this.ownerElement = owner;
+        }
+
+        public String getName() {
+            return getNodeName();
+        }
+
+        public boolean getSpecified() {
+            return true;
+        }
+
+        public String getValue() {
+            return nodeValue;
+        }
+
+        public void setValue(String value) throws DOMException {
+            nodeValue = value;
+        }
+
+        public Element getOwnerElement() {
+            return ownerElement;
+        }
+
+        /**
+         * Sets the owner element.
+         * 
+         * @param ownerElement
+         *            the new owner element.
+         */
+        public void setOwnerElement(Element ownerElement) {
+            this.ownerElement = ownerElement;
+        }
+
+        /**
+         * @return
+         */
+        public boolean isId() {
+            throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+        }
+
+        @Override
+        public short getNodeType() {
+            return ATTRIBUTE_NODE;
+        }
+    }
+
+    /**
+     * The Class IIOMetadataNodeList.
+     */
+    private class IIOMetadataNodeList implements NodeList, NamedNodeMap {
+
+        /**
+         * The list.
+         */
+        private List<IIOMetadataNode> list;
+
+        /**
+         * Instantiates a new iIO metadata node list.
+         * 
+         * @param list
+         *            the list.
+         */
+        IIOMetadataNodeList(List<IIOMetadataNode> list) {
+            this.list = list;
+        }
+
+        public Node item(int index) {
+            try {
+                return list.get(index);
+            } catch (IndexOutOfBoundsException e) {
+                return null;
+            }
+        }
+
+        public int getLength() {
+            return list.size();
+        }
+
+        public Node getNamedItem(String name) {
+            for (IIOMetadataNode node : list) {
+                if (name.equals(node.getNodeName())) {
+                    return node;
+                }
+            }
+            return null;
+        }
+
+        public Node setNamedItem(Node arg) throws DOMException {
+            throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
+                    "This NamedNodeMap is read-only!");
+        }
+
+        public Node removeNamedItem(String name) throws DOMException {
+            throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
+                    "This NamedNodeMap is read-only!");
+        }
+
+        public Node getNamedItemNS(String namespaceURI, String localName) throws DOMException {
+            return getNamedItem(localName);
+        }
+
+        public Node setNamedItemNS(Node arg) throws DOMException {
+            throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
+                    "This NamedNodeMap is read-only!");
+        }
+
+        public Node removeNamedItemNS(String namespaceURI, String localName) throws DOMException {
+            throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
+                    "This NamedNodeMap is read-only!");
+        }
+    }
+}
diff --git a/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java b/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java
new file mode 100644
index 0000000..706cb2f
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java
@@ -0,0 +1,297 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.metadata;
+
+import javax.imageio.ImageTypeSpecifier;
+import java.util.ArrayList;
+
+/**
+ * The class IIOStandardMetadataFormat describes the rules of the standard
+ * metadata format.
+ * 
+ * @since Android 1.0
+ */
+class IIOStandardMetadataFormat extends IIOMetadataFormatImpl {
+
+    /**
+     * Instantiates a new IIOStandardMetadataFormat.
+     */
+    public IIOStandardMetadataFormat() {
+        super(standardMetadataFormatName, CHILD_POLICY_SOME);
+        buildDTD();
+    }
+
+    @Override
+    public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) {
+        return true;
+    }
+
+    /**
+     * Builds the DTD that describes the standard metadata format.
+     */
+    private void buildDTD() {
+        // CHROMA
+        addElement("Chroma", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+        addElement("ColorSpaceType", "Chroma", CHILD_POLICY_EMPTY);
+
+        ArrayList<String> values = new ArrayList<String>(27);
+        values.add("XYZ");
+        values.add("Lab");
+        values.add("Luv");
+        values.add("YCbCr");
+        values.add("Yxy");
+        values.add("YCCK");
+        values.add("PhotoYCC");
+        values.add("RGB");
+        values.add("GRAY");
+        values.add("HSV");
+        values.add("HLS");
+        values.add("CMYK");
+        values.add("CMY");
+        values.add("2CLR");
+        values.add("3CLR");
+        values.add("4CLR");
+        values.add("5CLR");
+        values.add("6CLR");
+        values.add("7CLR");
+        values.add("8CLR");
+        values.add("9CLR");
+        values.add("ACLR");
+        values.add("BCLR");
+        values.add("CCLR");
+        values.add("DCLR");
+        values.add("ECLR");
+        values.add("FCLR");
+        addAttribute("ColorSpaceType", "name", DATATYPE_STRING, true, null, values);
+
+        addElement("NumChannels", "Chroma", CHILD_POLICY_EMPTY);
+        addAttribute("NumChannels", "value", DATATYPE_INTEGER, true, 0, Integer.MAX_VALUE); // list
+        // -
+        // why
+        // ?
+
+        addElement("Gamma", "Chroma", CHILD_POLICY_EMPTY);
+        addAttribute("Gamma", "value", DATATYPE_FLOAT, true, null);
+
+        addElement("BlackIsZero", "Chroma", CHILD_POLICY_EMPTY);
+        addBooleanAttribute("BlackIsZero", "value", true, true);
+
+        addElement("Palette", "Chroma", 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT
+        addElement("PaletteEntry", "Palette", CHILD_POLICY_EMPTY);
+        addAttribute("PaletteEntry", "index", DATATYPE_INTEGER, true, null);
+        addAttribute("PaletteEntry", "red", DATATYPE_INTEGER, true, null);
+        addAttribute("PaletteEntry", "green", DATATYPE_INTEGER, true, null);
+        addAttribute("PaletteEntry", "blue", DATATYPE_INTEGER, true, null);
+        addAttribute("PaletteEntry", "alpha", DATATYPE_INTEGER, false, "255");
+
+        addElement("BackgroundIndex", "Chroma", CHILD_POLICY_EMPTY);
+        addAttribute("BackgroundIndex", "value", DATATYPE_INTEGER, true, null);
+
+        addElement("BackgroundColor", "Chroma", CHILD_POLICY_EMPTY);
+        addAttribute("BackgroundColor", "red", DATATYPE_INTEGER, true, null);
+        addAttribute("BackgroundColor", "green", DATATYPE_INTEGER, true, null);
+        addAttribute("BackgroundColor", "blue", DATATYPE_INTEGER, true, null);
+
+        // COMPRESSION
+        addElement("Compression", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+        addElement("CompressionTypeName", "Compression", CHILD_POLICY_EMPTY);
+        addAttribute("CompressionTypeName", "value", DATATYPE_STRING, true, null);
+
+        addElement("Lossless", "Compression", CHILD_POLICY_EMPTY);
+        addBooleanAttribute("Lossless", "value", true, true);
+
+        addElement("NumProgressiveScans", "Compression", CHILD_POLICY_EMPTY);
+        addAttribute("NumProgressiveScans", "value", DATATYPE_INTEGER, true, null);
+
+        addElement("BitRate", "Compression", CHILD_POLICY_EMPTY);
+        addAttribute("BitRate", "value", DATATYPE_FLOAT, true, null);
+
+        // DATA
+        addElement("Data", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+        addElement("PlanarConfiguration", "Data", CHILD_POLICY_EMPTY);
+        values = new ArrayList<String>(4);
+        values.add("PixelInterleaved");
+        values.add("PlaneInterleaved");
+        values.add("LineInterleaved");
+        values.add("TileInterleaved");
+        addAttribute("PlanarConfiguration", "value", DATATYPE_STRING, true, null, values);
+
+        addElement("SampleFormat", "Data", CHILD_POLICY_EMPTY);
+        values = new ArrayList<String>(4);
+        values.add("SignedIntegral");
+        values.add("UnsignedIntegral");
+        values.add("Real");
+        values.add("Index");
+        addAttribute("SampleFormat", "value", DATATYPE_STRING, true, null, values);
+
+        addElement("BitsPerSample", "Data", CHILD_POLICY_EMPTY);
+        addAttribute("BitsPerSample", "value", DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE); // list
+
+        addElement("SignificantBitsPerSample", "Data", CHILD_POLICY_EMPTY);
+        addAttribute("SignificantBitsPerSample", "value", DATATYPE_INTEGER, true, 1,
+                Integer.MAX_VALUE); // list
+
+        addElement("SampleMSB", "Data", CHILD_POLICY_EMPTY);
+        addAttribute("SampleMSB", "value", DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE); // list
+
+        // DIMENSION
+        addElement("Dimension", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+        addElement("PixelAspectRatio", "Dimension", CHILD_POLICY_EMPTY);
+        addAttribute("PixelAspectRatio", "value", DATATYPE_FLOAT, true, null);
+
+        addElement("ImageOrientation", "Dimension", CHILD_POLICY_EMPTY);
+        values = new ArrayList<String>(8);
+        values.add("Normal");
+        values.add("Rotate90");
+        values.add("Rotate180");
+        values.add("Rotate270");
+        values.add("FlipH");
+        values.add("FlipV");
+        values.add("FlipHRotate90");
+        values.add("FlipVRotate90");
+        addAttribute("ImageOrientation", "value", DATATYPE_STRING, true, null, values);
+
+        addElement("HorizontalPixelSize", "Dimension", CHILD_POLICY_EMPTY);
+        addAttribute("HorizontalPixelSize", "value", DATATYPE_FLOAT, true, null);
+
+        addElement("VerticalPixelSize", "Dimension", CHILD_POLICY_EMPTY);
+        addAttribute("VerticalPixelSize", "value", DATATYPE_FLOAT, true, null);
+
+        addElement("HorizontalPhysicalPixelSpacing", "Dimension", CHILD_POLICY_EMPTY);
+        addAttribute("HorizontalPhysicalPixelSpacing", "value", DATATYPE_FLOAT, true, null);
+
+        addElement("VerticalPhysicalPixelSpacing", "Dimension", CHILD_POLICY_EMPTY);
+        addAttribute("VerticalPhysicalPixelSpacing", "value", DATATYPE_FLOAT, true, null);
+
+        addElement("HorizontalPosition", "Dimension", CHILD_POLICY_EMPTY);
+        addAttribute("HorizontalPosition", "value", DATATYPE_FLOAT, true, null);
+
+        addElement("VerticalPosition", "Dimension", CHILD_POLICY_EMPTY);
+        addAttribute("VerticalPosition", "value", DATATYPE_FLOAT, true, null);
+
+        addElement("HorizontalPixelOffset", "Dimension", CHILD_POLICY_EMPTY);
+        addAttribute("HorizontalPixelOffset", "value", DATATYPE_INTEGER, true, null);
+
+        addElement("VerticalPixelOffset", "Dimension", CHILD_POLICY_EMPTY);
+        addAttribute("VerticalPixelOffset", "value", DATATYPE_INTEGER, true, null);
+
+        addElement("HorizontalScreenSize", "Dimension", CHILD_POLICY_EMPTY);
+        addAttribute("HorizontalScreenSize", "value", DATATYPE_INTEGER, true, null);
+
+        addElement("VerticalScreenSize", "Dimension", CHILD_POLICY_EMPTY);
+        addAttribute("VerticalScreenSize", "value", DATATYPE_INTEGER, true, null);
+
+        // DOCUMENT
+        addElement("Document", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+        addElement("FormatVersion", "Document", CHILD_POLICY_EMPTY);
+        addAttribute("FormatVersion", "value", DATATYPE_STRING, true, null);
+
+        addElement("SubimageInterpretation", "Document", CHILD_POLICY_EMPTY);
+        values = new ArrayList<String>(14);
+        values.add("Standalone");
+        values.add("SinglePage");
+        values.add("FullResolution");
+        values.add("ReducedResolution");
+        values.add("PyramidLayer");
+        values.add("Preview");
+        values.add("VolumeSlice");
+        values.add("ObjectView");
+        values.add("Panorama");
+        values.add("AnimationFrame");
+        values.add("TransparencyMask");
+        values.add("CompositingLayer");
+        values.add("SpectralSlice");
+        values.add("Unknown");
+        addAttribute("SubimageInterpretation", "value", DATATYPE_STRING, true, null, values);
+
+        addElement("ImageCreationTime", "Document", CHILD_POLICY_EMPTY);
+        addAttribute("ImageCreationTime", "year", DATATYPE_INTEGER, true, null);
+        addAttribute("ImageCreationTime", "month", DATATYPE_INTEGER, true, null, "1", "12", true,
+                true);
+        addAttribute("ImageCreationTime", "day", DATATYPE_INTEGER, true, null, "1", "31", true,
+                true);
+        addAttribute("ImageCreationTime", "hour", DATATYPE_INTEGER, false, "0", "0", "23", true,
+                true);
+        addAttribute("ImageCreationTime", "minute", DATATYPE_INTEGER, false, "0", "0", "59", true,
+                true);
+        addAttribute("ImageCreationTime", "second", DATATYPE_INTEGER, false, "0", "0", "60", true,
+                true);
+
+        addElement("ImageModificationTime", "Document", CHILD_POLICY_EMPTY);
+        addAttribute("ImageModificationTime", "year", DATATYPE_INTEGER, true, null);
+        addAttribute("ImageModificationTime", "month", DATATYPE_INTEGER, true, null, "1", "12",
+                true, true);
+        addAttribute("ImageModificationTime", "day", DATATYPE_INTEGER, true, null, "1", "31", true,
+                true);
+        addAttribute("ImageModificationTime", "hour", DATATYPE_INTEGER, false, "0", "0", "23",
+                true, true);
+        addAttribute("ImageModificationTime", "minute", DATATYPE_INTEGER, false, "0", "0", "59",
+                true, true);
+        addAttribute("ImageModificationTime", "second", DATATYPE_INTEGER, false, "0", "0", "60",
+                true, true);
+
+        // TEXT
+        addElement("Text", standardMetadataFormatName, 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT
+
+        addElement("TextEntry", "Text", CHILD_POLICY_EMPTY);
+        addAttribute("TextEntry", "keyword", DATATYPE_STRING, false, null);
+        addAttribute("TextEntry", "value", DATATYPE_STRING, true, null);
+        addAttribute("TextEntry", "language", DATATYPE_STRING, false, null);
+        addAttribute("TextEntry", "encoding", DATATYPE_STRING, false, null);
+        values = new ArrayList<String>(5);
+        values.add("none");
+        values.add("lzw");
+        values.add("zip");
+        values.add("bzip");
+        values.add("other");
+        addAttribute("TextEntry", "compression", DATATYPE_STRING, false, "none", values);
+
+        // TRANSPARENCY
+        addElement("Transparency", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+        addElement("Alpha", "Transparency", CHILD_POLICY_EMPTY);
+        values = new ArrayList<String>(3);
+        values.add("none");
+        values.add("premultiplied");
+        values.add("nonpremultiplied");
+        addAttribute("Alpha", "value", DATATYPE_STRING, false, "none", values);
+
+        addElement("TransparentIndex", "Transparency", CHILD_POLICY_EMPTY);
+        addAttribute("TransparentIndex", "value", DATATYPE_INTEGER, true, null);
+
+        addElement("TransparentColor", "Transparency", CHILD_POLICY_EMPTY);
+        addAttribute("TransparentColor", "value", DATATYPE_INTEGER, true, 0, Integer.MAX_VALUE);
+
+        addElement("TileTransparencies", "Transparency", 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT
+
+        addElement("TransparentTile", "TileTransparencies", CHILD_POLICY_EMPTY);
+        addAttribute("TransparentTile", "x", DATATYPE_INTEGER, true, null);
+        addAttribute("TransparentTile", "y", DATATYPE_INTEGER, true, null);
+
+        addElement("TileOpacities", "Transparency", 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT
+
+        addElement("OpaqueTile", "TileOpacities", CHILD_POLICY_EMPTY);
+        addAttribute("OpaqueTile", "x", DATATYPE_INTEGER, true, null);
+        addAttribute("OpaqueTile", "y", DATATYPE_INTEGER, true, null);
+    }
+}
diff --git a/awt/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties b/awt/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties
new file mode 100644
index 0000000..d185808
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties
@@ -0,0 +1,133 @@
+# 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.
+
+# Descriptions of elements and attributes of the plugin neutral metadata format
+# (see IIOStandardMetadataFormat)
+
+# Messages for EN locale
+Chroma=Chroma (color) information
+ColorSpaceType=The raw color space of the image
+ColorSpaceType/name=The raw color space of the image
+NumChannels=The number of channels in the raw image, including alpha
+NumChannels/value=The number of channels in the raw image, including alpha
+Gamma=The image gamma
+Gamma/value=The image gamma
+BlackIsZero=True if smaller values represent darker shades
+BlackIsZero/value=True if smaller values represent darker shades
+Palette=Palette-color information
+PaletteEntry=A palette entry
+PaletteEntry/index=The index of the palette entry
+PaletteEntry/red=The red value for the palette entry
+PaletteEntry/green=The green value for the palette entry
+PaletteEntry/blue=The blue value for the palette entry
+PaletteEntry/alpha=The alpha value for the palette entry
+BackgroundIndex=A palette index to be used as a background
+BackgroundIndex/value=A palette index to be used as a background
+BackgroundColor=An RGB triple to be used as a background
+BackgroundColor/red=The red background value
+BackgroundColor/green=The green background value
+BackgroundColor/blue=The blue background value
+
+Compression=Compression information
+CompressionTypeName=The name of the compression scheme in use
+CompressionTypeName/value=The name of the compression scheme in use
+Lossless=True if the compression scheme is lossless
+Lossless/value=True if the compression scheme is lossless
+NumProgressiveScans=The number of progressive scans used in the image encoding
+NumProgressiveScans/value=The number of progressive scans used in the image encoding
+BitRate=The estimated bit rate of the compression scheme
+BitRate/value=The estimated bit rate of the compression scheme
+
+Data=Information on the image layout
+PlanarConfiguration=The organization of image samples in the stream
+PlanarConfiguration/value=The organization of image samples in the stream
+SampleFormat=The numeric format of image samples
+SampleFormat/value=The numeric format of image samples
+BitsPerSample=The number of bits per sample
+BitsPerSample/value=A list of integers, one per channel
+SignificantBitsPerSample=The number of significant bits per sample
+SignificantBitsPerSample/value=A list of integers, one per channel
+SampleMSB=The position of the most significant bit of each sample
+SampleMSB/value=A list of integers, one per channel
+
+Dimension=Dimension information
+PixelAspectRatio=The width of a pixel divided by its height
+PixelAspectRatio/value=The width of a pixel divided by its height
+ImageOrientation=The desired orientation of the image in terms of flips and counter-clockwise rotations
+ImageOrientation/value=The desired orientation of the image in terms of flips and counter-clockwise rotations
+HorizontalPixelSize=The width of a pixel, in millimeters, as it should be rendered on media
+HorizontalPixelSize/value=The width of a pixel, in millimeters, as it should be rendered on media
+VerticalPixelSize=The height of a pixel, in millimeters, as it should be rendered on media
+VerticalPixelSize/value=The height of a pixel, in millimeters, as it should be rendered on media
+HorizontalPhysicalPixelSpacing=The horizontal distance in the subject of the image, in millimeters, represented by one pixel at the center of the image
+HorizontalPhysicalPixelSpacing/value=The horizontal distance in the subject of the image, in millimeters, represented by one pixel at the center of the image
+VerticalPhysicalPixelSpacing=The vertical distance in the subject of the image, in millimeters, represented by one pixel at the center of the image
+VerticalPhysicalPixelSpacing/value=The vertical distance in the subject of the image, in millimeters, represented by one pixel at the center of the image
+HorizontalPosition=The horizontal position, in millimeters, where the image should be rendered on media
+HorizontalPosition/value=The horizontal position, in millimeters, where the image should be rendered on media
+VerticalPosition=The vertical position, in millimeters, where the image should be rendered on media
+VerticalPosition/value=The vertical position, in millimeters, where the image should be rendered on media
+HorizontalPixelOffset=The horizonal position, in pixels, where the image should be rendered onto a raster display
+HorizontalPixelOffset/value=The horizonal position, in pixels, where the image should be rendered onto a raster display
+VerticalPixelOffset=The vertical position, in pixels, where the image should be rendered onto a raster display
+VerticalPixelOffset/value=The vertical position, in pixels, where the image should be rendered onto a raster display
+HorizontalScreenSize=The width, in pixels, of the raster display into which the image should be rendered
+HorizontalScreenSize/value=The width, in pixels, of the raster display into which the image should be rendered
+VerticalScreenSize=The height, in pixels, of the raster display into which the image should be rendered
+VerticalScreenSize/value=The height, in pixels, of the raster display into which the image should be rendered
+
+Document=Document information
+FormatVersion=The version of the format used by the stream
+FormatVersion/value=The version of the format used by the stream
+SubimageInterpretation=The interpretation of this image in relation to the other images stored in the same stream
+SubimageInterpretation/value=The interpretation of this image in relation to the other images stored in the same stream
+ImageCreationTime=The time of image creation
+ImageCreationTime/year=The full year (e.g., 1967, not 67)
+ImageCreationTime/month=The month, with January = 1
+ImageCreationTime/day=The day of the month
+ImageCreationTime/hour=The hour from 0 to 23
+ImageCreationTime/minute=The minute from 0 to 59
+ImageCreationTime/second=The second from 0 to 60 (60 = leap second)
+ImageModificationTime=The time of the last image modification
+ImageModificationTime/year=The full year (e.g., 1967, not 67)
+ImageModificationTime/month=The month, with January = 1
+ImageModificationTime/day=The day of the month
+ImageModificationTime/hour=The hour from 0 to 23
+ImageModificationTime/minute=The minute from 0 to 59
+ImageModificationTime/second=The second from 0 to 60 (60 = leap second)
+
+Text=Text information
+TextEntry=A text entry
+TextEntry/keyword=A keyword associated with the text entry
+TextEntry/value=the text entry
+TextEntry/language=The language of the text
+TextEntry/encoding=The encoding of the text
+TextEntry/compression=The method used to compress the text
+
+Transparency=Transparency information
+Alpha=The type of alpha information contained in the image
+Alpha/value=The type of alpha information contained in the image
+TransparentIndex=A palette index to be treated as transparent
+TransparentIndex/value=A palette index to be treated as transparent
+TransparentColor=An RGB color to be treated as transparent
+TransparentColor/value=An RGB color to be treated as transparent
+TileTransparencies=A list of completely transparent tiles
+TransparentTile=The index of a completely transparent tile
+TransparentTile/x=The tile's X index
+TransparentTile/y=The tile's Y index
+TileOpacities=A list of completely opaque tiles
+OpaqueTile=The index of a completely opaque tile
+OpaqueTile/x=The tile's X index
+OpaqueTile/y=The tile's Y index
diff --git a/awt/javax/imageio/metadata/package.html b/awt/javax/imageio/metadata/package.html
new file mode 100644
index 0000000..29bd51b
--- /dev/null
+++ b/awt/javax/imageio/metadata/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      This package contains classes which allows to read and write describing metadata of image files.
+    </p>
+  @since Android 1.0
+  </body>
+</html>
diff --git a/awt/javax/imageio/package.html b/awt/javax/imageio/package.html
new file mode 100644
index 0000000..2fd6148
--- /dev/null
+++ b/awt/javax/imageio/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      This package contains classes and interfaces which provides an Image I/O API. The contained classes and interfaces allow reading and writing image files of different formats.
+    </p>
+  @since Android 1.0
+  </body>
+</html>
diff --git a/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java b/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java
new file mode 100644
index 0000000..ecfb20a
--- /dev/null
+++ b/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java
@@ -0,0 +1,79 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.plugins.bmp;
+
+import javax.imageio.ImageWriteParam;
+import java.util.Locale;
+
+/**
+ * The BMPImageWriteParam class allows encoding an image in BMP format.
+ * 
+ * @since Android 1.0
+ */
+public class BMPImageWriteParam extends ImageWriteParam {
+
+    /**
+     * The top down.
+     */
+    private boolean topDown; // Default is bottom-up
+
+    /**
+     * Instantiates a new BMPImageWriteParam with default values of all
+     * parameters.
+     */
+    public BMPImageWriteParam() {
+        this(null);
+    }
+
+    /**
+     * Instantiates a new BMPImageWriteParam with the specified Locale.
+     * 
+     * @param locale
+     *            the specified Locale.
+     */
+    public BMPImageWriteParam(Locale locale) {
+        super(locale);
+
+        // Set the compression
+        canWriteCompressed = true;
+        compressionTypes = new String[] {
+                "BI_RGB", "BI_RLE8", "BI_RLE4", "BI_BITFIELDS"
+        };
+        compressionType = compressionTypes[0];
+    }
+
+    /**
+     * Sets true if the data will be written in a top-down order, false
+     * otherwise.
+     * 
+     * @param topDown
+     *            the new top-down value.
+     */
+    public void setTopDown(boolean topDown) {
+        this.topDown = topDown;
+    }
+
+    /**
+     * Returns true if the data is written in top-down order, false otherwise.
+     * 
+     * @return true if the data is written in top-down order, false otherwise.
+     */
+    public boolean isTopDown() {
+        return topDown;
+    }
+}
diff --git a/awt/javax/imageio/plugins/bmp/package.html b/awt/javax/imageio/plugins/bmp/package.html
new file mode 100644
index 0000000..9494a10
--- /dev/null
+++ b/awt/javax/imageio/plugins/bmp/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      This package contains auxiliary classes for the built-in BMP image plug-in.
+    </p>
+  @since Android 1.0
+  </body>
+</html>
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java b/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java
new file mode 100644
index 0000000..67b504b
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java
@@ -0,0 +1,226 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.plugins.jpeg;
+
+/**
+ * The JPEGHuffmanTable class represents a single JPEG Huffman table. It
+ * contains the standard tables from the JPEG specification.
+ * 
+ * @since Android 1.0
+ */
+public class JPEGHuffmanTable {
+
+    /**
+     * The standard DC luminance Huffman table .
+     */
+    public static final JPEGHuffmanTable StdDCLuminance = new JPEGHuffmanTable(new short[] {
+            0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+    }, new short[] {
+            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B
+    }, false);
+
+    /**
+     * The standard DC chrominance Huffman table.
+     */
+    public static final JPEGHuffmanTable StdDCChrominance = new JPEGHuffmanTable(new short[] {
+            0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
+    }, new short[] {
+            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B
+    }, false);
+
+    /**
+     * The standard AC luminance Huffman table.
+     */
+    public static final JPEGHuffmanTable StdACLuminance = new JPEGHuffmanTable(new short[] {
+            0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7D
+    }, new short[] {
+            0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51,
+            0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1,
+            0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18,
+            0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+            0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57,
+            0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75,
+            0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92,
+            0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+            0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,
+            0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8,
+            0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2,
+            0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
+    }, false);
+
+    /**
+     * The standard AC chrominance Huffman table.
+     */
+    public static final JPEGHuffmanTable StdACChrominance = new JPEGHuffmanTable(new short[] {
+            0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
+    }, new short[] {
+            0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07,
+            0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09,
+            0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25,
+            0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38,
+            0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56,
+            0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74,
+            0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+            0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5,
+            0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA,
+            0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+            0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2,
+            0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
+    }, false);
+
+    /**
+     * The lengths.
+     */
+    private short lengths[];
+
+    /**
+     * The values.
+     */
+    private short values[];
+
+    /**
+     * Instantiates a new jPEG huffman table.
+     * 
+     * @param lengths
+     *            the lengths
+     * @param values
+     *            the values
+     * @param copy
+     *            the copy
+     */
+    JPEGHuffmanTable(short[] lengths, short[] values, boolean copy) {
+        // Construction of standard tables without checks
+        // The third param is dummy
+        // Could be also used for copying of the existing tables
+        this.lengths = lengths;
+        this.values = values;
+    }
+
+    /**
+     * Instantiates a new JPEGHuffmanTable.
+     * 
+     * @param lengths
+     *            the array of shorts lengths.
+     * @param values
+     *            the array of shorts containing the values in order of
+     *            increasing code length.
+     */
+    public JPEGHuffmanTable(short[] lengths, short[] values) {
+        if (lengths == null) {
+            throw new IllegalArgumentException("lengths array is null!");
+        }
+        if (values == null) {
+            throw new IllegalArgumentException("values array is null!");
+        }
+        if (lengths.length > 16) { // According to the spec
+            throw new IllegalArgumentException("lengths array is too long!");
+        }
+        if (values.length > 256) { // According to the spec
+            throw new IllegalArgumentException("values array is too long");
+        }
+        for (short length : lengths) {
+            if (length < 0) {
+                throw new IllegalArgumentException("Values in lengths array must be non-negative.");
+            }
+        }
+        for (short value : values) {
+            if (value < 0) {
+                throw new IllegalArgumentException("Values in values array must be non-negative.");
+            }
+        }
+
+        checkHuffmanTable(lengths, values);
+
+        this.lengths = new short[lengths.length];
+        this.values = new short[values.length];
+        System.arraycopy(lengths, 0, this.lengths, 0, lengths.length);
+        System.arraycopy(values, 0, this.values, 0, values.length);
+    }
+
+    /**
+     * Gets an array of lengths in the Huffman table.
+     * 
+     * @return the array of short values representing the length values in the
+     *         Huffman table.
+     */
+    public short[] getLengths() {
+        short newLengths[] = new short[lengths.length];
+        System.arraycopy(lengths, 0, newLengths, 0, lengths.length);
+        return newLengths;
+    }
+
+    /**
+     * Gets an array of values represented by increasing length of their codes.
+     * 
+     * @return the array of values.
+     */
+    public short[] getValues() {
+        short newValues[] = new short[values.length];
+        System.arraycopy(values, 0, newValues, 0, values.length);
+        return newValues;
+    }
+
+    /**
+     * Check huffman table.
+     * 
+     * @param lengths
+     *            the lengths.
+     * @param values
+     *            the values.
+     */
+    private static void checkHuffmanTable(short[] lengths, short[] values) {
+        int numLeaves = 0;
+        int possibleLeaves = 2;
+        for (short length : lengths) {
+            numLeaves += length;
+            possibleLeaves -= length;
+            if (possibleLeaves < 0) {
+                throw new IllegalArgumentException(
+                        "Invalid Huffman table provided, lengths are incorrect.");
+            }
+            possibleLeaves <<= 1;
+        }
+
+        if (values.length != numLeaves) {
+            throw new IllegalArgumentException(
+                    "Invalid Huffman table provided, sum of lengths != values.");
+        }
+    }
+
+    /**
+     * Returns the string representation of this JPEGHuffmanTable object.
+     * 
+     * @return the string representation of this JPEGHuffmanTable object.
+     */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append("JPEGHuffmanTable:\nlengths:");
+        for (short length : lengths) {
+            sb.append(' ').append(length);
+        }
+
+        sb.append("\nvalues:");
+        for (short value : values) {
+            sb.append(' ').append(value);
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java b/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java
new file mode 100644
index 0000000..2f3a9a8
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java
@@ -0,0 +1,123 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.plugins.jpeg;
+
+import javax.imageio.ImageReadParam;
+
+/**
+ * The JPEGImageReadParam class provides functionality to set Huffman tables and
+ * quantization tables when using the JPEG reader plug-in.
+ * 
+ * @since Android 1.0
+ */
+public class JPEGImageReadParam extends ImageReadParam {
+
+    /**
+     * The q tables.
+     */
+    private JPEGQTable qTables[];
+
+    /**
+     * The dc huffman tables.
+     */
+    private JPEGHuffmanTable dcHuffmanTables[];
+
+    /**
+     * The ac huffman tables.
+     */
+    private JPEGHuffmanTable acHuffmanTables[];
+
+    /**
+     * Instantiates a new JPEGImageReadParam.
+     */
+    public JPEGImageReadParam() {
+    }
+
+    /**
+     * Returns true if tables are set, false otherwise.
+     * 
+     * @return true, if tables are set, false otherwise.
+     */
+    public boolean areTablesSet() {
+        return qTables != null;
+    }
+
+    /**
+     * Sets the quantization and Huffman tables for using in decoding streams.
+     * 
+     * @param qTables
+     *            the quantization tables.
+     * @param DCHuffmanTables
+     *            the standart DC Huffman tables.
+     * @param ACHuffmanTables
+     *            the standart AC huffman tables.
+     */
+    public void setDecodeTables(JPEGQTable[] qTables, JPEGHuffmanTable[] DCHuffmanTables,
+            JPEGHuffmanTable[] ACHuffmanTables) {
+        if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null) {
+            throw new IllegalArgumentException("Invalid JPEG table arrays");
+        }
+        if (DCHuffmanTables.length != ACHuffmanTables.length) {
+            throw new IllegalArgumentException("Invalid JPEG table arrays");
+        }
+        if (qTables.length > 4 || DCHuffmanTables.length > 4) {
+            throw new IllegalArgumentException("Invalid JPEG table arrays");
+        }
+
+        // Do the shallow copy, it should be enough
+        this.qTables = qTables.clone();
+        dcHuffmanTables = DCHuffmanTables.clone();
+        acHuffmanTables = ACHuffmanTables.clone();
+    }
+
+    /**
+     * Unset all decoded tables.
+     */
+    public void unsetDecodeTables() {
+        qTables = null;
+        dcHuffmanTables = null;
+        acHuffmanTables = null;
+    }
+
+    /**
+     * Gets the quantization tables.
+     * 
+     * @return the quantization tables, or null.
+     */
+    public JPEGQTable[] getQTables() {
+        return qTables == null ? null : qTables.clone();
+    }
+
+    /**
+     * Gets the DC Huffman tables.
+     * 
+     * @return the DC Huffman tables which are set, or null.
+     */
+    public JPEGHuffmanTable[] getDCHuffmanTables() {
+        return dcHuffmanTables == null ? null : dcHuffmanTables.clone();
+    }
+
+    /**
+     * Gets the AC Huffman tables.
+     * 
+     * @return the AC Huffman tables which are set, or null.
+     */
+    public JPEGHuffmanTable[] getACHuffmanTables() {
+        return acHuffmanTables == null ? null : acHuffmanTables.clone();
+    }
+}
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java b/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java
new file mode 100644
index 0000000..b979911
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java
@@ -0,0 +1,209 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.plugins.jpeg;
+
+import org.apache.harmony.x.imageio.plugins.jpeg.JPEGConsts;
+
+import javax.imageio.ImageWriteParam;
+import java.util.Locale;
+
+/**
+ * The JPEGImageWriteParam class allows to set JPEG Huffman tables and
+ * quantization when using the JPEG writer plug-in.
+ * 
+ * @since Android 1.0
+ */
+public class JPEGImageWriteParam extends ImageWriteParam {
+
+    /**
+     * The Constant COMP_QUALITY_VALUES.
+     */
+    private static final float[] COMP_QUALITY_VALUES = {
+            0.05f, 0.75f, 0.95f
+    };
+
+    /**
+     * The Constant COMP_QUALITY_DESCRIPTIONS.
+     */
+    private static final String[] COMP_QUALITY_DESCRIPTIONS = {
+            "Minimum useful", "Visually lossless", "Maximum useful"
+    };
+
+    /**
+     * The q tables.
+     */
+    private JPEGQTable[] qTables;
+
+    /**
+     * The dc huffman tables.
+     */
+    private JPEGHuffmanTable[] dcHuffmanTables;
+
+    /**
+     * The ac huffman tables.
+     */
+    private JPEGHuffmanTable[] acHuffmanTables;
+
+    /**
+     * The optimize huffman tables.
+     */
+    private boolean optimizeHuffmanTables;
+
+    /**
+     * Instantiates a new JPEGImageWriteParam object with the specified Locale.
+     * 
+     * @param locale
+     *            the Locale.
+     */
+    public JPEGImageWriteParam(Locale locale) {
+        super(locale);
+
+        canWriteProgressive = true;
+        progressiveMode = ImageWriteParam.MODE_DISABLED;
+
+        canWriteCompressed = true;
+        compressionTypes = new String[] {
+            "JPEG"
+        };
+        compressionType = compressionTypes[0];
+        compressionQuality = JPEGConsts.DEFAULT_JPEG_COMPRESSION_QUALITY;
+    }
+
+    /**
+     * Returns true if tables are set, false otherwise.
+     * 
+     * @return true, if tables are set, false otherwise.
+     */
+    public boolean areTablesSet() {
+        return qTables != null;
+    }
+
+    /**
+     * Sets the quantization and Huffman tables for using in encoding streams.
+     * 
+     * @param qTables
+     *            the quantization tables.
+     * @param DCHuffmanTables
+     *            the standart DC Huffman tables.
+     * @param ACHuffmanTables
+     *            the standart AC huffman tables.
+     */
+    public void setEncodeTables(JPEGQTable[] qTables, JPEGHuffmanTable[] DCHuffmanTables,
+            JPEGHuffmanTable[] ACHuffmanTables) {
+        if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null) {
+            throw new IllegalArgumentException("Invalid JPEG table arrays");
+        }
+        if (DCHuffmanTables.length != ACHuffmanTables.length) {
+            throw new IllegalArgumentException("Invalid JPEG table arrays");
+        }
+        if (qTables.length > 4 || DCHuffmanTables.length > 4) {
+            throw new IllegalArgumentException("Invalid JPEG table arrays");
+        }
+
+        // Do the shallow copy, it should be enough
+        this.qTables = qTables.clone();
+        dcHuffmanTables = DCHuffmanTables.clone();
+        acHuffmanTables = ACHuffmanTables.clone();
+    }
+
+    /**
+     * Unset all encoded tables.
+     */
+    public void unsetEncodeTables() {
+        qTables = null;
+        dcHuffmanTables = null;
+        acHuffmanTables = null;
+    }
+
+    /**
+     * Gets the DC Huffman tables.
+     * 
+     * @return the DC Huffman tables which are set, or null.
+     */
+    public JPEGHuffmanTable[] getDCHuffmanTables() {
+        return dcHuffmanTables == null ? null : dcHuffmanTables.clone();
+    }
+
+    /**
+     * Gets the AC Huffman tables.
+     * 
+     * @return the AC Huffman tables which are set, or null.
+     */
+    public JPEGHuffmanTable[] getACHuffmanTables() {
+        return acHuffmanTables == null ? null : acHuffmanTables.clone();
+    }
+
+    /**
+     * Gets the quantization tables.
+     * 
+     * @return the quantization tables, or null.
+     */
+    public JPEGQTable[] getQTables() {
+        return qTables == null ? null : qTables.clone();
+    }
+
+    @Override
+    public String[] getCompressionQualityDescriptions() {
+        super.getCompressionQualityDescriptions();
+        return COMP_QUALITY_DESCRIPTIONS.clone();
+    }
+
+    @Override
+    public float[] getCompressionQualityValues() {
+        super.getCompressionQualityValues();
+        return COMP_QUALITY_VALUES.clone();
+    }
+
+    /**
+     * Sets the flag indicated that the writer will generate optimized Huffman
+     * tables for the image as part of the writing process.
+     * 
+     * @param optimize
+     *            the flag of optimizing huffman tables.
+     */
+    public void setOptimizeHuffmanTables(boolean optimize) {
+        optimizeHuffmanTables = optimize;
+    }
+
+    /**
+     * Returns true if the writer generates optimized Huffman tables, false
+     * otherwise.
+     * 
+     * @return true, if the writer generates optimized Huffman tables, false
+     *         otherwise.
+     */
+    public boolean getOptimizeHuffmanTables() {
+        return optimizeHuffmanTables;
+    }
+
+    @Override
+    public boolean isCompressionLossless() {
+        if (getCompressionMode() != MODE_EXPLICIT) {
+            throw new IllegalStateException("Compression mode not MODE_EXPLICIT!");
+        }
+        return false;
+    }
+
+    @Override
+    public void unsetCompression() {
+        if (getCompressionMode() != MODE_EXPLICIT) {
+            throw new IllegalStateException("Compression mode not MODE_EXPLICIT!");
+        }
+        compressionQuality = JPEGConsts.DEFAULT_JPEG_COMPRESSION_QUALITY;
+    }
+}
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGQTable.java b/awt/javax/imageio/plugins/jpeg/JPEGQTable.java
new file mode 100644
index 0000000..3461d46
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGQTable.java
@@ -0,0 +1,165 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.plugins.jpeg;
+
+/**
+ * The JPEGQTable class represents a single JPEG quantization table and provides
+ * for the standard tables taken from the JPEG specification.
+ * 
+ * @since Android 1.0
+ */
+public class JPEGQTable {
+
+    /**
+     * The Constant SIZE.
+     */
+    private final static int SIZE = 64;
+
+    /**
+     * The Constant BASELINE_MAX.
+     */
+    private final static int BASELINE_MAX = 255;
+
+    /**
+     * The Constant MAX.
+     */
+    private final static int MAX = 32767;
+
+    /**
+     * The table.
+     */
+    private int[] theTable;
+
+    /*
+     * K1 & K2 tables can be found in the JPEG format specification at
+     * http://www.w3.org/Graphics/JPEG/itu-t81.pdf
+     */
+
+    /**
+     * The Constant K1LumTable.
+     */
+    private static final int[] K1LumTable = new int[] {
+            16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57,
+            69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55,
+            64, 81, 104, 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100,
+            103, 99
+    };
+
+    /**
+     * The Constant K2ChrTable.
+     */
+    private static final int[] K2ChrTable = new int[] {
+            17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99,
+            99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+            99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99
+    };
+
+    /**
+     * The K1Luminance indicates standard table K.1 from JPEG specification and
+     * produces "good" quality output.
+     */
+    public static final JPEGQTable K1Luminance = new JPEGQTable(K1LumTable);
+
+    /**
+     * The K1Div2Luminance indicates K.1 table from JPEG specification with all
+     * elements divided by 2 and produces "very good" quality output.
+     */
+    public static final JPEGQTable K1Div2Luminance = K1Luminance.getScaledInstance(0.5f, true);
+
+    /**
+     * The K2Chrominance indicates K.2 table from JPEG specification and
+     * produces "good" quality output.
+     */
+    public static final JPEGQTable K2Chrominance = new JPEGQTable(K2ChrTable);
+
+    /**
+     * The Constant K2Div2Chrominance indicates K.2 table from JPEG
+     * specification with all elements divided by 2 and produces "very good"
+     * quality output.
+     */
+    public static final JPEGQTable K2Div2Chrominance = K2Chrominance.getScaledInstance(0.5f, true);;
+
+    /**
+     * Instantiates a new JPEGQTable from the array, which should contain 64
+     * elements in natural order.
+     * 
+     * @param table
+     *            the quantization table.
+     */
+    public JPEGQTable(int[] table) {
+        if (table == null) {
+            throw new IllegalArgumentException("table should not be NULL");
+        }
+        if (table.length != SIZE) {
+            throw new IllegalArgumentException("illegal table size: " + table.length);
+        }
+        theTable = table.clone();
+    }
+
+    /**
+     * Gets the current quantization table as an array of integer values.
+     * 
+     * @return the current quantization table as an array of integer values.
+     */
+    public int[] getTable() {
+        return theTable.clone();
+    }
+
+    /**
+     * Gets the scaled instance as quantization table where the values are
+     * multiplied by the scaleFactor and then clamped if forceBaseline is true.
+     * 
+     * @param scaleFactor
+     *            the scale factor of table.
+     * @param forceBaseline
+     *            the force baseline flag, the values should be clamped if true.
+     * @return the new quantization table.
+     */
+    public JPEGQTable getScaledInstance(float scaleFactor, boolean forceBaseline) {
+        int table[] = new int[SIZE];
+
+        int maxValue = forceBaseline ? BASELINE_MAX : MAX;
+
+        for (int i = 0; i < theTable.length; i++) {
+            int rounded = Math.round(theTable[i] * scaleFactor);
+            if (rounded < 1) {
+                rounded = 1;
+            }
+            if (rounded > maxValue) {
+                rounded = maxValue;
+            }
+            table[i] = rounded;
+        }
+        return new JPEGQTable(table);
+    }
+
+    /**
+     * Returns the string representation of this JPEGQTable object.
+     * 
+     * @return the string representation of this JPEGQTable object.
+     */
+    @Override
+    public String toString() {
+        // -- TODO more informative info
+        return "JPEGQTable";
+    }
+}
diff --git a/awt/javax/imageio/plugins/jpeg/package.html b/awt/javax/imageio/plugins/jpeg/package.html
new file mode 100644
index 0000000..14575c4
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      This package contains auxiliary classes for the built-in JPEG image plug-in.
+    </p>
+  @since Android 1.0
+  </body>
+</html>
diff --git a/awt/javax/imageio/spi/IIORegistry.java b/awt/javax/imageio/spi/IIORegistry.java
new file mode 100644
index 0000000..01ddeaa
--- /dev/null
+++ b/awt/javax/imageio/spi/IIORegistry.java
@@ -0,0 +1,115 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.spi;
+
+import java.util.Arrays;
+
+import org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageReaderSpi;
+import org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageWriterSpi;
+import org.apache.harmony.x.imageio.plugins.png.PNGImageReaderSpi;
+import org.apache.harmony.x.imageio.plugins.png.PNGImageWriterSpi;
+import org.apache.harmony.x.imageio.spi.FileIISSpi;
+import org.apache.harmony.x.imageio.spi.FileIOSSpi;
+import org.apache.harmony.x.imageio.spi.InputStreamIISSpi;
+import org.apache.harmony.x.imageio.spi.OutputStreamIOSSpi;
+import org.apache.harmony.x.imageio.spi.RAFIISSpi;
+import org.apache.harmony.x.imageio.spi.RAFIOSSpi;
+
+/*
+ * @author Rustem V. Rafikov, Viskov Nikolay
+ * @version $Revision: 1.3 $
+ */
+
+/**
+ * The IIORegistry class registers service provider instances (SPI). Service
+ * provider instances are recognized by specific meta-information in the JAR
+ * files containing them. The JAR files with SPI classes are loaded from the
+ * application class path.
+ * 
+ * @since Android 1.0
+ */
+public final class IIORegistry extends ServiceRegistry {
+
+    /**
+     * The instance.
+     */
+    private static IIORegistry instance;
+
+    /**
+     * The Constant CATEGORIES.
+     */
+    private static final Class[] CATEGORIES = new Class[] {
+            javax.imageio.spi.ImageWriterSpi.class, javax.imageio.spi.ImageReaderSpi.class,
+            javax.imageio.spi.ImageInputStreamSpi.class,
+            // javax.imageio.spi.ImageTranscoderSpi.class,
+            javax.imageio.spi.ImageOutputStreamSpi.class
+    };
+
+    /**
+     * Instantiates a new IIO registry.
+     */
+    private IIORegistry() {
+        super(Arrays.<Class<?>> asList(CATEGORIES).iterator());
+        registerBuiltinSpis();
+        registerApplicationClasspathSpis();
+    }
+
+    /**
+     * Register built-in SPIs.
+     */
+    private void registerBuiltinSpis() {
+        registerServiceProvider(new JPEGImageWriterSpi());
+        registerServiceProvider(new JPEGImageReaderSpi());
+        registerServiceProvider(new PNGImageReaderSpi());
+        registerServiceProvider(new PNGImageWriterSpi());
+        registerServiceProvider(new FileIOSSpi());
+        registerServiceProvider(new FileIISSpi());
+        registerServiceProvider(new RAFIOSSpi());
+        registerServiceProvider(new RAFIISSpi());
+        registerServiceProvider(new OutputStreamIOSSpi());
+        registerServiceProvider(new InputStreamIISSpi());
+        // -- TODO implement
+    }
+
+    /**
+     * Gets the default IIORegistry instance.
+     * 
+     * @return the default IIORegistry instance.
+     */
+    public static IIORegistry getDefaultInstance() {
+        // TODO implement own instance for each ThreadGroup (see also
+        // ThreadLocal)
+        synchronized (IIORegistry.class) {
+            if (instance == null) {
+                instance = new IIORegistry();
+            }
+            return instance;
+        }
+    }
+
+    /**
+     * Registers all service providers from the application class path.
+     */
+    public void registerApplicationClasspathSpis() {
+        // -- TODO implement for non-builtin plugins
+    }
+}
diff --git a/awt/javax/imageio/spi/IIOServiceProvider.java b/awt/javax/imageio/spi/IIOServiceProvider.java
new file mode 100644
index 0000000..e947677
--- /dev/null
+++ b/awt/javax/imageio/spi/IIOServiceProvider.java
@@ -0,0 +1,105 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.spi;
+
+import java.util.Locale;
+
+/**
+ * The IIOServiceProvider abstract class provides base functionality for ImageIO
+ * service provider interfaces (SPIs).
+ * 
+ * @since Android 1.0
+ */
+public abstract class IIOServiceProvider implements RegisterableService {
+
+    /**
+     * The vendor name of this service provider.
+     */
+    protected String vendorName;
+
+    /**
+     * The version of this service provider.
+     */
+    protected String version;
+
+    /**
+     * Instantiates a new IIOServiceProvider.
+     * 
+     * @param vendorName
+     *            the vendor name of service provider.
+     * @param version
+     *            the version of service provider.
+     */
+    public IIOServiceProvider(String vendorName, String version) {
+        if (vendorName == null) {
+            throw new NullPointerException("vendor name cannot be NULL");
+        }
+        if (version == null) {
+            throw new NullPointerException("version name cannot be NULL");
+        }
+        this.vendorName = vendorName;
+        this.version = version;
+    }
+
+    /**
+     * Instantiates a new IIOServiceProvider.
+     */
+    public IIOServiceProvider() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    public void onRegistration(ServiceRegistry registry, Class<?> category) {
+        // the default impl. does nothing
+    }
+
+    public void onDeregistration(ServiceRegistry registry, Class<?> category) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the vendor name of this service provider.
+     * 
+     * @return the vendor name of this service provider.
+     */
+    public String getVendorName() {
+        return vendorName;
+    }
+
+    /**
+     * Gets the version of this service provider.
+     * 
+     * @return the version of this service provider.
+     */
+    public String getVersion() {
+        return version;
+    }
+
+    /**
+     * Gets a description of this service provider. The result string should be
+     * localized for the specified Locale.
+     * 
+     * @param locale
+     *            the specified Locale.
+     * @return the description of this service provider.
+     */
+    public abstract String getDescription(Locale locale);
+}
diff --git a/awt/javax/imageio/spi/ImageInputStreamSpi.java b/awt/javax/imageio/spi/ImageInputStreamSpi.java
new file mode 100644
index 0000000..fc859a8
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageInputStreamSpi.java
@@ -0,0 +1,131 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.spi;
+
+import java.io.File;
+import java.io.IOException;
+import javax.imageio.stream.ImageInputStream;
+
+/**
+ * The ImageInputStreamSpi abstract class is a service provider interface (SPI)
+ * for ImageInputStreams.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ImageInputStreamSpi extends IIOServiceProvider implements RegisterableService {
+
+    /**
+     * The input class.
+     */
+    protected Class<?> inputClass;
+
+    /**
+     * Instantiates a new ImageInputStreamSpi.
+     */
+    protected ImageInputStreamSpi() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Instantiates a new ImageInputStreamSpi.
+     * 
+     * @param vendorName
+     *            the vendor name.
+     * @param version
+     *            the version.
+     * @param inputClass
+     *            the input class.
+     */
+    public ImageInputStreamSpi(String vendorName, String version, Class<?> inputClass) {
+        super(vendorName, version);
+        this.inputClass = inputClass;
+    }
+
+    /**
+     * Gets an input Class object that represents class or interface that must
+     * be implemented by an input source.
+     * 
+     * @return the input class.
+     */
+    public Class<?> getInputClass() {
+        return inputClass;
+    }
+
+    /**
+     * Returns true if the ImageInputStream can use a cache file. If this method
+     * returns false, the value of the useCache parameter of
+     * createInputStreamInstance will be ignored. The default implementation
+     * returns false.
+     * 
+     * @return true, if the ImageInputStream can use a cache file, false
+     *         otherwise.
+     */
+    public boolean canUseCacheFile() {
+        return false; // -- def
+    }
+
+    /**
+     * Returns true if the ImageInputStream implementation requires the use of a
+     * cache file. The default implementation returns false.
+     * 
+     * @return true, if the ImageInputStream implementation requires the use of
+     *         a cache file, false otherwise.
+     */
+    public boolean needsCacheFile() {
+        return false; // def
+    }
+
+    /**
+     * Creates the ImageInputStream associated with this service provider. The
+     * input object should be an instance of the class returned by the
+     * getInputClass method. This method uses the specified directory for the
+     * cache file if the useCache parameter is true.
+     * 
+     * @param input
+     *            the input Object.
+     * @param useCache
+     *            the flag indicating if a cache file is needed or not.
+     * @param cacheDir
+     *            the cache directory.
+     * @return the ImageInputStream.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public abstract ImageInputStream createInputStreamInstance(Object input, boolean useCache,
+            File cacheDir) throws IOException;
+
+    /**
+     * Creates the ImageInputStream associated with this service provider. The
+     * input object should be an instance of the class returned by getInputClass
+     * method. This method uses the default system directory for the cache file,
+     * if it is needed.
+     * 
+     * @param input
+     *            the input Object.
+     * @return the ImageInputStream.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public ImageInputStream createInputStreamInstance(Object input) throws IOException {
+        return createInputStreamInstance(input, true, null);
+    }
+}
diff --git a/awt/javax/imageio/spi/ImageOutputStreamSpi.java b/awt/javax/imageio/spi/ImageOutputStreamSpi.java
new file mode 100644
index 0000000..b7a9a5c
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageOutputStreamSpi.java
@@ -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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.spi;
+
+import javax.imageio.stream.ImageOutputStream;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * The ImageOutputStreamSpi abstract class is a service provider interface (SPI)
+ * for ImageOutputStreams.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ImageOutputStreamSpi extends IIOServiceProvider implements
+        RegisterableService {
+
+    /**
+     * The output class.
+     */
+    protected Class<?> outputClass;
+
+    /**
+     * Instantiates a new ImageOutputStreamSpi.
+     */
+    protected ImageOutputStreamSpi() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Instantiates a new ImageOutputStreamSpi.
+     * 
+     * @param vendorName
+     *            the vendor name.
+     * @param version
+     *            the version.
+     * @param outputClass
+     *            the output class.
+     */
+    public ImageOutputStreamSpi(String vendorName, String version, Class<?> outputClass) {
+        super(vendorName, version);
+        this.outputClass = outputClass;
+    }
+
+    /**
+     * Gets an output Class object that represents the class or interface that
+     * must be implemented by an output source.
+     * 
+     * @return the output class.
+     */
+    public Class<?> getOutputClass() {
+        return outputClass;
+    }
+
+    /**
+     * Returns true if the ImageOutputStream can use a cache file. If this
+     * method returns false, the value of the useCache parameter of
+     * createOutputStreamInstance will be ignored. The default implementation
+     * returns false.
+     * 
+     * @return true, if the ImageOutputStream can use a cache file, false
+     *         otherwise.
+     */
+    public boolean canUseCacheFile() {
+        return false; // def
+    }
+
+    /**
+     * Returns true if the ImageOutputStream implementation requires the use of
+     * a cache file. The default implementation returns false.
+     * 
+     * @return true, if the ImageOutputStream implementation requires the use of
+     *         a cache file, false otherwise.
+     */
+    public boolean needsCacheFile() {
+        return false; // def
+    }
+
+    /**
+     * Creates the ImageOutputStream associated with this service provider. The
+     * output object should be an instance of the class returned by
+     * getOutputClass method. This method uses the default system directory for
+     * the cache file, if it is needed.
+     * 
+     * @param output
+     *            the output Object.
+     * @return the ImageOutputStream.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public ImageOutputStream createOutputStreamInstance(Object output) throws IOException {
+        return createOutputStreamInstance(output, true, null);
+    }
+
+    /**
+     * Creates the ImageOutputStream associated with this service provider. The
+     * output object should be an instance of the class returned by
+     * getInputClass method. This method uses the specified directory for the
+     * cache file, if the useCache parameter is true.
+     * 
+     * @param output
+     *            the output Object.
+     * @param useCache
+     *            the flag indicating if cache file is needed or not.
+     * @param cacheDir
+     *            the cache directory.
+     * @return the ImageOutputStream.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public abstract ImageOutputStream createOutputStreamInstance(Object output, boolean useCache,
+            File cacheDir) throws IOException;
+}
diff --git a/awt/javax/imageio/spi/ImageReaderSpi.java b/awt/javax/imageio/spi/ImageReaderSpi.java
new file mode 100644
index 0000000..0528d25
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageReaderSpi.java
@@ -0,0 +1,204 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.spi;
+
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.ImageReader;
+import java.io.IOException;
+
+/**
+ * The ImageReaderSpi abstract class is a service provider interface (SPI) for
+ * ImageReaders.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ImageReaderSpi extends ImageReaderWriterSpi {
+
+    /**
+     * The STANDARD_INPUT_TYPE contains ImageInputStream.class.
+     */
+    public static final Class[] STANDARD_INPUT_TYPE = new Class[] {
+        ImageInputStream.class
+    };
+
+    /**
+     * The input types.
+     */
+    protected Class[] inputTypes;
+
+    /**
+     * The writer SPI names.
+     */
+    protected String[] writerSpiNames;
+
+    /**
+     * Instantiates a new ImageReaderSpi.
+     */
+    protected ImageReaderSpi() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Instantiates a new ImageReaderSpi.
+     * 
+     * @param vendorName
+     *            the vendor name.
+     * @param version
+     *            the version.
+     * @param names
+     *            the format names.
+     * @param suffixes
+     *            the array of strings representing the file suffixes.
+     * @param MIMETypes
+     *            the an array of strings representing MIME types.
+     * @param pluginClassName
+     *            the plug-in class name.
+     * @param inputTypes
+     *            the input types.
+     * @param writerSpiNames
+     *            the array of strings with class names of all associated
+     *            ImageWriters.
+     * @param supportsStandardStreamMetadataFormat
+     *            the value indicating if stream metadata can be described by
+     *            standard metadata format.
+     * @param nativeStreamMetadataFormatName
+     *            the native stream metadata format name, returned by
+     *            getNativeStreamMetadataFormatName.
+     * @param nativeStreamMetadataFormatClassName
+     *            the native stream metadata format class name, returned by
+     *            getNativeStreamMetadataFormat.
+     * @param extraStreamMetadataFormatNames
+     *            the extra stream metadata format names, returned by
+     *            getExtraStreamMetadataFormatNames.
+     * @param extraStreamMetadataFormatClassNames
+     *            the extra stream metadata format class names, returned by
+     *            getStreamMetadataFormat.
+     * @param supportsStandardImageMetadataFormat
+     *            the value indicating if image metadata can be described by
+     *            standard metadata format.
+     * @param nativeImageMetadataFormatName
+     *            the native image metadata format name, returned by
+     *            getNativeImageMetadataFormatName.
+     * @param nativeImageMetadataFormatClassName
+     *            the native image metadata format class name, returned by
+     *            getNativeImageMetadataFormat.
+     * @param extraImageMetadataFormatNames
+     *            the extra image metadata format names, returned by
+     *            getExtraImageMetadataFormatNames.
+     * @param extraImageMetadataFormatClassNames
+     *            the extra image metadata format class names, returned by
+     *            getImageMetadataFormat.
+     */
+    public ImageReaderSpi(String vendorName, String version, String[] names, String[] suffixes,
+            String[] MIMETypes, String pluginClassName, Class[] inputTypes,
+            String[] writerSpiNames, boolean supportsStandardStreamMetadataFormat,
+            String nativeStreamMetadataFormatName, String nativeStreamMetadataFormatClassName,
+            String[] extraStreamMetadataFormatNames, String[] extraStreamMetadataFormatClassNames,
+            boolean supportsStandardImageMetadataFormat, String nativeImageMetadataFormatName,
+            String nativeImageMetadataFormatClassName, String[] extraImageMetadataFormatNames,
+            String[] extraImageMetadataFormatClassNames) {
+        super(vendorName, version, names, suffixes, MIMETypes, pluginClassName,
+                supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName,
+                nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames,
+                extraStreamMetadataFormatClassNames, supportsStandardImageMetadataFormat,
+                nativeImageMetadataFormatName, nativeImageMetadataFormatClassName,
+                extraImageMetadataFormatNames, extraImageMetadataFormatClassNames);
+
+        if (inputTypes == null || inputTypes.length == 0) {
+            throw new NullPointerException("input types array cannot be NULL or empty");
+        }
+        this.inputTypes = inputTypes;
+        this.writerSpiNames = writerSpiNames;
+    }
+
+    /**
+     * Gets an array of Class objects whose types can be used as input for this
+     * reader.
+     * 
+     * @return the input types.
+     */
+    public Class[] getInputTypes() {
+        return inputTypes;
+    }
+
+    /**
+     * Returns true if the format of source object is supported by this reader.
+     * 
+     * @param source
+     *            the source object to be decoded (for example an
+     *            ImageInputStream).
+     * @return true, if the format of source object is supported by this reader,
+     *         false otherwise.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public abstract boolean canDecodeInput(Object source) throws IOException;
+
+    /**
+     * Returns an instance of the ImageReader implementation for this service
+     * provider.
+     * 
+     * @return the ImageReader.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public ImageReader createReaderInstance() throws IOException {
+        return createReaderInstance(null);
+    }
+
+    /**
+     * Returns an instance of the ImageReader implementation for this service
+     * provider.
+     * 
+     * @param extension
+     *            the a plug-in specific extension object, or null.
+     * @return the ImageReader.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public abstract ImageReader createReaderInstance(Object extension) throws IOException;
+
+    /**
+     * Checks whether or not the specified ImageReader object is an instance of
+     * the ImageReader associated with this service provider or not.
+     * 
+     * @param reader
+     *            the ImageReader.
+     * @return true, if the specified ImageReader object is an instance of the
+     *         ImageReader associated with this service provider, false
+     *         otherwise.
+     */
+    public boolean isOwnReader(ImageReader reader) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets an array of strings with names of the ImageWriterSpi classes that
+     * support the internal metadata representation used by the ImageReader of
+     * this service provider, or null if there are no such ImageWriters.
+     * 
+     * @return the array of strings with names of the ImageWriterSpi classes.
+     */
+    public String[] getImageWriterSpiNames() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+}
diff --git a/awt/javax/imageio/spi/ImageReaderWriterSpi.java b/awt/javax/imageio/spi/ImageReaderWriterSpi.java
new file mode 100644
index 0000000..9ca08b5
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageReaderWriterSpi.java
@@ -0,0 +1,344 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.spi;
+
+import org.apache.harmony.x.imageio.metadata.IIOMetadataUtils;
+
+import javax.imageio.metadata.IIOMetadataFormat;
+
+/**
+ * The ImageReaderWriterSpi class is a superclass for the ImageReaderSpi and
+ * ImageWriterSpi SPIs.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ImageReaderWriterSpi extends IIOServiceProvider implements
+        RegisterableService {
+
+    /**
+     * The names.
+     */
+    protected String[] names;
+
+    /**
+     * The suffixes.
+     */
+    protected String[] suffixes;
+
+    /**
+     * The MIME types.
+     */
+    protected String[] MIMETypes;
+
+    /**
+     * The plug-in class name.
+     */
+    protected String pluginClassName;
+
+    /**
+     * Whether the reader/writer supports standard stream metadata format.
+     */
+    protected boolean supportsStandardStreamMetadataFormat;
+
+    /**
+     * The native stream metadata format name.
+     */
+    protected String nativeStreamMetadataFormatName;
+
+    /**
+     * The native stream metadata format class name.
+     */
+    protected String nativeStreamMetadataFormatClassName;
+
+    /**
+     * The extra stream metadata format names.
+     */
+    protected String[] extraStreamMetadataFormatNames;
+
+    /**
+     * The extra stream metadata format class names.
+     */
+    protected String[] extraStreamMetadataFormatClassNames;
+
+    /**
+     * Whether the reader/writer supports standard image metadata format.
+     */
+    protected boolean supportsStandardImageMetadataFormat;
+
+    /**
+     * The native image metadata format name.
+     */
+    protected String nativeImageMetadataFormatName;
+
+    /**
+     * The native image metadata format class name.
+     */
+    protected String nativeImageMetadataFormatClassName;
+
+    /**
+     * The extra image metadata format names.
+     */
+    protected String[] extraImageMetadataFormatNames;
+
+    /**
+     * The extra image metadata format class names.
+     */
+    protected String[] extraImageMetadataFormatClassNames;
+
+    /**
+     * Instantiates a new ImageReaderWriterSpi.
+     * 
+     * @param vendorName
+     *            the vendor name.
+     * @param version
+     *            the version.
+     * @param names
+     *            the format names.
+     * @param suffixes
+     *            the array of strings representing the file suffixes.
+     * @param MIMETypes
+     *            the an array of strings representing MIME types.
+     * @param pluginClassName
+     *            the plug-in class name.
+     * @param supportsStandardStreamMetadataFormat
+     *            the value indicating if stream metadata can be described by
+     *            standard metadata format.
+     * @param nativeStreamMetadataFormatName
+     *            the native stream metadata format name, returned by
+     *            getNativeStreamMetadataFormatName.
+     * @param nativeStreamMetadataFormatClassName
+     *            the native stream metadata format class name, returned by
+     *            getNativeStreamMetadataFormat.
+     * @param extraStreamMetadataFormatNames
+     *            the extra stream metadata format names, returned by
+     *            getExtraStreamMetadataFormatNames.
+     * @param extraStreamMetadataFormatClassNames
+     *            the extra stream metadata format class names, returned by
+     *            getStreamMetadataFormat.
+     * @param supportsStandardImageMetadataFormat
+     *            the value indicating if image metadata can be described by
+     *            standard metadata format.
+     * @param nativeImageMetadataFormatName
+     *            the native image metadata format name, returned by
+     *            getNativeImageMetadataFormatName.
+     * @param nativeImageMetadataFormatClassName
+     *            the native image metadata format class name, returned by
+     *            getNativeImageMetadataFormat.
+     * @param extraImageMetadataFormatNames
+     *            the extra image metadata format names, returned by
+     *            getExtraImageMetadataFormatNames.
+     * @param extraImageMetadataFormatClassNames
+     *            the extra image metadata format class names, returned by
+     *            getImageMetadataFormat.
+     */
+    public ImageReaderWriterSpi(String vendorName, String version, String[] names,
+            String[] suffixes, String[] MIMETypes, String pluginClassName,
+            boolean supportsStandardStreamMetadataFormat, String nativeStreamMetadataFormatName,
+            String nativeStreamMetadataFormatClassName, String[] extraStreamMetadataFormatNames,
+            String[] extraStreamMetadataFormatClassNames,
+            boolean supportsStandardImageMetadataFormat, String nativeImageMetadataFormatName,
+            String nativeImageMetadataFormatClassName, String[] extraImageMetadataFormatNames,
+            String[] extraImageMetadataFormatClassNames) {
+        super(vendorName, version);
+
+        if (names == null || names.length == 0) {
+            throw new NullPointerException("format names array cannot be NULL or empty");
+        }
+
+        if (pluginClassName == null) {
+            throw new NullPointerException("Plugin class name cannot be NULL");
+        }
+
+        // We clone all the arrays to be consistent with the fact that
+        // some methods of this class must return clones of the arrays
+        // as it is stated in the spec.
+        this.names = names.clone();
+        this.suffixes = suffixes == null ? null : suffixes.clone();
+        this.MIMETypes = MIMETypes == null ? null : MIMETypes.clone();
+        this.pluginClassName = pluginClassName;
+        this.supportsStandardStreamMetadataFormat = supportsStandardStreamMetadataFormat;
+        this.nativeStreamMetadataFormatName = nativeStreamMetadataFormatName;
+        this.nativeStreamMetadataFormatClassName = nativeStreamMetadataFormatClassName;
+
+        this.extraStreamMetadataFormatNames = extraStreamMetadataFormatNames == null ? null
+                : extraStreamMetadataFormatNames.clone();
+
+        this.extraStreamMetadataFormatClassNames = extraStreamMetadataFormatClassNames == null ? null
+                : extraStreamMetadataFormatClassNames.clone();
+
+        this.supportsStandardImageMetadataFormat = supportsStandardImageMetadataFormat;
+        this.nativeImageMetadataFormatName = nativeImageMetadataFormatName;
+        this.nativeImageMetadataFormatClassName = nativeImageMetadataFormatClassName;
+
+        this.extraImageMetadataFormatNames = extraImageMetadataFormatNames == null ? null
+                : extraImageMetadataFormatNames.clone();
+
+        this.extraImageMetadataFormatClassNames = extraImageMetadataFormatClassNames == null ? null
+                : extraImageMetadataFormatClassNames.clone();
+    }
+
+    /**
+     * Instantiates a new ImageReaderWriterSpi.
+     */
+    public ImageReaderWriterSpi() {
+    }
+
+    /**
+     * Gets an array of strings representing names of the formats that can be
+     * used by the ImageReader or ImageWriter implementation associated with
+     * this service provider.
+     * 
+     * @return the array of supported format names.
+     */
+    public String[] getFormatNames() {
+        return names.clone();
+    }
+
+    /**
+     * Gets an array of strings representing file suffixes associated with the
+     * formats that can be used by the ImageReader or ImageWriter implementation
+     * of this service provider.
+     * 
+     * @return the array of file suffixes.
+     */
+    public String[] getFileSuffixes() {
+        return suffixes == null ? null : suffixes.clone();
+    }
+
+    /**
+     * Gets an array of strings with the names of additional formats of the
+     * image metadata objects produced or consumed by this plug-in.
+     * 
+     * @return the array of extra image metadata format names.
+     */
+    public String[] getExtraImageMetadataFormatNames() {
+        return extraImageMetadataFormatNames == null ? null : extraImageMetadataFormatNames.clone();
+    }
+
+    /**
+     * Gets an array of strings with the names of additional formats of the
+     * stream metadata objects produced or consumed by this plug-in.
+     * 
+     * @return the array of extra stream metadata format names.
+     */
+    public String[] getExtraStreamMetadataFormatNames() {
+        return extraStreamMetadataFormatNames == null ? null : extraStreamMetadataFormatNames
+                .clone();
+    }
+
+    /**
+     * Gets an IIOMetadataFormat object for the specified image metadata format
+     * name.
+     * 
+     * @param formatName
+     *            the format name.
+     * @return the IIOMetadataFormat, or null.
+     */
+    public IIOMetadataFormat getImageMetadataFormat(String formatName) {
+        return IIOMetadataUtils.instantiateMetadataFormat(formatName,
+                supportsStandardImageMetadataFormat, nativeImageMetadataFormatName,
+                nativeImageMetadataFormatClassName, extraImageMetadataFormatNames,
+                extraImageMetadataFormatClassNames);
+    }
+
+    /**
+     * Gets an IIOMetadataFormat object for the specified stream metadata format
+     * name.
+     * 
+     * @param formatName
+     *            the format name.
+     * @return the IIOMetadataFormat, or null.
+     */
+    public IIOMetadataFormat getStreamMetadataFormat(String formatName) {
+        return IIOMetadataUtils.instantiateMetadataFormat(formatName,
+                supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName,
+                nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames,
+                extraStreamMetadataFormatClassNames);
+    }
+
+    /**
+     * Gets an array of strings representing the MIME types of the formats that
+     * are supported by the ImageReader or ImageWriter implementation of this
+     * service provider.
+     * 
+     * @return the array MIME types.
+     */
+    public String[] getMIMETypes() {
+        return MIMETypes == null ? null : MIMETypes.clone();
+    }
+
+    /**
+     * Gets the name of the native image metadata format for this reader/writer,
+     * which allows for lossless encoding or decoding of the image metadata with
+     * the format.
+     * 
+     * @return the string with native image metadata format name, or null.
+     */
+    public String getNativeImageMetadataFormatName() {
+        return nativeImageMetadataFormatName;
+    }
+
+    /**
+     * Gets the name of the native stream metadata format for this
+     * reader/writer, which allows for lossless encoding or decoding of the
+     * stream metadata with the format.
+     * 
+     * @return the string with native stream metadata format name, or null.
+     */
+    public String getNativeStreamMetadataFormatName() {
+        return nativeStreamMetadataFormatName;
+    }
+
+    /**
+     * Gets the class name of the ImageReader or ImageWriter associated with
+     * this service provider.
+     * 
+     * @return the class name.
+     */
+    public String getPluginClassName() {
+        return pluginClassName;
+    }
+
+    /**
+     * Checks if the standard metadata format is supported by the getAsTree and
+     * setFromTree methods for the image metadata objects produced or consumed
+     * by this reader or writer.
+     * 
+     * @return true, if standard image metadata format is supported, false
+     *         otherwise.
+     */
+    public boolean isStandardImageMetadataFormatSupported() {
+        return supportsStandardImageMetadataFormat;
+    }
+
+    /**
+     * Checks if the standard metadata format is supported by the getAsTree and
+     * setFromTree methods for the stream metadata objects produced or consumed
+     * by this reader or writer.
+     * 
+     * @return true, if standard stream metadata format is supported, false
+     *         otherwise.
+     */
+    public boolean isStandardStreamMetadataFormatSupported() {
+        return supportsStandardStreamMetadataFormat;
+    }
+}
diff --git a/awt/javax/imageio/spi/ImageTranscoderSpi.java b/awt/javax/imageio/spi/ImageTranscoderSpi.java
new file mode 100644
index 0000000..742af19
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageTranscoderSpi.java
@@ -0,0 +1,76 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.spi;
+
+import javax.imageio.ImageTranscoder;
+
+/**
+ * The ImageTranscoderSpi class is a service provider interface (SPI) for
+ * ImageTranscoders.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ImageTranscoderSpi extends IIOServiceProvider implements RegisterableService {
+
+    /**
+     * Instantiates a new ImageTranscoderSpi.
+     */
+    protected ImageTranscoderSpi() {
+    }
+
+    /**
+     * Instantiates a new ImageTranscoderSpi with the specified vendor name and
+     * version.
+     * 
+     * @param vendorName
+     *            the vendor name.
+     * @param version
+     *            the version.
+     */
+    public ImageTranscoderSpi(String vendorName, String version) {
+        super(vendorName, version);
+    }
+
+    /**
+     * Gets the class name of an ImageReaderSpi that produces IIOMetadata
+     * objects that can be used as input to this transcoder.
+     * 
+     * @return the class name of an ImageReaderSpi.
+     */
+    public abstract String getReaderServiceProviderName();
+
+    /**
+     * Gets the class name of an ImageWriterSpi that produces IIOMetadata
+     * objects that can be used as input to this transcoder.
+     * 
+     * @return the class name of an ImageWriterSpi.
+     */
+    public abstract String getWriterServiceProviderName();
+
+    /**
+     * Creates an instance of the ImageTranscoder associated with this service
+     * provider.
+     * 
+     * @return the ImageTranscoder instance.
+     */
+    public abstract ImageTranscoder createTranscoderInstance();
+}
diff --git a/awt/javax/imageio/spi/ImageWriterSpi.java b/awt/javax/imageio/spi/ImageWriterSpi.java
new file mode 100644
index 0000000..bf25455
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageWriterSpi.java
@@ -0,0 +1,227 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.spi;
+
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriter;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+
+/**
+ * The ImageWriterSpi abstract class is a service provider interface (SPI) for
+ * ImageWriters.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ImageWriterSpi extends ImageReaderWriterSpi {
+
+    /**
+     * The STANDARD_OUTPUT_TYPE contains ImageInputStream.class.
+     */
+    public static final Class[] STANDARD_OUTPUT_TYPE = new Class[] {
+        ImageInputStream.class
+    };
+
+    /**
+     * The output types.
+     */
+    protected Class[] outputTypes;
+
+    /**
+     * The reader SPI names.
+     */
+    protected String[] readerSpiNames;
+
+    /**
+     * Instantiates a new ImageWriterSpi.
+     */
+    protected ImageWriterSpi() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Instantiates a new ImageWriterSpi with the specified parameters.
+     * 
+     * @param vendorName
+     *            the vendor name.
+     * @param version
+     *            the version.
+     * @param names
+     *            the format names.
+     * @param suffixes
+     *            the array of strings representing the file suffixes.
+     * @param MIMETypes
+     *            the an array of strings representing MIME types.
+     * @param pluginClassName
+     *            the plug-in class name.
+     * @param outputTypes
+     *            the output types.
+     * @param readerSpiNames
+     *            the array of strings with class names of all associated
+     *            ImageReaders.
+     * @param supportsStandardStreamMetadataFormat
+     *            the value indicating if stream metadata can be described by
+     *            standard metadata format.
+     * @param nativeStreamMetadataFormatName
+     *            the native stream metadata format name, returned by
+     *            getNativeStreamMetadataFormatName.
+     * @param nativeStreamMetadataFormatClassName
+     *            the native stream metadata format class name, returned by
+     *            getNativeStreamMetadataFormat.
+     * @param extraStreamMetadataFormatNames
+     *            the extra stream metadata format names, returned by
+     *            getExtraStreamMetadataFormatNames.
+     * @param extraStreamMetadataFormatClassNames
+     *            the extra stream metadata format class names, returned by
+     *            getStreamMetadataFormat.
+     * @param supportsStandardImageMetadataFormat
+     *            the value indicating if image metadata can be described by
+     *            standard metadata format.
+     * @param nativeImageMetadataFormatName
+     *            the native image metadata format name, returned by
+     *            getNativeImageMetadataFormatName.
+     * @param nativeImageMetadataFormatClassName
+     *            the native image metadata format class name, returned by
+     *            getNativeImageMetadataFormat.
+     * @param extraImageMetadataFormatNames
+     *            the extra image metadata format names, returned by
+     *            getExtraImageMetadataFormatNames.
+     * @param extraImageMetadataFormatClassNames
+     *            the extra image metadata format class names, returned by
+     *            getImageMetadataFormat.
+     */
+    public ImageWriterSpi(String vendorName, String version, String[] names, String[] suffixes,
+            String[] MIMETypes, String pluginClassName, Class[] outputTypes,
+            String[] readerSpiNames, boolean supportsStandardStreamMetadataFormat,
+            String nativeStreamMetadataFormatName, String nativeStreamMetadataFormatClassName,
+            String[] extraStreamMetadataFormatNames, String[] extraStreamMetadataFormatClassNames,
+            boolean supportsStandardImageMetadataFormat, String nativeImageMetadataFormatName,
+            String nativeImageMetadataFormatClassName, String[] extraImageMetadataFormatNames,
+            String[] extraImageMetadataFormatClassNames) {
+        super(vendorName, version, names, suffixes, MIMETypes, pluginClassName,
+                supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName,
+                nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames,
+                extraStreamMetadataFormatClassNames, supportsStandardImageMetadataFormat,
+                nativeImageMetadataFormatName, nativeImageMetadataFormatClassName,
+                extraImageMetadataFormatNames, extraImageMetadataFormatClassNames);
+
+        if (outputTypes == null || outputTypes.length == 0) {
+            throw new NullPointerException("output types array cannot be NULL or empty");
+        }
+
+        this.outputTypes = outputTypes;
+        this.readerSpiNames = readerSpiNames;
+    }
+
+    /**
+     * Returns true if the format of the writer's output is lossless. The
+     * default implementation returns true.
+     * 
+     * @return true, if a format is lossless, false otherwise.
+     */
+    public boolean isFormatLossless() {
+        return true;
+    }
+
+    /**
+     * Gets an array of Class objects whose types can be used as output for this
+     * writer.
+     * 
+     * @return the output types.
+     */
+    public Class[] getOutputTypes() {
+        return outputTypes;
+    }
+
+    /**
+     * Checks whether or not the ImageWriter implementation associated with this
+     * service provider can encode an image with the specified type.
+     * 
+     * @param type
+     *            the ImageTypeSpecifier.
+     * @return true, if an image with the specified type can be encoded, false
+     *         otherwise.
+     */
+    public abstract boolean canEncodeImage(ImageTypeSpecifier type);
+
+    /**
+     * Checks whether or not the ImageWriter implementation associated with this
+     * service provider can encode the specified RenderedImage.
+     * 
+     * @param im
+     *            the RenderedImage.
+     * @return true, if RenderedImage can be encoded, false otherwise.
+     */
+    public boolean canEncodeImage(RenderedImage im) {
+        return canEncodeImage(ImageTypeSpecifier.createFromRenderedImage(im));
+    }
+
+    /**
+     * Returns an instance of the ImageWriter implementation for this service
+     * provider.
+     * 
+     * @return the ImageWriter.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public ImageWriter createWriterInstance() throws IOException {
+        return createWriterInstance(null);
+    }
+
+    /**
+     * Returns an instance of the ImageWriter implementation for this service
+     * provider.
+     * 
+     * @param extension
+     *            the a plug-in specific extension object, or null.
+     * @return the ImageWriter.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public abstract ImageWriter createWriterInstance(Object extension) throws IOException;
+
+    /**
+     * Checks whether or not the specified ImageWriter object is an instance of
+     * the ImageWriter associated with this service provider or not.
+     * 
+     * @param writer
+     *            the ImageWriter.
+     * @return true, if the specified ImageWriter object is an instance of the
+     *         ImageWriter associated with this service provider, false
+     *         otherwise.
+     */
+    public boolean isOwnWriter(ImageWriter writer) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets an array of strings with names of the ImageReaderSpi classes that
+     * support the internal metadata representation used by the ImageWriter of
+     * this service provider, or null if there are no such ImageReaders.
+     * 
+     * @return the array of strings with names of the ImageWriterSpi classes.
+     */
+    public String[] getImageReaderSpiNames() {
+        return readerSpiNames;
+    }
+}
diff --git a/awt/javax/imageio/spi/RegisterableService.java b/awt/javax/imageio/spi/RegisterableService.java
new file mode 100644
index 0000000..ae2f4d3
--- /dev/null
+++ b/awt/javax/imageio/spi/RegisterableService.java
@@ -0,0 +1,54 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.spi;
+
+/**
+ * The RegisterableService interface provides service provider objects that can
+ * be registered by a ServiceRegistry, and notifications that registration and
+ * deregistration have been performed.
+ * 
+ * @since Android 1.0
+ */
+public interface RegisterableService {
+
+    /**
+     * This method is called when the object which implements this interface is
+     * registered to the specified category of the specified registry.
+     * 
+     * @param registry
+     *            the ServiceRegistry to be registered.
+     * @param category
+     *            the class representing a category.
+     */
+    void onRegistration(ServiceRegistry registry, Class<?> category);
+
+    /**
+     * This method is called when the object which implements this interface is
+     * deregistered to the specified category of the specified registry.
+     * 
+     * @param registry
+     *            the ServiceRegistry to be registered.
+     * @param category
+     *            the class representing a category.
+     */
+    void onDeregistration(ServiceRegistry registry, Class<?> category);
+}
diff --git a/awt/javax/imageio/spi/ServiceRegistry.java b/awt/javax/imageio/spi/ServiceRegistry.java
new file mode 100644
index 0000000..79b02a3
--- /dev/null
+++ b/awt/javax/imageio/spi/ServiceRegistry.java
@@ -0,0 +1,552 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.spi;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * The ServiceRegistry class provides ability to register, deregister, look up
+ * and obtain service provider instances (SPIs). A service means a set of
+ * interfaces and classes, and a service provider is an implementation of a
+ * service. Service providers can be associated with one or more categories.
+ * Each category is defined by a class or interface. Only a single instance of a
+ * each class is allowed to be registered as a category.
+ * 
+ * @since Android 1.0
+ */
+public class ServiceRegistry {
+
+    /**
+     * The categories.
+     */
+    CategoriesMap categories = new CategoriesMap(this);
+
+    /**
+     * Instantiates a new ServiceRegistry with the specified categories.
+     * 
+     * @param categoriesIterator
+     *            an Iterator of Class objects for defining of categories.
+     */
+    public ServiceRegistry(Iterator<Class<?>> categoriesIterator) {
+        if (null == categoriesIterator) {
+            throw new IllegalArgumentException("categories iterator should not be NULL");
+        }
+        while (categoriesIterator.hasNext()) {
+            Class<?> c = categoriesIterator.next();
+            categories.addCategory(c);
+        }
+    }
+
+    /**
+     * Looks up and instantiates the available providers of this service using
+     * the specified class loader.
+     * 
+     * @param providerClass
+     *            the Class object of the provider to be looked up.
+     * @param loader
+     *            the class loader to be used.
+     * @return the iterator of providers objects for this service.
+     */
+    public static <T> Iterator<T> lookupProviders(Class<T> providerClass, ClassLoader loader) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Looks up and instantiates the available providers of this service using
+     * the context class loader.
+     * 
+     * @param providerClass
+     *            the Class object of the provider to be looked up.
+     * @return the iterator of providers objects for this service.
+     */
+    public static <T> Iterator<T> lookupProviders(Class<T> providerClass) {
+        return lookupProviders(providerClass, Thread.currentThread().getContextClassLoader());
+    }
+
+    /**
+     * Registers the specified service provider object in the specified
+     * categories.
+     * 
+     * @param provider
+     *            the specified provider to be registered.
+     * @param category
+     *            the category.
+     * @return true, if no provider of the same class is registered in this
+     *         category, false otherwise.
+     */
+    public <T> boolean registerServiceProvider(T provider, Class<T> category) {
+        return categories.addProvider(provider, category);
+    }
+
+    /**
+     * Registers a list of service providers.
+     * 
+     * @param providers
+     *            the list of service providers.
+     */
+    public void registerServiceProviders(Iterator<?> providers) {
+        for (Iterator<?> iterator = providers; iterator.hasNext();) {
+            categories.addProvider(iterator.next(), null);
+        }
+    }
+
+    /**
+     * Registers the specified service provider object in all categories.
+     * 
+     * @param provider
+     *            the service provider.
+     */
+    public void registerServiceProvider(Object provider) {
+        categories.addProvider(provider, null);
+    }
+
+    /**
+     * Deregisters the specifies service provider from the specified category.
+     * 
+     * @param provider
+     *            the service provider to be deregistered.
+     * @param category
+     *            the specified category.
+     * @return true, if the provider was already registered in the specified
+     *         category, false otherwise.
+     */
+    public <T> boolean deregisterServiceProvider(T provider, Class<T> category) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Deregisters the specified service provider from all categories.
+     * 
+     * @param provider
+     *            the specified service provider.
+     */
+    public void deregisterServiceProvider(Object provider) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets an Iterator of registered service providers in the specified
+     * category which satisfy the specified Filter. The useOrdering parameter
+     * indicates whether the iterator will return all of the server provider
+     * objects in a set order.
+     * 
+     * @param category
+     *            the specified category.
+     * @param filter
+     *            the specified filter.
+     * @param useOrdering
+     *            the flag indicating that providers are ordered in the returned
+     *            Iterator.
+     * @return the iterator of registered service providers.
+     */
+    @SuppressWarnings("unchecked")
+    public <T> Iterator<T> getServiceProviders(Class<T> category, Filter filter, boolean useOrdering) {
+        return new FilteredIterator<T>(filter, (Iterator<T>)categories.getProviders(category,
+                useOrdering));
+    }
+
+    /**
+     * Gets an Iterator of all registered service providers in the specified
+     * category. The useOrdering parameter indicates whether the iterator will
+     * return all of the server provider objects in a set order.
+     * 
+     * @param category
+     *            the specified category.
+     * @param useOrdering
+     *            the flag indicating that providers are ordered in the returned
+     *            Iterator.
+     * @return the Iterator of service providers.
+     */
+    @SuppressWarnings("unchecked")
+    public <T> Iterator<T> getServiceProviders(Class<T> category, boolean useOrdering) {
+        return (Iterator<T>)categories.getProviders(category, useOrdering);
+    }
+
+    /**
+     * Gets the registered service provider object that has the specified class
+     * type.
+     * 
+     * @param providerClass
+     *            the specified provider class.
+     * @return the service provider object.
+     */
+    public <T> T getServiceProviderByClass(Class<T> providerClass) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Sets an ordering between two service provider objects within the
+     * specified category.
+     * 
+     * @param category
+     *            the specified category.
+     * @param firstProvider
+     *            the first provider.
+     * @param secondProvider
+     *            the second provider.
+     * @return true, if a previously unset order was set.
+     */
+    public <T> boolean setOrdering(Class<T> category, T firstProvider, T secondProvider) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Unsets an ordering between two service provider objects within the
+     * specified category.
+     * 
+     * @param category
+     *            the specified category.
+     * @param firstProvider
+     *            the first provider.
+     * @param secondProvider
+     *            the second provider.
+     * @return true, if a previously unset order was removed.
+     */
+    public <T> boolean unsetOrdering(Class<T> category, T firstProvider, T secondProvider) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Deregisters all providers from the specified category.
+     * 
+     * @param category
+     *            the specified category.
+     */
+    public void deregisterAll(Class<?> category) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Deregister all providers from all categories.
+     */
+    public void deregisterAll() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Finalizes this object.
+     * 
+     * @throws Throwable
+     *             if an error occurs during finalization.
+     */
+    @Override
+    public void finalize() throws Throwable {
+        // TODO uncomment when deregisterAll is implemented
+        // deregisterAll();
+    }
+
+    /**
+     * Checks whether the specified provider has been already registered.
+     * 
+     * @param provider
+     *            the provider to be checked.
+     * @return true, if the specified provider has been already registered,
+     *         false otherwise.
+     */
+    public boolean contains(Object provider) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets an iterator of Class objects representing the current categories.
+     * 
+     * @return the Iterator of Class objects.
+     */
+    public Iterator<Class<?>> getCategories() {
+        return categories.list();
+    }
+
+    /**
+     * The ServiceRegistry.Filter interface is used by
+     * ServiceRegistry.getServiceProviders to filter providers according to the
+     * specified criterion.
+     * 
+     * @since Android 1.0
+     */
+    public static interface Filter {
+
+        /**
+         * Returns true if the specified provider satisfies the criterion of
+         * this Filter.
+         * 
+         * @param provider
+         *            the provider.
+         * @return true, if the specified provider satisfies the criterion of
+         *         this Filter, false otherwise.
+         */
+        boolean filter(Object provider);
+    }
+
+    /**
+     * The Class CategoriesMap.
+     */
+    private static class CategoriesMap {
+
+        /**
+         * The categories.
+         */
+        Map<Class<?>, ProvidersMap> categories = new HashMap<Class<?>, ProvidersMap>();
+
+        /**
+         * The registry.
+         */
+        ServiceRegistry registry;
+
+        /**
+         * Instantiates a new categories map.
+         * 
+         * @param registry
+         *            the registry.
+         */
+        public CategoriesMap(ServiceRegistry registry) {
+            this.registry = registry;
+        }
+
+        // -- TODO: useOrdering
+        /**
+         * Gets the providers.
+         * 
+         * @param category
+         *            the category.
+         * @param useOrdering
+         *            the use ordering.
+         * @return the providers.
+         */
+        Iterator<?> getProviders(Class<?> category, boolean useOrdering) {
+            ProvidersMap providers = categories.get(category);
+            if (null == providers) {
+                throw new IllegalArgumentException("Unknown category: " + category);
+            }
+            return providers.getProviders(useOrdering);
+        }
+
+        /**
+         * List.
+         * 
+         * @return the iterator< class<?>>.
+         */
+        Iterator<Class<?>> list() {
+            return categories.keySet().iterator();
+        }
+
+        /**
+         * Adds the category.
+         * 
+         * @param category
+         *            the category.
+         */
+        void addCategory(Class<?> category) {
+            categories.put(category, new ProvidersMap());
+        }
+
+        /**
+         * Adds a provider to the category. If <code>category</code> is
+         * <code>null</code> then the provider will be added to all categories
+         * which the provider is assignable from.
+         * 
+         * @param provider
+         *            provider to add.
+         * @param category
+         *            category to add provider to.
+         * @return true, if there were such provider in some category.
+         */
+        boolean addProvider(Object provider, Class<?> category) {
+            if (provider == null) {
+                throw new IllegalArgumentException("provider should be != NULL");
+            }
+
+            boolean rt;
+            if (category == null) {
+                rt = findAndAdd(provider);
+            } else {
+                rt = addToNamed(provider, category);
+            }
+
+            if (provider instanceof RegisterableService) {
+                ((RegisterableService)provider).onRegistration(registry, category);
+            }
+
+            return rt;
+        }
+
+        /**
+         * Adds the to named.
+         * 
+         * @param provider
+         *            the provider.
+         * @param category
+         *            the category.
+         * @return true, if successful.
+         */
+        private boolean addToNamed(Object provider, Class<?> category) {
+            Object obj = categories.get(category);
+
+            if (null == obj) {
+                throw new IllegalArgumentException("Unknown category: " + category);
+            }
+
+            return ((ProvidersMap)obj).addProvider(provider);
+        }
+
+        /**
+         * Find and add.
+         * 
+         * @param provider
+         *            the provider.
+         * @return true, if successful.
+         */
+        private boolean findAndAdd(Object provider) {
+            boolean rt = false;
+            for (Entry<Class<?>, ProvidersMap> e : categories.entrySet()) {
+                if (e.getKey().isAssignableFrom(provider.getClass())) {
+                    rt |= e.getValue().addProvider(provider);
+                }
+            }
+            return rt;
+        }
+    }
+
+    /**
+     * The Class ProvidersMap.
+     */
+    private static class ProvidersMap {
+        // -- TODO: providers ordering support
+
+        /**
+         * The providers.
+         */
+        Map<Class<?>, Object> providers = new HashMap<Class<?>, Object>();
+
+        /**
+         * Adds the provider.
+         * 
+         * @param provider
+         *            the provider.
+         * @return true, if successful.
+         */
+        boolean addProvider(Object provider) {
+            return providers.put(provider.getClass(), provider) != null;
+        }
+
+        /**
+         * Gets the provider classes.
+         * 
+         * @return the provider classes.
+         */
+        Iterator<Class<?>> getProviderClasses() {
+            return providers.keySet().iterator();
+        }
+
+        // -- TODO ordering
+        /**
+         * Gets the providers.
+         * 
+         * @param userOrdering
+         *            the user ordering.
+         * @return the providers.
+         */
+        Iterator<?> getProviders(boolean userOrdering) {
+            return providers.values().iterator();
+        }
+    }
+
+    /**
+     * The Class FilteredIterator.
+     */
+    private static class FilteredIterator<E> implements Iterator<E> {
+
+        /**
+         * The filter.
+         */
+        private Filter filter;
+
+        /**
+         * The backend.
+         */
+        private Iterator<E> backend;
+
+        /**
+         * The next obj.
+         */
+        private E nextObj;
+
+        /**
+         * Instantiates a new filtered iterator.
+         * 
+         * @param filter
+         *            the filter.
+         * @param backend
+         *            the backend.
+         */
+        public FilteredIterator(Filter filter, Iterator<E> backend) {
+            this.filter = filter;
+            this.backend = backend;
+            findNext();
+        }
+
+        /**
+         * Next.
+         * 
+         * @return the e.
+         */
+        public E next() {
+            if (nextObj == null) {
+                throw new NoSuchElementException();
+            }
+            E tmp = nextObj;
+            findNext();
+            return tmp;
+        }
+
+        /**
+         * Checks for next.
+         * 
+         * @return true, if successful.
+         */
+        public boolean hasNext() {
+            return nextObj != null;
+        }
+
+        /**
+         * Removes the.
+         */
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Sets nextObj to a next provider matching the criterion given by the
+         * filter.
+         */
+        private void findNext() {
+            nextObj = null;
+            while (backend.hasNext()) {
+                E o = backend.next();
+                if (filter.filter(o)) {
+                    nextObj = o;
+                    return;
+                }
+            }
+        }
+    }
+}
diff --git a/awt/javax/imageio/spi/package.html b/awt/javax/imageio/spi/package.html
new file mode 100644
index 0000000..18ceff4
--- /dev/null
+++ b/awt/javax/imageio/spi/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+    This package provides several Service Provider Interface (SPI) classes for readers, writers, transcoders and streams to handle images.
+    </p>
+  @since Android 1.0
+  </body>
+</html>
diff --git a/awt/javax/imageio/stream/FileCacheImageInputStream.java b/awt/javax/imageio/stream/FileCacheImageInputStream.java
new file mode 100644
index 0000000..710ac66
--- /dev/null
+++ b/awt/javax/imageio/stream/FileCacheImageInputStream.java
@@ -0,0 +1,137 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.stream;
+
+import java.io.*;
+
+/**
+ * The FileCacheImageInputStream class is an implementation of ImageInputStream
+ * which reads from its InputStream and uses a temporary file as a cache.
+ * 
+ * @since Android 1.0
+ */
+public class FileCacheImageInputStream extends ImageInputStreamImpl {
+
+    /**
+     * The is.
+     */
+    private InputStream is;
+
+    /**
+     * The file.
+     */
+    private File file;
+
+    /**
+     * The raf.
+     */
+    private RandomAccessFile raf;
+
+    /**
+     * Instantiates a new FileCacheImageInputStream from the specified
+     * InputStream and using the specified File as its cache directory.
+     * 
+     * @param stream
+     *            the InputStream for reading.
+     * @param cacheDir
+     *            the cache directory where the cache file will be created.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public FileCacheImageInputStream(InputStream stream, File cacheDir) throws IOException {
+        if (stream == null) {
+            throw new IllegalArgumentException("stream == null!");
+        }
+        is = stream;
+
+        if (cacheDir == null || cacheDir.isDirectory()) {
+            file = File.createTempFile(FileCacheImageOutputStream.IIO_TEMP_FILE_PREFIX, null,
+                    cacheDir);
+            file.deleteOnExit();
+        } else {
+            throw new IllegalArgumentException("Not a directory!");
+        }
+
+        raf = new RandomAccessFile(file, "rw");
+    }
+
+    @Override
+    public int read() throws IOException {
+        bitOffset = 0;
+
+        if (streamPos >= raf.length()) {
+            int b = is.read();
+
+            if (b < 0) {
+                return -1;
+            }
+
+            raf.seek(streamPos++);
+            raf.write(b);
+            return b;
+        }
+
+        raf.seek(streamPos++);
+        return raf.read();
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        bitOffset = 0;
+
+        if (streamPos >= raf.length()) {
+            int nBytes = is.read(b, off, len);
+
+            if (nBytes < 0) {
+                return -1;
+            }
+
+            raf.seek(streamPos);
+            raf.write(b, off, nBytes);
+            streamPos += nBytes;
+            return nBytes;
+        }
+
+        raf.seek(streamPos);
+        int nBytes = raf.read(b, off, len);
+        streamPos += nBytes;
+        return nBytes;
+    }
+
+    @Override
+    public boolean isCached() {
+        return true;
+    }
+
+    @Override
+    public boolean isCachedFile() {
+        return true;
+    }
+
+    @Override
+    public boolean isCachedMemory() {
+        return false;
+    }
+
+    @Override
+    public void close() throws IOException {
+        super.close();
+        raf.close();
+        file.delete();
+    }
+}
diff --git a/awt/javax/imageio/stream/FileCacheImageOutputStream.java b/awt/javax/imageio/stream/FileCacheImageOutputStream.java
new file mode 100644
index 0000000..135afab
--- /dev/null
+++ b/awt/javax/imageio/stream/FileCacheImageOutputStream.java
@@ -0,0 +1,196 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.stream;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+
+/**
+ * The FileCacheImageOutputStream class is an implementation of
+ * ImageOutputStream that writes to its OutputStream using a temporary file as a
+ * cache.
+ * 
+ * @since Android 1.0
+ */
+public class FileCacheImageOutputStream extends ImageOutputStreamImpl {
+
+    /**
+     * The Constant IIO_TEMP_FILE_PREFIX.
+     */
+    static final String IIO_TEMP_FILE_PREFIX = "iioCache";
+
+    /**
+     * The Constant MAX_BUFFER_LEN.
+     */
+    static final int MAX_BUFFER_LEN = 1048575; // 1 MB - is it not too much?
+
+    /**
+     * The os.
+     */
+    private OutputStream os;
+
+    /**
+     * The file.
+     */
+    private File file;
+
+    /**
+     * The raf.
+     */
+    private RandomAccessFile raf;
+
+    /**
+     * Instantiates a FileCacheImageOutputStream.
+     * 
+     * @param stream
+     *            the OutputStream for writing.
+     * @param cacheDir
+     *            the cache directory where the cache file will be created.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public FileCacheImageOutputStream(OutputStream stream, File cacheDir) throws IOException {
+        if (stream == null) {
+            throw new IllegalArgumentException("stream == null!");
+        }
+        os = stream;
+
+        if (cacheDir == null || cacheDir.isDirectory()) {
+            file = File.createTempFile(IIO_TEMP_FILE_PREFIX, null, cacheDir);
+            file.deleteOnExit();
+        } else {
+            throw new IllegalArgumentException("Not a directory!");
+        }
+
+        raf = new RandomAccessFile(file, "rw");
+    }
+
+    @Override
+    public void close() throws IOException {
+        flushBefore(raf.length());
+        super.close();
+        raf.close();
+        file.delete();
+    }
+
+    @Override
+    public boolean isCached() {
+        return true;
+    }
+
+    @Override
+    public boolean isCachedFile() {
+        return true;
+    }
+
+    @Override
+    public boolean isCachedMemory() {
+        return false;
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        flushBits(); // See the flushBits method description
+
+        raf.write(b);
+        streamPos++;
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException {
+        flushBits(); // See the flushBits method description
+
+        raf.write(b, off, len);
+        streamPos += len;
+    }
+
+    @Override
+    public int read() throws IOException {
+        bitOffset = 0; // Should reset
+
+        int res = raf.read();
+        if (res >= 0) {
+            streamPos++;
+        }
+
+        return res;
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        bitOffset = 0;
+
+        int numRead = raf.read(b, off, len);
+        if (numRead > 0) {
+            streamPos += numRead;
+        }
+
+        return numRead;
+    }
+
+    @Override
+    public void flushBefore(long pos) throws IOException {
+        long readFromPos = flushedPos;
+        super.flushBefore(pos);
+
+        long bytesToRead = pos - readFromPos;
+        raf.seek(readFromPos);
+
+        if (bytesToRead < MAX_BUFFER_LEN) {
+            byte buffer[] = new byte[(int)bytesToRead];
+            raf.readFully(buffer);
+            os.write(buffer);
+        } else {
+            byte buffer[] = new byte[MAX_BUFFER_LEN];
+            while (bytesToRead > 0) {
+                int count = (int)Math.min(MAX_BUFFER_LEN, bytesToRead);
+                raf.readFully(buffer, 0, count);
+                os.write(buffer, 0, count);
+                bytesToRead -= count;
+            }
+        }
+
+        os.flush();
+
+        if (pos != streamPos) {
+            raf.seek(streamPos); // Reset the position
+        }
+    }
+
+    @Override
+    public void seek(long pos) throws IOException {
+        if (pos < flushedPos) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        raf.seek(pos);
+        streamPos = raf.getFilePointer();
+        bitOffset = 0;
+    }
+
+    @Override
+    public long length() {
+        try {
+            return raf.length();
+        } catch (IOException e) {
+            return -1L;
+        }
+    }
+}
diff --git a/awt/javax/imageio/stream/FileImageInputStream.java b/awt/javax/imageio/stream/FileImageInputStream.java
new file mode 100644
index 0000000..b9b6002
--- /dev/null
+++ b/awt/javax/imageio/stream/FileImageInputStream.java
@@ -0,0 +1,122 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.stream;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * The FileImageInputStream class implements ImageInputStream and obtains its
+ * input data from a File or RandomAccessFile.
+ * 
+ * @since Android 1.0
+ */
+public class FileImageInputStream extends ImageInputStreamImpl {
+
+    /**
+     * The raf.
+     */
+    RandomAccessFile raf;
+
+    /**
+     * Instantiates a new FileImageInputStream from the specified File.
+     * 
+     * @param f
+     *            the File of input data.
+     * @throws FileNotFoundException
+     *             if the specified file doesn't exist.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    @SuppressWarnings( {
+        "DuplicateThrows"
+    })
+    public FileImageInputStream(File f) throws FileNotFoundException, IOException {
+        if (f == null) {
+            throw new IllegalArgumentException("f == null!");
+        }
+
+        raf = new RandomAccessFile(f, "r");
+    }
+
+    /**
+     * Instantiates a new FileImageInputStream from the specified
+     * RandomAccessFile.
+     * 
+     * @param raf
+     *            the RandomAccessFile of input data.
+     */
+    public FileImageInputStream(RandomAccessFile raf) {
+        if (raf == null) {
+            throw new IllegalArgumentException("raf == null!");
+        }
+
+        this.raf = raf;
+    }
+
+    @Override
+    public int read() throws IOException {
+        bitOffset = 0;
+
+        int res = raf.read();
+        if (res != -1) {
+            streamPos++;
+        }
+        return res;
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        bitOffset = 0;
+
+        int numRead = raf.read(b, off, len);
+        if (numRead >= 0) {
+            streamPos += numRead;
+        }
+
+        return numRead;
+    }
+
+    @Override
+    public long length() {
+        try {
+            return raf.length();
+        } catch (IOException e) {
+            return -1L;
+        }
+    }
+
+    @Override
+    public void seek(long pos) throws IOException {
+        if (pos < getFlushedPosition()) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        raf.seek(pos);
+        streamPos = raf.getFilePointer();
+        bitOffset = 0;
+    }
+
+    @Override
+    public void close() throws IOException {
+        super.close();
+        raf.close();
+    }
+}
diff --git a/awt/javax/imageio/stream/FileImageOutputStream.java b/awt/javax/imageio/stream/FileImageOutputStream.java
new file mode 100644
index 0000000..2730ba6
--- /dev/null
+++ b/awt/javax/imageio/stream/FileImageOutputStream.java
@@ -0,0 +1,128 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.stream;
+
+import java.io.*;
+
+/**
+ * The FileImageOutputStream class implements ImageOutputStream and writes the
+ * output data to a File or RandomAccessFile.
+ * 
+ * @since Android 1.0
+ */
+public class FileImageOutputStream extends ImageOutputStreamImpl {
+
+    /**
+     * The file.
+     */
+    RandomAccessFile file;
+
+    /**
+     * Instantiates a new FileImageOutputStream with the specified File.
+     * 
+     * @param f
+     *            the output File.
+     * @throws FileNotFoundException
+     *             if the file not found.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    public FileImageOutputStream(File f) throws FileNotFoundException, IOException {
+        this(f != null ? new RandomAccessFile(f, "rw") : null);
+    }
+
+    /**
+     * Instantiates a new FileImageOutputStream with the specified
+     * RandomAccessFile.
+     * 
+     * @param raf
+     *            the output RandomAccessFile.
+     */
+    public FileImageOutputStream(RandomAccessFile raf) {
+        if (raf == null) {
+            throw new IllegalArgumentException("file should not be NULL");
+        }
+        file = raf;
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        checkClosed();
+        // according to the spec for ImageOutputStreamImpl#flushBits()
+        flushBits();
+        file.write(b);
+        streamPos++;
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException {
+        checkClosed();
+        // according to the spec for ImageOutputStreamImpl#flushBits()
+        flushBits();
+        file.write(b, off, len);
+        streamPos += len;
+    }
+
+    @Override
+    public int read() throws IOException {
+        checkClosed();
+        int rt = file.read();
+        if (rt != -1) {
+            streamPos++;
+        }
+        return rt;
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        checkClosed();
+        int rt = file.read(b, off, len);
+        if (rt != -1) {
+            streamPos += rt;
+        }
+        return rt;
+    }
+
+    @Override
+    public long length() {
+        try {
+            checkClosed();
+            return file.length();
+        } catch (IOException e) {
+            return super.length(); // -1L
+        }
+    }
+
+    @Override
+    public void seek(long pos) throws IOException {
+        // -- checkClosed() is performed in super.seek()
+        super.seek(pos);
+        file.seek(pos);
+        streamPos = file.getFilePointer();
+    }
+
+    @Override
+    public void close() throws IOException {
+        super.close();
+        file.close();
+    }
+}
diff --git a/awt/javax/imageio/stream/IIOByteBuffer.java b/awt/javax/imageio/stream/IIOByteBuffer.java
new file mode 100644
index 0000000..867d808
--- /dev/null
+++ b/awt/javax/imageio/stream/IIOByteBuffer.java
@@ -0,0 +1,124 @@
+/*
+ *  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.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+package javax.imageio.stream;
+
+// 
+// @author Sergey I. Salishev
+// @version $Revision: 1.2 $
+//
+
+/**
+ * The IIOByteBuffer class represents a byte array with offset and length that
+ * is used by ImageInputStream for obtaining a sequence of bytes.
+ * 
+ * @since Android 1.0
+ */
+public class IIOByteBuffer {
+
+    /**
+     * The data.
+     */
+    private byte[] data;
+
+    /**
+     * The offset.
+     */
+    private int offset;
+
+    /**
+     * The length.
+     */
+    private int length;
+
+    /**
+     * Instantiates a new IIOByteBuffer.
+     * 
+     * @param data
+     *            the byte array.
+     * @param offset
+     *            the offset in the array.
+     * @param length
+     *            the length of array.
+     */
+    public IIOByteBuffer(byte[] data, int offset, int length) {
+        this.data = data;
+        this.offset = offset;
+        this.length = length;
+    }
+
+    /**
+     * Gets the byte array of this IIOByteBuffer.
+     * 
+     * @return the byte array.
+     */
+    public byte[] getData() {
+        return data;
+    }
+
+    /**
+     * Gets the length in the array which will be used.
+     * 
+     * @return the length of the data.
+     */
+    public int getLength() {
+        return length;
+    }
+
+    /**
+     * Gets the offset of this IIOByteBuffer.
+     * 
+     * @return the offset of this IIOByteBuffer.
+     */
+    public int getOffset() {
+        return offset;
+    }
+
+    /**
+     * Sets the new data array to this IIOByteBuffer object.
+     * 
+     * @param data
+     *            the new data array.
+     */
+    public void setData(byte[] data) {
+        this.data = data;
+    }
+
+    /**
+     * Sets the length of data which will be used.
+     * 
+     * @param length
+     *            the new length.
+     */
+    public void setLength(int length) {
+        this.length = length;
+    }
+
+    /**
+     * Sets the offset in the data array of this IIOByteBuffer.
+     * 
+     * @param offset
+     *            the new offset.
+     */
+    public void setOffset(int offset) {
+        this.offset = offset;
+    }
+}
diff --git a/awt/javax/imageio/stream/ImageInputStream.java b/awt/javax/imageio/stream/ImageInputStream.java
new file mode 100644
index 0000000..3dec5d2
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageInputStream.java
@@ -0,0 +1,502 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+
+package javax.imageio.stream;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+/**
+ * The ImageInputStream represents input stream interface that is used by
+ * ImageReaders.
+ * 
+ * @since Android 1.0
+ */
+public interface ImageInputStream extends DataInput {
+
+    /**
+     * Sets the specified byte order for reading of data values from this
+     * stream.
+     * 
+     * @param byteOrder
+     *            the byte order.
+     */
+    void setByteOrder(ByteOrder byteOrder);
+
+    /**
+     * Gets the byte order.
+     * 
+     * @return the byte order.
+     */
+    ByteOrder getByteOrder();
+
+    /**
+     * Reads a byte from the stream.
+     * 
+     * @return the byte of the stream, or -1 for EOF indicating.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    int read() throws IOException;
+
+    /**
+     * Reads number of bytes which is equal to the specified array's length and
+     * stores a result to this array.
+     * 
+     * @param b
+     *            the byte array.
+     * @return the number of read bytes, or -1 indicated EOF.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    int read(byte[] b) throws IOException;
+
+    /**
+     * Reads the number of bytes specified by len parameter from the stream and
+     * stores a result to the specified array with the specified offset.
+     * 
+     * @param b
+     *            the byte array.
+     * @param off
+     *            the offset.
+     * @param len
+     *            the number of bytes to be read.
+     * @return the number of read bytes, or -1 indicated EOF.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    int read(byte[] b, int off, int len) throws IOException;
+
+    /**
+     * Reads the number of bytes specified by len parameter from the stream, and
+     * modifies the specified IIOByteBuffer with the byte array, offset, and
+     * length.
+     * 
+     * @param buf
+     *            the IIOByteBuffer.
+     * @param len
+     *            the number of bytes to be read.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void readBytes(IIOByteBuffer buf, int len) throws IOException;
+
+    /**
+     * Reads a byte from the stream and returns a boolean true value if it is
+     * non zero, false if it is zero.
+     * 
+     * @return the boolean value for read byte.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    boolean readBoolean() throws IOException;
+
+    /**
+     * Reads a byte from the stream and returns its value as signed byte.
+     * 
+     * @return the signed byte value for read byte.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    byte readByte() throws IOException;
+
+    /**
+     * Reads a byte from the stream and returns its value as an integer.
+     * 
+     * @return the unsigned byte value for read byte as an integer.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    int readUnsignedByte() throws IOException;
+
+    /**
+     * Reads 2 bytes from the stream, and returns the result as a short.
+     * 
+     * @return the signed short value from the stream.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    short readShort() throws IOException;
+
+    /**
+     * Reads 2 bytes from the stream and returns its value as an unsigned short.
+     * 
+     * @return a unsigned short value coded in an integer.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    int readUnsignedShort() throws IOException;
+
+    /**
+     * Reads 2 bytes from the stream and returns their unsigned char value.
+     * 
+     * @return the unsigned char value.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    char readChar() throws IOException;
+
+    /**
+     * Reads 4 bytes from the stream, and returns the result as an integer.
+     * 
+     * @return the signed integer value from the stream.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    int readInt() throws IOException;
+
+    /**
+     * Reads 4 bytes from the stream and returns its value as long.
+     * 
+     * @return the unsigned integer value as long.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    long readUnsignedInt() throws IOException;
+
+    /**
+     * Reads 8 bytes from the stream, and returns the result as a long.
+     * 
+     * @return the long value from the stream.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    long readLong() throws IOException;
+
+    /**
+     * Reads 4 bytes from the stream, and returns the result as a float.
+     * 
+     * @return the float value from the stream.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    float readFloat() throws IOException;
+
+    /**
+     * Reads 8 bytes from the stream, and returns the result as a double.
+     * 
+     * @return the double value from the stream.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    double readDouble() throws IOException;
+
+    /**
+     * Reads a line from the stream.
+     * 
+     * @return the string contained the line from the stream.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    String readLine() throws IOException;
+
+    /**
+     * Reads bytes from the stream in a string that has been encoded in a
+     * modified UTF-8 format.
+     * 
+     * @return the string read from stream and modified UTF-8 format.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    String readUTF() throws IOException;
+
+    /**
+     * Reads the specified number of bytes from the stream, and stores the
+     * result into the specified array starting at the specified index offset.
+     * 
+     * @param b
+     *            the byte array.
+     * @param off
+     *            the offset.
+     * @param len
+     *            the number of bytes to be read.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void readFully(byte[] b, int off, int len) throws IOException;
+
+    /**
+     * Reads number of bytes from the stream which is equal to the specified
+     * array's length, and stores them into this array.
+     * 
+     * @param b
+     *            the byte array.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void readFully(byte[] b) throws IOException;
+
+    /**
+     * Reads the specified number of shorts from the stream, and stores the
+     * result into the specified array starting at the specified index offset.
+     * 
+     * @param s
+     *            the short array.
+     * @param off
+     *            the offset.
+     * @param len
+     *            the number of shorts to be read.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void readFully(short[] s, int off, int len) throws IOException;
+
+    /**
+     * Reads the specified number of chars from the stream, and stores the
+     * result into the specified array starting at the specified index offset.
+     * 
+     * @param c
+     *            the char array.
+     * @param off
+     *            the offset.
+     * @param len
+     *            the number of chars to be read.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void readFully(char[] c, int off, int len) throws IOException;
+
+    /**
+     * Reads the specified number of integer from the stream, and stores the
+     * result into the specified array starting at the specified index offset.
+     * 
+     * @param i
+     *            the integer array.
+     * @param off
+     *            the offset.
+     * @param len
+     *            the number of integer to be read.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void readFully(int[] i, int off, int len) throws IOException;
+
+    /**
+     * Reads the specified number of longs from the stream, and stores the
+     * result into the specified array starting at the specified index offset.
+     * 
+     * @param l
+     *            the long array.
+     * @param off
+     *            the offset.
+     * @param len
+     *            the number of longs to be read.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void readFully(long[] l, int off, int len) throws IOException;
+
+    /**
+     * Reads the specified number of floats from the stream, and stores the
+     * result into the specified array starting at the specified index offset.
+     * 
+     * @param f
+     *            the float array.
+     * @param off
+     *            the offset.
+     * @param len
+     *            the number of floats to be read.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void readFully(float[] f, int off, int len) throws IOException;
+
+    /**
+     * Reads the specified number of doubles from the stream, and stores the
+     * result into the specified array starting at the specified index offset.
+     * 
+     * @param d
+     *            the double array.
+     * @param off
+     *            the offset.
+     * @param len
+     *            the number of doubles to be read.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void readFully(double[] d, int off, int len) throws IOException;
+
+    /**
+     * Gets the stream position.
+     * 
+     * @return the stream position.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    long getStreamPosition() throws IOException;
+
+    /**
+     * Gets the bit offset.
+     * 
+     * @return the bit offset.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    int getBitOffset() throws IOException;
+
+    /**
+     * Sets the bit offset to an integer between 0 and 7.
+     * 
+     * @param bitOffset
+     *            the bit offset.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void setBitOffset(int bitOffset) throws IOException;
+
+    /**
+     * Reads a bit from the stream and returns the value 0 or 1.
+     * 
+     * @return the value of single bit: 0 or 1.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    int readBit() throws IOException;
+
+    /**
+     * Read the specified number of bits and returns their values as long.
+     * 
+     * @param numBits
+     *            the number of bits to be read.
+     * @return the bit string as a long.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    long readBits(int numBits) throws IOException;
+
+    /**
+     * Returns the length of the stream.
+     * 
+     * @return the length of the stream, or -1 if unknown.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    long length() throws IOException;
+
+    /**
+     * Skips the specified number of bytes by moving stream position.
+     * 
+     * @param n
+     *            the number of bytes.
+     * @return the actual skipped number of bytes.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    int skipBytes(int n) throws IOException;
+
+    /**
+     * Skips the specified number of bytes by moving stream position.
+     * 
+     * @param n
+     *            the number of bytes.
+     * @return the actual skipped number of bytes.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    long skipBytes(long n) throws IOException;
+
+    /**
+     * Sets the current stream position to the specified location.
+     * 
+     * @param pos
+     *            a file pointer position.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void seek(long pos) throws IOException;
+
+    /**
+     * Marks a position in the stream to be returned to by a subsequent call to
+     * reset.
+     */
+    void mark();
+
+    /**
+     * Returns the file pointer to its previous position.
+     * 
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void reset() throws IOException;
+
+    /**
+     * Flushes the initial position in this stream prior to the specified stream
+     * position.
+     * 
+     * @param pos
+     *            the position.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void flushBefore(long pos) throws IOException;
+
+    /**
+     * Flushes the initial position in this stream prior to the current stream
+     * position.
+     * 
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void flush() throws IOException;
+
+    /**
+     * Gets the flushed position.
+     * 
+     * @return the flushed position.
+     */
+    long getFlushedPosition();
+
+    /**
+     * Returns true if this ImageInputStream caches data in order to allow
+     * seeking backwards.
+     * 
+     * @return true, if this ImageInputStream caches data in order to allow
+     *         seeking backwards, false otherwise.
+     */
+    boolean isCached();
+
+    /**
+     * Returns true if this ImageInputStream caches data in order to allow
+     * seeking backwards, and keeps it in memory.
+     * 
+     * @return true, if this ImageInputStream caches data in order to allow
+     *         seeking backwards, and keeps it in memory.
+     */
+    boolean isCachedMemory();
+
+    /**
+     * Returns true if this ImageInputStream caches data in order to allow
+     * seeking backwards, and keeps it in a temporary file.
+     * 
+     * @return true, if this ImageInputStream caches data in order to allow
+     *         seeking backwards, and keeps it in a temporary file.
+     */
+    boolean isCachedFile();
+
+    /**
+     * Closes this stream.
+     * 
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void close() throws IOException;
+}
diff --git a/awt/javax/imageio/stream/ImageInputStreamImpl.java b/awt/javax/imageio/stream/ImageInputStreamImpl.java
new file mode 100644
index 0000000..d79da41
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageInputStreamImpl.java
@@ -0,0 +1,418 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.stream;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+/**
+ * The ImageInputStreamImpl abstract class implements the ImageInputStream
+ * interface.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ImageInputStreamImpl implements ImageInputStream {
+
+    /**
+     * The byte order.
+     */
+    protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
+
+    /**
+     * The stream position.
+     */
+    protected long streamPos = 0;
+
+    /**
+     * The flushed position.
+     */
+    protected long flushedPos = 0;
+
+    /**
+     * The bit offset.
+     */
+    protected int bitOffset = 0;
+
+    /**
+     * The closed.
+     */
+    private boolean closed = false;
+
+    /**
+     * The position stack.
+     */
+    private final PositionStack posStack = new PositionStack();
+
+    /**
+     * Instantiates a new ImageInputStreamImpl.
+     */
+    public ImageInputStreamImpl() {
+    }
+
+    /**
+     * Check if the stream is closed and if true, throws an IOException.
+     * 
+     * @throws IOException
+     *             if the stream is closed.
+     */
+    protected final void checkClosed() throws IOException {
+        if (closed) {
+            throw new IOException("stream is closed");
+        }
+    }
+
+    public void setByteOrder(ByteOrder byteOrder) {
+        this.byteOrder = byteOrder;
+    }
+
+    public ByteOrder getByteOrder() {
+        return byteOrder;
+    }
+
+    public abstract int read() throws IOException;
+
+    public int read(byte[] b) throws IOException {
+        return read(b, 0, b.length);
+    }
+
+    public abstract int read(byte[] b, int off, int len) throws IOException;
+
+    public void readBytes(IIOByteBuffer buf, int len) throws IOException {
+        if (buf == null) {
+            throw new NullPointerException("buffer is NULL");
+        }
+
+        byte[] b = new byte[len];
+        len = read(b, 0, b.length);
+
+        buf.setData(b);
+        buf.setOffset(0);
+        buf.setLength(len);
+    }
+
+    public boolean readBoolean() throws IOException {
+        int b = read();
+        if (b < 0) {
+            throw new EOFException("EOF reached");
+        }
+        return b != 0;
+    }
+
+    public byte readByte() throws IOException {
+        int b = read();
+        if (b < 0) {
+            throw new EOFException("EOF reached");
+        }
+        return (byte)b;
+    }
+
+    public int readUnsignedByte() throws IOException {
+        int b = read();
+        if (b < 0) {
+            throw new EOFException("EOF reached");
+        }
+        return b;
+    }
+
+    public short readShort() throws IOException {
+        int b1 = read();
+        int b2 = read();
+
+        if (b1 < 0 || b2 < 0) {
+            throw new EOFException("EOF reached");
+        }
+
+        return byteOrder == ByteOrder.BIG_ENDIAN ? (short)((b1 << 8) | (b2 & 0xff))
+                : (short)((b2 << 8) | (b1 & 0xff));
+    }
+
+    public int readUnsignedShort() throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public char readChar() throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public int readInt() throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public long readUnsignedInt() throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public long readLong() throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public float readFloat() throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public double readDouble() throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public String readLine() throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public String readUTF() throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void readFully(byte[] b, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void readFully(byte[] b) throws IOException {
+        readFully(b, 0, b.length);
+    }
+
+    public void readFully(short[] s, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void readFully(char[] c, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void readFully(int[] i, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void readFully(long[] l, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void readFully(float[] f, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void readFully(double[] d, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public long getStreamPosition() throws IOException {
+        checkClosed();
+        return streamPos;
+    }
+
+    public int getBitOffset() throws IOException {
+        checkClosed();
+        return bitOffset;
+    }
+
+    public void setBitOffset(int bitOffset) throws IOException {
+        checkClosed();
+        this.bitOffset = bitOffset;
+    }
+
+    public int readBit() throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public long readBits(int numBits) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public long length() {
+        return -1L;
+    }
+
+    public int skipBytes(int n) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public long skipBytes(long n) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void seek(long pos) throws IOException {
+        checkClosed();
+        if (pos < getFlushedPosition()) {
+            throw new IllegalArgumentException("trying to seek before flushed pos");
+        }
+        bitOffset = 0;
+        streamPos = pos;
+    }
+
+    public void mark() {
+        try {
+            posStack.push(getStreamPosition());
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new RuntimeException("Stream marking error");
+        }
+    }
+
+    public void reset() throws IOException {
+        // -- TODO bit pos
+        if (!posStack.isEmpty()) {
+            long p = posStack.pop();
+            if (p < flushedPos) {
+                throw new IOException("marked position lies in the flushed portion of the stream");
+            }
+            seek(p);
+        }
+    }
+
+    public void flushBefore(long pos) throws IOException {
+        if (pos > getStreamPosition()) {
+            throw new IndexOutOfBoundsException("Trying to flush outside of current position");
+        }
+        if (pos < flushedPos) {
+            throw new IndexOutOfBoundsException("Trying to flush within already flushed portion");
+        }
+        flushedPos = pos;
+        // -- TODO implement
+    }
+
+    public void flush() throws IOException {
+        flushBefore(getStreamPosition());
+    }
+
+    public long getFlushedPosition() {
+        return flushedPos;
+    }
+
+    public boolean isCached() {
+        return false; // def
+    }
+
+    public boolean isCachedMemory() {
+        return false; // def
+    }
+
+    public boolean isCachedFile() {
+        return false; // def
+    }
+
+    public void close() throws IOException {
+        checkClosed();
+        closed = true;
+
+    }
+
+    /**
+     * Finalizes this object.
+     * 
+     * @throws Throwable
+     *             if an error occurs.
+     */
+    @Override
+    protected void finalize() throws Throwable {
+        if (!closed) {
+            try {
+                close();
+            } finally {
+                super.finalize();
+            }
+        }
+    }
+
+    /**
+     * The Class PositionStack.
+     */
+    private static class PositionStack {
+
+        /**
+         * The Constant SIZE.
+         */
+        private static final int SIZE = 10;
+
+        /**
+         * The values.
+         */
+        private long[] values = new long[SIZE];
+
+        /**
+         * The pos.
+         */
+        private int pos = 0;
+
+        /**
+         * Push.
+         * 
+         * @param v
+         *            the v.
+         */
+        void push(long v) {
+            if (pos >= values.length) {
+                ensure(pos + 1);
+            }
+            values[pos++] = v;
+        }
+
+        /**
+         * Pop.
+         * 
+         * @return the long.
+         */
+        long pop() {
+            return values[--pos];
+        }
+
+        /**
+         * Checks if is empty.
+         * 
+         * @return true, if is empty.
+         */
+        boolean isEmpty() {
+            return pos == 0;
+        }
+
+        /**
+         * Ensure.
+         * 
+         * @param size
+         *            the size.
+         */
+        private void ensure(int size) {
+            long[] arr = new long[Math.max(2 * values.length, size)];
+            System.arraycopy(values, 0, arr, 0, values.length);
+            values = arr;
+        }
+    }
+}
diff --git a/awt/javax/imageio/stream/ImageOutputStream.java b/awt/javax/imageio/stream/ImageOutputStream.java
new file mode 100644
index 0000000..28ec932
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageOutputStream.java
@@ -0,0 +1,307 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+
+package javax.imageio.stream;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * The ImageOutputStream represents output stream interface that is used by
+ * ImageWriters.
+ * 
+ * @since Android 1.0
+ */
+public interface ImageOutputStream extends DataOutput, ImageInputStream {
+
+    /**
+     * Writes a single byte to the stream at the current position.
+     * 
+     * @param b
+     *            the integer value, of which the 8 lowest bits will be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void write(int b) throws IOException;
+
+    /**
+     * Writes the bytes array to the stream.
+     * 
+     * @param b
+     *            the byte array to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void write(byte[] b) throws IOException;
+
+    /**
+     * Writes a number of bytes from the specified byte array beginning from the
+     * specified offset.
+     * 
+     * @param b
+     *            the byte array.
+     * @param off
+     *            the offset.
+     * @param len
+     *            the number of bytes to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void write(byte[] b, int off, int len) throws IOException;
+
+    /**
+     * Writes the specified boolean value to the stream, 1 if it is true, 0 if
+     * it is false.
+     * 
+     * @param b
+     *            the boolean value to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeBoolean(boolean b) throws IOException;
+
+    /**
+     * Writes the 8 lowest bits of the specified integer value to the stream.
+     * 
+     * @param b
+     *            the specified integer value.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeByte(int b) throws IOException;
+
+    /**
+     * Writes a short value to the output stream.
+     * 
+     * @param v
+     *            the short value to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeShort(int v) throws IOException;
+
+    /**
+     * Writes the 16 lowest bits of the specified integer value to the stream.
+     * 
+     * @param v
+     *            the specified integer value.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeChar(int v) throws IOException;
+
+    /**
+     * Writes an integer value to the output stream.
+     * 
+     * @param v
+     *            the integer value to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeInt(int v) throws IOException;
+
+    /**
+     * Write long.
+     * 
+     * @param v
+     *            the long value.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeLong(long v) throws IOException;
+
+    /**
+     * Writes a float value to the output stream.
+     * 
+     * @param v
+     *            the float which contains value to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeFloat(float v) throws IOException;
+
+    /**
+     * Writes a double value to the output stream.
+     * 
+     * @param v
+     *            the double which contains value to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeDouble(double v) throws IOException;
+
+    /**
+     * Writes the specified string to the stream.
+     * 
+     * @param s
+     *            the string to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeBytes(String s) throws IOException;
+
+    /**
+     * Writes the specified String to the output stream.
+     * 
+     * @param s
+     *            the String to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeChars(String s) throws IOException;
+
+    /**
+     * Writes 2 bytes to the output stream in the modified UTF-8 representation
+     * of every character of the specified string.
+     * 
+     * @param s
+     *            the specified string to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeUTF(String s) throws IOException;
+
+    /**
+     * Flushes the initial position in this stream prior to the specified stream
+     * position.
+     * 
+     * @param pos
+     *            the position.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void flushBefore(long pos) throws IOException;
+
+    /**
+     * Writes a len number of short values from the specified array to the
+     * stream.
+     * 
+     * @param s
+     *            the shorts array to be written.
+     * @param off
+     *            the offset in the char array.
+     * @param len
+     *            the length of chars to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeShorts(short[] s, int off, int len) throws IOException;
+
+    /**
+     * Writes a len number of chars to the stream.
+     * 
+     * @param c
+     *            the char array to be written.
+     * @param off
+     *            the offset in the char array.
+     * @param len
+     *            the length of chars to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeChars(char[] c, int off, int len) throws IOException;
+
+    /**
+     * Writes a len number of integer values from the specified array to the
+     * stream.
+     * 
+     * @param i
+     *            the integer array to be written.
+     * @param off
+     *            the offset in the char array.
+     * @param len
+     *            the length of chars to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeInts(int[] i, int off, int len) throws IOException;
+
+    /**
+     * Writes a len number of long values from the specified array to the
+     * stream.
+     * 
+     * @param l
+     *            the long array to be written.
+     * @param off
+     *            the offset in the char array.
+     * @param len
+     *            the length of chars to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeLongs(long[] l, int off, int len) throws IOException;
+
+    /**
+     * Writes a len number of float values from the specified array to the
+     * stream.
+     * 
+     * @param f
+     *            the float array to be written.
+     * @param off
+     *            the offset in the char array.
+     * @param len
+     *            the length of chars to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeFloats(float[] f, int off, int len) throws IOException;
+
+    /**
+     * Writes a len number of double values from the specified array to the
+     * stream.
+     * 
+     * @param d
+     *            the double array to be written.
+     * @param off
+     *            the offset in the char array.
+     * @param len
+     *            the length of chars to be written.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeDoubles(double[] d, int off, int len) throws IOException;
+
+    /**
+     * Writes a single bit at the current position.
+     * 
+     * @param bit
+     *            the integer whose least significant bit is to be written to
+     *            the stream.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeBit(int bit) throws IOException;
+
+    /**
+     * Writes a sequence of bits beginning from the current position.
+     * 
+     * @param bits
+     *            the long value containing the bits to be written, starting
+     *            with the bit in position numBits - 1 down to the least
+     *            significant bit.
+     * @param numBits
+     *            the number of significant bit, it can be between 0 and 64.
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    void writeBits(long bits, int numBits) throws IOException;
+
+}
diff --git a/awt/javax/imageio/stream/ImageOutputStreamImpl.java b/awt/javax/imageio/stream/ImageOutputStreamImpl.java
new file mode 100644
index 0000000..0fef78f
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageOutputStreamImpl.java
@@ -0,0 +1,174 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+package javax.imageio.stream;
+
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+/* 
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+/**
+ * The ImageOutputStreamImpl abstract class implements the ImageOutputStream
+ * interface.
+ * 
+ * @since Android 1.0
+ */
+public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl implements
+        ImageOutputStream {
+
+    /**
+     * Instantiates a new ImageOutputStreamImpl.
+     */
+    public ImageOutputStreamImpl() {
+    }
+
+    public abstract void write(int b) throws IOException;
+
+    public void write(byte[] b) throws IOException {
+        write(b, 0, b.length);
+    }
+
+    public abstract void write(byte[] b, int off, int len) throws IOException;
+
+    public void writeBoolean(boolean v) throws IOException {
+        write(v ? 1 : 0);
+    }
+
+    public void writeByte(int v) throws IOException {
+        write(v);
+    }
+
+    public void writeShort(int v) throws IOException {
+        if (byteOrder == ByteOrder.BIG_ENDIAN) {
+
+        } else {
+
+        }
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void writeChar(int v) throws IOException {
+        writeShort(v);
+    }
+
+    public void writeInt(int v) throws IOException {
+        if (byteOrder == ByteOrder.BIG_ENDIAN) {
+
+        } else {
+
+        }
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void writeLong(long v) throws IOException {
+        if (byteOrder == ByteOrder.BIG_ENDIAN) {
+
+        } else {
+
+        }
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void writeFloat(float v) throws IOException {
+        writeInt(Float.floatToIntBits(v));
+    }
+
+    public void writeDouble(double v) throws IOException {
+        writeLong(Double.doubleToLongBits(v));
+    }
+
+    public void writeBytes(String s) throws IOException {
+        write(s.getBytes());
+    }
+
+    public void writeChars(String s) throws IOException {
+        char[] chs = s.toCharArray();
+        writeChars(chs, 0, chs.length);
+    }
+
+    public void writeUTF(String s) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void writeShorts(short[] s, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void writeChars(char[] c, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void writeInts(int[] i, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void writeLongs(long[] l, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void writeFloats(float[] f, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void writeDoubles(double[] d, int off, int len) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void writeBit(int bit) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    public void writeBits(long bits, int numBits) throws IOException {
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Flushes the bits. This method should be called in the write methods by
+     * subclasses.
+     * 
+     * @throws IOException
+     *             if an I/O exception has occurred.
+     */
+    protected final void flushBits() throws IOException {
+        if (bitOffset == 0) {
+            return;
+        }
+
+        // -- TODO implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+}
diff --git a/awt/javax/imageio/stream/MemoryCacheImageInputStream.java b/awt/javax/imageio/stream/MemoryCacheImageInputStream.java
new file mode 100644
index 0000000..d7fc791
--- /dev/null
+++ b/awt/javax/imageio/stream/MemoryCacheImageInputStream.java
@@ -0,0 +1,119 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.stream;
+
+import org.apache.harmony.x.imageio.stream.RandomAccessMemoryCache;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * The MemoryCacheImageInputStream class implements ImageInputStream using a
+ * memory buffer for caching the data.
+ * 
+ * @since Android 1.0
+ */
+public class MemoryCacheImageInputStream extends ImageInputStreamImpl {
+
+    /**
+     * The is.
+     */
+    private InputStream is;
+
+    /**
+     * The ramc.
+     */
+    private RandomAccessMemoryCache ramc = new RandomAccessMemoryCache();
+
+    /**
+     * Instantiates a new MemoryCacheImageInputStream which reads from the
+     * specified InputStream.
+     * 
+     * @param stream
+     *            the InputStream to be read.
+     */
+    public MemoryCacheImageInputStream(InputStream stream) {
+        if (stream == null) {
+            throw new IllegalArgumentException("stream == null!");
+        }
+        is = stream;
+    }
+
+    @Override
+    public int read() throws IOException {
+        bitOffset = 0;
+
+        if (streamPos >= ramc.length()) {
+            int count = (int)(streamPos - ramc.length() + 1);
+            int bytesAppended = ramc.appendData(is, count);
+
+            if (bytesAppended < count) {
+                return -1;
+            }
+        }
+
+        int res = ramc.getData(streamPos);
+        if (res >= 0) {
+            streamPos++;
+        }
+        return res;
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        bitOffset = 0;
+
+        if (streamPos >= ramc.length()) {
+            int count = (int)(streamPos - ramc.length() + len);
+            ramc.appendData(is, count);
+        }
+
+        int res = ramc.getData(b, off, len, streamPos);
+        if (res > 0) {
+            streamPos += res;
+        }
+        return res;
+    }
+
+    @Override
+    public boolean isCached() {
+        return true;
+    }
+
+    @Override
+    public boolean isCachedFile() {
+        return false;
+    }
+
+    @Override
+    public boolean isCachedMemory() {
+        return true;
+    }
+
+    @Override
+    public void close() throws IOException {
+        super.close();
+        ramc.close();
+    }
+
+    @Override
+    public void flushBefore(long pos) throws IOException {
+        super.flushBefore(pos);
+        ramc.freeBefore(getFlushedPosition());
+    }
+}
diff --git a/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java b/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java
new file mode 100644
index 0000000..1df40a3
--- /dev/null
+++ b/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java
@@ -0,0 +1,135 @@
+/*
+ *  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.
+ */
+
+package javax.imageio.stream;
+
+import org.apache.harmony.x.imageio.stream.RandomAccessMemoryCache;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * The MemoryCacheImageOutputStream class implements ImageOutputStream using a
+ * memory buffer for caching the data.
+ * 
+ * @since Android 1.0
+ */
+public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl {
+
+    /**
+     * The os.
+     */
+    OutputStream os;
+
+    /**
+     * The ramc.
+     */
+    RandomAccessMemoryCache ramc = new RandomAccessMemoryCache();
+
+    /**
+     * Instantiates a new MemoryCacheImageOutputStream which writes to the
+     * specified OutputStream.
+     * 
+     * @param stream
+     *            the OutputStream.
+     */
+    public MemoryCacheImageOutputStream(OutputStream stream) {
+        if (stream == null) {
+            throw new IllegalArgumentException("stream == null!");
+        }
+        os = stream;
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        flushBits(); // See the flushBits method description
+
+        ramc.putData(b, streamPos);
+        streamPos++;
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException {
+        flushBits(); // See the flushBits method description
+
+        ramc.putData(b, off, len, streamPos);
+        streamPos += len;
+    }
+
+    @Override
+    public int read() throws IOException {
+        bitOffset = 0;
+
+        int res = ramc.getData(streamPos);
+        if (res >= 0) {
+            streamPos++;
+        }
+        return res;
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        bitOffset = 0;
+
+        int res = ramc.getData(b, off, len, streamPos);
+        if (res > 0) {
+            streamPos += res;
+        }
+        return res;
+    }
+
+    @Override
+    public long length() {
+        return ramc.length();
+    }
+
+    @Override
+    public boolean isCached() {
+        return true;
+    }
+
+    @Override
+    public boolean isCachedMemory() {
+        return true;
+    }
+
+    @Override
+    public boolean isCachedFile() {
+        return false;
+    }
+
+    @Override
+    public void close() throws IOException {
+        flushBefore(length());
+        super.close();
+        ramc.close();
+    }
+
+    @Override
+    public void flushBefore(long pos) throws IOException {
+        long flushedPosition = getFlushedPosition();
+        super.flushBefore(pos);
+
+        long newFlushedPosition = getFlushedPosition();
+        int nBytes = (int)(newFlushedPosition - flushedPosition);
+
+        ramc.getData(os, nBytes, flushedPosition);
+        ramc.freeBefore(newFlushedPosition);
+
+        os.flush();
+    }
+}
diff --git a/awt/javax/imageio/stream/package.html b/awt/javax/imageio/stream/package.html
new file mode 100644
index 0000000..6cf53c3
--- /dev/null
+++ b/awt/javax/imageio/stream/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      This package contains classes and interfaces for handling images with low-level I/O operations. 
+    </p>
+  @since Android 1.0
+  </body>
+</html>
diff --git a/awt/org/apache/harmony/awt/ChoiceStyle.java b/awt/org/apache/harmony/awt/ChoiceStyle.java
new file mode 100644
index 0000000..93b7aad
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ChoiceStyle.java
@@ -0,0 +1,33 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+/**
+ * ChoiceStyle.
+ * Is used to define custom choice properties:
+ * width and x screen coordinate of the list popup window. 
+ */
+public interface ChoiceStyle {
+
+    int getPopupX(int x, int width, int choiceWidth, int screenWidth);
+    int getPopupWidth(int choiceWidth);
+
+}
diff --git a/awt/org/apache/harmony/awt/ClipRegion.java b/awt/org/apache/harmony/awt/ClipRegion.java
new file mode 100644
index 0000000..c89a81d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ClipRegion.java
@@ -0,0 +1,84 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov, Anton Avtamonov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+import java.awt.Component;
+import java.awt.Rectangle;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class ClipRegion extends Rectangle {
+    private final MultiRectArea clip;
+
+    public ClipRegion(final MultiRectArea clip) {
+        this.clip = new MultiRectArea(clip);
+        setBounds(clip.getBounds());
+    }
+
+    public MultiRectArea getClip() {
+        return clip;
+    }
+
+    @Override
+    public String toString() {
+        String str = clip.toString();
+        int i = str.indexOf('[');
+        str = str.substring(i);
+        if (clip.getRectCount() == 1) {
+            str = str.substring(1, str.length() - 1);
+        }
+        return getClass().getName() + str;
+    }
+
+
+    public void convertRegion(final Component child, final Component parent) {
+        convertRegion(child, clip, parent);
+    }
+
+    public void intersect(final Rectangle rect) {
+        clip.intersect(rect);
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return clip.isEmpty();
+    }
+
+    public static void convertRegion(final Component child,
+                                     final MultiRectArea region,
+                                     final Component parent) {
+        int x = 0, y = 0;
+        Component c = child;
+        //???AWT
+        /*
+        for (; c != null && c != parent; c = c.getParent()) {
+            x += c.getX();
+            y += c.getY();
+        }
+        */
+        if (c == null) {
+            // awt.51=Component expected to be a parent
+            throw new IllegalArgumentException(Messages.getString("awt.51")); //$NON-NLS-1$
+        }
+        region.translate(x, y);
+    }
+}
diff --git a/awt/org/apache/harmony/awt/ComponentInternals.java b/awt/org/apache/harmony/awt/ComponentInternals.java
new file mode 100644
index 0000000..c359784
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ComponentInternals.java
@@ -0,0 +1,212 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+//???AWT
+//import java.awt.Component;
+//import java.awt.Container;
+//import java.awt.Dialog;
+import java.awt.Dimension;
+//import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+//import java.awt.Window;
+//import java.awt.Choice;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+//import org.apache.harmony.awt.text.TextFieldKit;
+//import org.apache.harmony.awt.text.TextKit;
+//import org.apache.harmony.awt.wtk.NativeWindow;
+
+import org.apache.harmony.luni.util.NotImplementedException;
+
+/**
+ *  The accessor to AWT private API
+ */
+public abstract class ComponentInternals {
+
+    /**
+     * @return the ComponentInternals instance to serve the requests
+     */
+    public static ComponentInternals getComponentInternals() {
+        return ContextStorage.getComponentInternals();
+    }
+
+    /**
+     * This method must be called by AWT to establish the connection
+     * @param internals - implementation of ComponentInternals created by AWT
+     */
+    public static void setComponentInternals(ComponentInternals internals) {
+        ContextStorage.setComponentInternals(internals);
+    }
+
+    /**
+     * The accessor to native resource connected to a component.
+     * It returns non-<code>null</code> value only if component
+     * already has the native resource
+     */
+    //public abstract NativeWindow getNativeWindow(Component component);
+
+    /**
+     * Connect Window object to existing native resource
+     * @param nativeWindowId - id of native window to attach
+     * @return Window object with special behaviour that
+     * restricts manupulation with that window
+     */
+    //public abstract Window attachNativeWindow(long nativeWindowId);
+
+    /**
+     * Start mouse grab in "client" mode.
+     * All mouse events in AWT components will be reported as usual,
+     * mouse events that occured outside of AWT components will be sent to
+     * the window passed as grabWindow parameter. When mouse grab is canceled
+     * (because of click in non-AWT window or by task switching)
+     * the whenCanceled callback is called
+     *
+     * @param grabWindow - window that will own the grab
+     * @param whenCanceled - callback called when grab is canceled by user's action
+     */
+    //public abstract void startMouseGrab(Window grabWindow, Runnable whenCanceled);
+
+    /**
+     * End mouse grab and resume normal processing of mouse events
+     */
+    //public abstract void endMouseGrab();
+
+    /**
+     * Set the <code>popup</code> flag of the window to true.
+     * This window won't be controlled by window manager on Linux.
+     * Call this method before the window is shown first time
+     * @param window - the window that should become popup one
+     */
+    //public abstract void makePopup(Window window);
+
+    /**
+     * This method must be called by Graphics at the beginning of drawImage()
+     * to store image drawing parameters (defined by application developer) in component
+     *
+     * @param comp - component that draws the image
+     * @param image - image to be drawn
+     * @param destLocation - location of the image upon the component's surface. Never null.
+     * @param destSize - size of the component's area to be filled with the image.
+     *                  Equals to null if size parameters omitted in drawImage.
+     * @param source - area of the image to be drawn on the component.
+     *                  Equals to null if src parameters omitted in drawImage.
+     */
+    /*
+    public abstract void onDrawImage(Component comp, Image image, Point destLocation,
+            Dimension destSize, Rectangle source);
+*/
+    /**
+     * Sets system's caret position.
+     * This method should be called by text component to synchronize our caret position
+     * with system's caret position.
+     * @param x
+     * @param y
+     */
+    //public abstract void setCaretPos(Component c, int x, int y);
+
+    /**
+     * NEVER USE IT. FORGET IT. IT DOES NOT EXIST.
+     * See Toolkit.unsafeInvokeAndWait(Runnable).
+     *
+     * Accessor for Toolkit.unsafeInvokeAndWait(Runnable) method.
+     * For use in exceptional cases only.
+     * Read comments for Toolkit.unsafeInvokeAndWait(Runnable) before use.
+     */
+    /*
+    public abstract void unsafeInvokeAndWait(Runnable runnable)
+            throws InterruptedException, InvocationTargetException;
+
+    public abstract TextKit getTextKit(Component comp);
+
+    public abstract void setTextKit(Component comp, TextKit kit);
+
+    public abstract TextFieldKit getTextFieldKit(Component comp);
+
+    public abstract void setTextFieldKit(Component comp, TextFieldKit kit);
+*/
+    /**
+     * Terminate event dispatch thread, completely destroy AWT context.<br>
+     * Intended for multi-context mode, in single-context mode does nothing.
+     *
+     */
+    public abstract void shutdown();
+
+    /**
+     * Sets mouse events preprocessor for event queue
+     */
+    //public abstract void setMouseEventPreprocessor(MouseEventPreprocessor preprocessor);
+
+    /**
+     * Create customized Choice using style
+     */
+    //public abstract Choice createCustomChoice(ChoiceStyle style);
+
+    //public abstract Insets getNativeInsets(Window w);
+
+    /**
+     * Region to be repainted (could be null). Use this in overridden repaint()
+     */
+    //public abstract MultiRectArea getRepaintRegion(Component c);
+
+    //public abstract MultiRectArea subtractPendingRepaintRegion(Component c, MultiRectArea mra);
+
+    /**
+     * Returns true if the window was at least once painted due to native paint events
+     */
+    //public abstract boolean wasPainted(Window w);
+
+    /**
+     * The component's region hidden behind top-level windows
+     * (belonging to both this Java app and all other apps), and behind
+     * heavyweight components overlapping with passed component
+     */
+    //public abstract MultiRectArea getObscuredRegion(Component c);
+    
+    /**
+     * An accessor to Container.addObscuredRegions() method
+     * @see java.awt.Container#addObscuredRegions(MultiRectArea, Component)
+     */
+    //public abstract void addObscuredRegions(MultiRectArea mra, Component c, Container container);
+    
+    /**
+     * Makes it possible to call protected Toolkit.setDesktopProperty()
+     * method from any class outside of java.awt package
+     */
+    public abstract void setDesktopProperty(String name, Object value);
+    
+    /**
+     * Makes it possible to start/stop dialog modal loop
+     * from anywhere outside of java.awt package
+     */
+    //public abstract void runModalLoop(Dialog dlg);
+    //public abstract void endModalLoop(Dialog dlg);
+    
+    /**
+     * Sets component's visible flag only
+     * (the component is not actually shown/hidden)
+     */
+    //public abstract void setVisibleFlag(Component comp, boolean visible);
+    
+}
diff --git a/awt/org/apache/harmony/awt/ContextStorage.java b/awt/org/apache/harmony/awt/ContextStorage.java
new file mode 100644
index 0000000..d44648a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ContextStorage.java
@@ -0,0 +1,154 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+import java.awt.*;
+
+//???AWT
+//import org.apache.harmony.awt.datatransfer.*;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.wtk.*;
+
+
+public final class ContextStorage {
+
+    private static volatile boolean multiContextMode = false;
+    private volatile boolean shutdownPending = false;
+
+    private static final ContextStorage globalContext = new ContextStorage();
+
+    private Toolkit toolkit;
+    private ComponentInternals componentInternals;
+    //???AWT: private DTK dtk;
+    private WTK wtk;
+    private GraphicsEnvironment graphicsEnvironment;
+
+    private class ContextLock {}
+    private final Object contextLock = new ContextLock();
+    private final Synchronizer synchronizer = new Synchronizer();
+
+    public static void activateMultiContextMode() {
+        // TODO: checkPermission
+        multiContextMode = true;
+    }
+
+    public static void setDefaultToolkit(Toolkit newToolkit) {
+        // TODO: checkPermission
+        getCurrentContext().toolkit = newToolkit;
+    }
+
+    public static Toolkit getDefaultToolkit() {
+        return getCurrentContext().toolkit;
+    }
+
+    //???AWT
+    /*
+    public static void setDTK(DTK dtk) {
+        // TODO: checkPermission
+        getCurrentContext().dtk = dtk;
+    }
+
+    public static DTK getDTK() {
+        return getCurrentContext().dtk;
+    }
+    */
+
+    public static Synchronizer getSynchronizer() {
+        return getCurrentContext().synchronizer;
+    }
+
+    public static ComponentInternals getComponentInternals() {
+        return getCurrentContext().componentInternals;
+    }
+
+    static void setComponentInternals(ComponentInternals internals) {
+        // TODO: checkPermission
+        getCurrentContext().componentInternals = internals;
+    }
+
+    public static Object getContextLock() {
+        return getCurrentContext().contextLock;
+    }
+
+    public static WindowFactory getWindowFactory() {
+        return getCurrentContext().wtk.getWindowFactory();
+    }
+
+    public static void setWTK(WTK wtk) {
+        getCurrentContext().wtk = wtk;
+    }
+
+    public static NativeIM getNativeIM() {
+        return getCurrentContext().wtk.getNativeIM();
+    }
+
+    public static NativeEventQueue getNativeEventQueue() {
+        return getCurrentContext().wtk.getNativeEventQueue();
+    }
+
+    public static GraphicsEnvironment getGraphicsEnvironment() {
+        return getCurrentContext().graphicsEnvironment;
+    }
+
+    public static void setGraphicsEnvironment(GraphicsEnvironment environment) {
+        getCurrentContext().graphicsEnvironment = environment;
+    }
+
+    private static ContextStorage getCurrentContext() {
+        return multiContextMode ? getContextThreadGroup().context : globalContext;
+    }
+
+    private static ContextThreadGroup getContextThreadGroup() {
+
+        Thread thread = Thread.currentThread();
+        ThreadGroup group = thread.getThreadGroup();
+        while (group != null) {
+            if (group instanceof ContextThreadGroup) {
+                return (ContextThreadGroup)group;
+            }
+            group = group.getParent();
+        }
+        // awt.59=Application has run out of context thread group
+        throw new RuntimeException(Messages.getString("awt.59")); //$NON-NLS-1$
+    }
+    
+    public static boolean shutdownPending() {
+        return getCurrentContext().shutdownPending;
+    }
+
+    void shutdown() {
+        if (!multiContextMode) {
+            return;
+        }
+        shutdownPending = true;
+
+        //???AWT: componentInternals.shutdown();
+
+        synchronized(contextLock) {
+            toolkit = null;
+            componentInternals = null;
+            //???AWT: dtk = null;
+            wtk = null;
+            graphicsEnvironment = null;
+        }
+    }
+    
+}
diff --git a/awt/org/apache/harmony/awt/ContextThreadGroup.java b/awt/org/apache/harmony/awt/ContextThreadGroup.java
new file mode 100644
index 0000000..4f0af52
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ContextThreadGroup.java
@@ -0,0 +1,34 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+public class ContextThreadGroup extends ThreadGroup {
+
+    final ContextStorage context = new ContextStorage();
+
+    public ContextThreadGroup(String name) {
+        super(name);
+    }
+
+    public void dispose() {
+        context.shutdown();
+    }
+}
diff --git a/awt/org/apache/harmony/awt/ListenerList.java b/awt/org/apache/harmony/awt/ListenerList.java
new file mode 100644
index 0000000..f5c55f1
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ListenerList.java
@@ -0,0 +1,194 @@
+/*
+ *  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.
+ */
+
+package org.apache.harmony.awt;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * List of AWT listeners. It is for 3 purposes.
+ * 1. To support list modification from listeners
+ * 2. To ensure call for all listeners as atomic operation
+ * 3. To support system listeners that are needed for built-in AWT components
+ */
+public class ListenerList<T extends EventListener> implements Serializable {
+    private static final long serialVersionUID = 9180703263299648154L;
+
+    private transient ArrayList<T> systemList;
+    private transient ArrayList<T> userList;
+    
+    public ListenerList() {
+        super();
+    }
+
+    /**
+     * Adds system listener to this list.
+     *
+     * @param listener - listener to be added.
+     */
+    public void addSystemListener(T listener) {
+        if (systemList == null) {
+            systemList = new ArrayList<T>();
+        }
+        systemList.add(listener);
+    }
+
+    /**
+     * Adds user (public) listener to this list.
+     *
+     * @param listener - listener to be added.
+     */
+    public void addUserListener(T listener) {
+        if (listener == null) {
+            return;
+        }
+        // transactionally replace old list
+        synchronized (this) {
+            if (userList == null) {
+                userList = new ArrayList<T>();
+                userList.add(listener);
+                return;
+            }
+            ArrayList<T> newList = new ArrayList<T>(userList);
+            newList.add(listener);
+            userList = newList;
+        }
+    }
+
+    /**
+     * Removes user (public) listener to this list.
+     *
+     * @param listener - listener to be removed.
+     */
+    public void removeUserListener(Object listener) {
+        if (listener == null) {
+            return;
+        }
+        // transactionally replace old list
+        synchronized (this) {
+            if (userList == null || !userList.contains(listener)) {
+                return;
+            }
+            ArrayList<T> newList = new ArrayList<T>(userList);
+            newList.remove(listener);
+            userList = (newList.size() > 0 ? newList : null);
+        }
+    }
+
+    /**
+     * Gets all user (public) listeners in one array.
+     *
+     * @param emptyArray - empty array, it's for deriving particular listeners class.
+     * @return array of all user listeners.
+     */
+    public <AT> AT[] getUserListeners(AT[] emptyArray){
+        synchronized (this) {
+            return (userList != null ? userList.toArray(emptyArray) : emptyArray);
+
+        }
+    }
+
+    /**
+     * Gets all user (public) listeners in one list.
+     *
+     * @return list of all user listeners.
+     */
+    public List<T> getUserListeners() {
+        synchronized (this) {
+            if (userList == null || userList.isEmpty()) {
+                return Collections.emptyList();
+            }
+            return new ArrayList<T>(userList);
+        }
+    }
+    
+    public List<T> getSystemListeners() {
+        synchronized (this) {
+            if (systemList == null || systemList.isEmpty()) {
+                return Collections.emptyList();
+            }
+            return new ArrayList<T>(systemList);
+        }
+    }
+
+    /**
+     * Gets iterator for user listeners.
+     *
+     * @return iterator for user listeners.
+     */
+    public Iterator<T> getUserIterator() {
+        synchronized (this) {
+            if (userList == null) {
+                List<T> emptyList = Collections.emptyList();
+                return emptyList.iterator();
+            }
+            return new ReadOnlyIterator<T>(userList.iterator());
+        }
+    }
+
+    /**
+     * Gets iterator for system listeners.
+     *
+     * @return iterator for system listeners.
+     */
+    public Iterator<T> getSystemIterator() {
+        return systemList.iterator();
+    }
+
+    private static ArrayList<?> getOnlySerializable(ArrayList<?> list) {
+        if (list == null) {
+            return null;
+        }
+
+        ArrayList<Object> result = new ArrayList<Object>();
+        for (Iterator<?> it = list.iterator(); it.hasNext();) {
+            Object obj = it.next();
+            if (obj instanceof Serializable) {
+                result.add(obj);
+            }
+        }
+
+        return (result.size() != 0) ? result : null;
+    }
+
+    private void writeObject(ObjectOutputStream stream) throws IOException {
+
+        stream.defaultWriteObject();
+
+        stream.writeObject(getOnlySerializable(systemList));
+        stream.writeObject(getOnlySerializable(userList));
+    }
+
+    @SuppressWarnings("unchecked")
+    private void readObject(ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+
+        stream.defaultReadObject();
+
+        systemList = (ArrayList<T>)stream.readObject();
+        userList = (ArrayList<T>)stream.readObject();
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/ReadOnlyIterator.java b/awt/org/apache/harmony/awt/ReadOnlyIterator.java
new file mode 100644
index 0000000..671653f
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ReadOnlyIterator.java
@@ -0,0 +1,53 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+import java.util.Iterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * ReadOnlyIterator
+ */
+public final class ReadOnlyIterator<E> implements Iterator<E> {
+
+    private final Iterator<E> it;
+
+    public ReadOnlyIterator(Iterator<E> it) {
+        if (it == null) {
+            throw new NullPointerException();
+        }
+        this.it = it;
+    }
+
+    public void remove() {
+        // awt.50=Iterator is read-only
+        throw new UnsupportedOperationException(Messages.getString("awt.50")); //$NON-NLS-1$
+    }
+
+    public boolean hasNext() {
+        return it.hasNext();
+    }
+
+    public E next() {
+        return it.next();
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java b/awt/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java
new file mode 100644
index 0000000..bd5f6c6
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java
@@ -0,0 +1,65 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 23.11.2005
+ *
+ */
+
+
+package org.apache.harmony.awt.gl;
+
+import java.awt.Image;
+import java.awt.image.DataBuffer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.DataBufferInt;
+
+import org.apache.harmony.awt.gl.image.DataBufferListener;
+
+/**
+ * This class give an opportunity to get access to private data of 
+ * some java.awt.image classes 
+ * Implementation of this class placed in java.awt.image package
+ */
+
+public abstract class AwtImageBackdoorAccessor {
+
+    static protected AwtImageBackdoorAccessor inst;
+
+    public static AwtImageBackdoorAccessor getInstance(){
+        // First we need to run the static initializer in the DataBuffer class to resolve inst.
+        new DataBufferInt(0);
+        return inst;
+    }
+
+    public abstract Surface getImageSurface(Image image);
+    public abstract boolean isGrayPallete(IndexColorModel icm);
+
+    public abstract Object getData(DataBuffer db);
+    public abstract int[] getDataInt(DataBuffer db);
+    public abstract byte[] getDataByte(DataBuffer db);
+    public abstract short[] getDataShort(DataBuffer db);
+    public abstract short[] getDataUShort(DataBuffer db);
+    public abstract double[] getDataDouble(DataBuffer db);
+    public abstract float[] getDataFloat(DataBuffer db);
+    public abstract void releaseData(DataBuffer db);
+    
+    public abstract void addDataBufferListener(DataBuffer db, DataBufferListener listener);
+    public abstract void removeDataBufferListener(DataBuffer db);
+    public abstract void validate(DataBuffer db);
+}
diff --git a/awt/org/apache/harmony/awt/gl/CommonGraphics2D.java b/awt/org/apache/harmony/awt/gl/CommonGraphics2D.java
new file mode 100644
index 0000000..a33c38b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/CommonGraphics2D.java
@@ -0,0 +1,1132 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.PaintContext;
+import java.awt.Point;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.Toolkit;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.ImageObserver;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.WritableRaster;
+import java.awt.image.renderable.RenderableImage;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.RoundRectangle2D;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.image.OffscreenImage;
+import org.apache.harmony.awt.gl.render.Blitter;
+import org.apache.harmony.awt.gl.render.JavaArcRasterizer;
+import org.apache.harmony.awt.gl.render.JavaLineRasterizer;
+import org.apache.harmony.awt.gl.render.JavaShapeRasterizer;
+import org.apache.harmony.awt.gl.render.JavaTextRenderer;
+import org.apache.harmony.awt.gl.render.NullBlitter;
+
+/*
+ * List of abstract methods to implement in subclusses
+ * Graphics.copyArea(int x, int y, int width, int height, int dx, int dy)
+ * Graphics.create()
+ * Graphics2D.getDeviceConfiguration()
+ * CommonGraphics2D.fillMultiRectAreaColor(MultiRectArea mra);
+ * CommonGraphics2D.fillMultiRectAreaPaint(MultiRectArea mra);
+ */
+
+/**
+ * CommonGraphics2D class is a super class for all system-dependent
+ * implementations. It implements major part of Graphics and Graphics2D
+ * abstract methods.
+ * <h2>CommonGraphics2D Class Internals</h2>
+ * <h3>Line and Shape Rasterizers</h3>
+ * <p>
+ * The CommonGraphics2D class splits all shapes into a set of rectangles 
+ * to unify the drawing process for different operating systems and architectures. 
+ * For this purpose Java 2D* uses the JavaShapeRasterizer and the JavaLineRasterizer 
+ * classes from the org.apache.harmony.awt.gl.render package. The JavaShapeRasterizer 
+ * class splits an object implementing a Shape interface into a set of rectangles and 
+ * produces a MultiRectArea object. The JavaLineRasterizer class makes line drawing 
+ * more accurate and processes lines with strokes, which are instances of the BasicStroke 
+ * class.
+ * </p>
+ * <p>
+ * To port the shape drawing to another platform you just need to override 
+ * rectangle-drawing methods. However, if your operating system has functions to draw 
+ * particular shapes, you can optimize your subclass of the CommonGraphics2D class by 
+ * using this functionality in overridden methods.
+ * </p>
+
+ * <h3>Blitters</h3>
+ * <p>
+ * Blitter classes draw images on the display or buffered images. All blitters inherit 
+ * the org.apache.harmony.awt.gl.render.Blitter interface.
+ * </p>
+ * <p>Blitters are divided into:
+ * <ul>
+ * <li>Native blitters for simple types of images, which the underlying native library 
+ * can draw.</li> 
+ * <li>Java* blitters for those types of images, which the underlying native library 
+ * cannot handle.</li>
+ * </ul></p>
+ * <p>
+ * DRL Java 2D* also uses blitters to fill the shapes and the user-defined subclasses 
+ * of the java.awt.Paint class with paints, which the system does not support.
+ * </p>
+ *
+ *<h3>Text Renderers</h3>
+ *<p>
+ *Text renderers draw strings and glyph vectors. All text renderers are subclasses 
+ *of the org.apache.harmony.awt.gl.TextRenderer class.
+ *</p>
+ *
+ */
+public abstract class CommonGraphics2D extends Graphics2D {
+    protected Surface dstSurf = null;
+    protected Blitter blitter = NullBlitter.getInstance();
+    protected RenderingHints hints = new RenderingHints(null);
+
+    // Clipping things
+    protected MultiRectArea clip = null;
+
+    protected Paint paint = Color.WHITE;
+    protected Color fgColor = Color.WHITE;
+    protected Color bgColor = Color.BLACK;
+
+    protected Composite composite = AlphaComposite.SrcOver;
+
+    protected Stroke stroke = new BasicStroke();
+
+    //TODO: Think more about FontRenderContext
+    protected FontRenderContext frc = new FontRenderContext(null, false, false);
+
+    protected JavaShapeRasterizer jsr = new JavaShapeRasterizer();
+
+    protected Font font = new Font("Dialog", Font.PLAIN, 12);; //$NON-NLS-1$
+
+    protected TextRenderer jtr = JavaTextRenderer.inst;
+
+    // Current graphics transform
+    protected AffineTransform transform = new AffineTransform();
+    protected double[] matrix = new double[6];
+
+    // Original user->device translation as transform and point
+    //public AffineTransform origTransform = new AffineTransform();
+    public Point origPoint = new Point(0, 0);
+
+
+    // Print debug output or not
+    protected static final boolean debugOutput = "1".equals(System.getProperty("g2d.debug")); //$NON-NLS-1$ //$NON-NLS-2$
+
+    // Constructors
+    protected CommonGraphics2D() {
+    }
+
+    protected CommonGraphics2D(int tx, int ty) {
+        this(tx, ty, null);
+    }
+
+    protected CommonGraphics2D(int tx, int ty, MultiRectArea clip) {
+        setTransform(AffineTransform.getTranslateInstance(tx, ty));
+        //origTransform = AffineTransform.getTranslateInstance(tx, ty);
+        origPoint = new Point(tx, ty);
+        setClip(clip);
+    }
+
+    // Public methods
+    @Override
+    public void addRenderingHints(Map<?,?> hints) {
+        this.hints.putAll(hints);
+    }
+
+    @Override
+    public void clearRect(int x, int y, int width, int height) {
+        Color c = getColor();
+        Paint p = getPaint();
+        setColor(getBackground());
+        fillRect(x, y, width, height);
+        setColor(c);
+        setPaint(p);
+        if (debugOutput) {
+            System.err.println("CommonGraphics2D.clearRect("+x+", "+y+", "+width+", "+height+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+        }
+    }
+
+    @Override
+    public void clipRect(int x, int y, int width, int height) {
+        clip(new Rectangle(x, y, width, height));
+    }
+
+
+    @Override
+    public void clip(Shape s) {
+        if (s == null) {
+            clip = null;
+            return;
+        }
+
+        MultiRectArea mra = null;
+        if (s instanceof MultiRectArea) {
+            mra = new MultiRectArea((MultiRectArea)s);
+            mra.translate((int)transform.getTranslateX(), (int)transform.getTranslateY());
+        } else {
+            int type = transform.getType();
+            if(s instanceof Rectangle && (type & (AffineTransform.TYPE_IDENTITY |
+                AffineTransform.TYPE_TRANSLATION)) != 0){
+                    mra = new MultiRectArea((Rectangle)s);
+                    if(type == AffineTransform.TYPE_TRANSLATION){
+                        mra.translate((int)transform.getTranslateX(), (int)transform.getTranslateY());
+                    }
+            } else {
+                s = transform.createTransformedShape(s);
+                mra = jsr.rasterize(s, 0.5);
+            }
+        }
+
+        if (clip == null) {
+            setTransformedClip(mra);
+        } else {
+            clip.intersect(mra);
+            setTransformedClip(clip);
+        }
+    }
+
+    @Override
+    public void dispose() {
+        // Do nothing for Java only classes
+    }
+
+
+
+
+    /***************************************************************************
+     *
+     *  Draw methods
+     *
+     ***************************************************************************/
+
+    @Override
+    public void draw(Shape s) {
+        if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1) {
+            //TODO: Think about drawing the shape in one fillMultiRectArea call
+            BasicStroke bstroke = (BasicStroke)stroke;
+            JavaLineRasterizer.LineDasher ld = (bstroke.getDashArray() == null)?null:new JavaLineRasterizer.LineDasher(bstroke.getDashArray(), bstroke.getDashPhase());
+            PathIterator pi = s.getPathIterator(transform, 0.5);
+            float []points = new float[6];
+            int x1 = Integer.MIN_VALUE;
+            int y1 = Integer.MIN_VALUE;
+            int cx1 = Integer.MIN_VALUE;
+            int cy1 = Integer.MIN_VALUE;
+            while (!pi.isDone()) {
+                switch (pi.currentSegment(points)) {
+                    case PathIterator.SEG_MOVETO:
+                        x1 = (int)Math.floor(points[0]);
+                        y1 = (int)Math.floor(points[1]);
+                        cx1 = x1;
+                        cy1 = y1;
+                        break;
+                    case PathIterator.SEG_LINETO:
+                        int x2 = (int)Math.floor(points[0]);
+                        int y2 = (int)Math.floor(points[1]);
+                        fillMultiRectArea(JavaLineRasterizer.rasterize(x1, y1, x2, y2, null, ld, false));
+                        x1 = x2;
+                        y1 = y2;
+                        break;
+                    case PathIterator.SEG_CLOSE:
+                        x2 = cx1;
+                        y2 = cy1;
+                        fillMultiRectArea(JavaLineRasterizer.rasterize(x1, y1, x2, y2, null, ld, false));
+                        x1 = x2;
+                        y1 = y2;
+                        break;
+                }
+                pi.next();
+            }
+        } else {
+            s = stroke.createStrokedShape(s);
+            s = transform.createTransformedShape(s);
+            fillMultiRectArea(jsr.rasterize(s, 0.5));
+        }
+    }
+
+    @Override
+    public void drawArc(int x, int y, int width, int height, int sa, int ea) {
+        if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1 &&
+                ((BasicStroke)stroke).getDashArray() == null && 
+                (transform.isIdentity() || transform.getType() == AffineTransform.TYPE_TRANSLATION)) {
+            Point p = new Point(x, y);
+            transform.transform(p, p);
+            MultiRectArea mra = JavaArcRasterizer.rasterize(x, y, width, height, sa, ea, clip);
+            fillMultiRectArea(mra);
+            return;
+        }
+        draw(new Arc2D.Float(x, y, width, height, sa, ea, Arc2D.OPEN));
+    }
+
+
+    @Override
+    public boolean drawImage(Image image, int x, int y, Color bgcolor,
+            ImageObserver imageObserver) {
+
+        if(image == null) {
+            return true;
+        }
+
+        boolean done = false;
+        boolean somebits = false;
+        Surface srcSurf = null;
+        if(image instanceof OffscreenImage){
+            OffscreenImage oi = (OffscreenImage) image;
+            if((oi.getState() & ImageObserver.ERROR) != 0) {
+                return false;
+            }
+            done = oi.prepareImage(imageObserver);
+            somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+            srcSurf = oi.getImageSurface();
+        }else{
+            done = true;
+            srcSurf = Surface.getImageSurface(image);
+        }
+
+        if(done || somebits) {
+            int w = srcSurf.getWidth();
+            int h = srcSurf.getHeight();
+            blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, (AffineTransform) transform.clone(),
+                    composite, bgcolor, clip);
+        }
+        return done;
+    }
+
+    @Override
+    public boolean drawImage(Image image, int x, int y, ImageObserver imageObserver) {
+        return drawImage(image, x, y, null, imageObserver);
+    }
+
+    @Override
+    public boolean drawImage(Image image, int x, int y, int width, int height,
+            Color bgcolor, ImageObserver imageObserver) {
+
+        if(image == null) {
+            return true;
+        }
+        if(width == 0 || height == 0) {
+            return true;
+        }
+
+        boolean done = false;
+        boolean somebits = false;
+        Surface srcSurf = null;
+
+        if(image instanceof OffscreenImage){
+            OffscreenImage oi = (OffscreenImage) image;
+            if((oi.getState() & ImageObserver.ERROR) != 0) {
+                return false;
+            }
+            done = oi.prepareImage(imageObserver);
+            somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+            srcSurf = oi.getImageSurface();
+        }else{
+            done = true;
+            srcSurf = Surface.getImageSurface(image);
+        }
+
+        if(done || somebits) {
+            int w = srcSurf.getWidth();
+            int h = srcSurf.getHeight();
+            if(w == width && h == height){
+                blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+                        (AffineTransform) transform.clone(),
+                        composite, bgcolor, clip);
+            }else{
+                AffineTransform xform = new AffineTransform();
+                xform.setToScale((float)width / w, (float)height / h);
+                blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+                        (AffineTransform) transform.clone(),
+                        xform, composite, bgcolor, clip);
+            }
+        }
+        return done;
+    }
+
+    @Override
+    public boolean drawImage(Image image, int x, int y, int width, int height,
+            ImageObserver imageObserver) {
+        return drawImage(image, x, y, width, height, null, imageObserver);
+    }
+
+    @Override
+    public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
+            int sx1, int sy1, int sx2, int sy2, Color bgcolor,
+            ImageObserver imageObserver) {
+
+        if(image == null) {
+            return true;
+        }
+        if(dx1 == dx2 || dy1 == dy2 || sx1 == sx2 || sy1 == sy2) {
+            return true;
+        }
+
+        boolean done = false;
+        boolean somebits = false;
+        Surface srcSurf = null;
+        if(image instanceof OffscreenImage){
+            OffscreenImage oi = (OffscreenImage) image;
+            if((oi.getState() & ImageObserver.ERROR) != 0) {
+                return false;
+            }
+            done = oi.prepareImage(imageObserver);
+            somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+            srcSurf = oi.getImageSurface();
+        }else{
+            done = true;
+            srcSurf = Surface.getImageSurface(image);
+        }
+
+        if(done || somebits) {
+
+            int dstX = dx1;
+            int dstY = dy1;
+            int srcX = sx1;
+            int srcY = sy1;
+
+            int dstW = dx2 - dx1;
+            int dstH = dy2 - dy1;
+            int srcW = sx2 - sx1;
+            int srcH = sy2 - sy1;
+
+            if(srcW == dstW && srcH == dstH){
+                blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
+                        (AffineTransform) transform.clone(),
+                        composite, bgcolor, clip);
+            }else{
+                AffineTransform xform = new AffineTransform();
+                xform.setToScale((float)dstW / srcW, (float)dstH / srcH);
+                blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
+                        (AffineTransform) transform.clone(),
+                        xform, composite, bgcolor, clip);
+            }
+        }
+        return done;
+    }
+
+    @Override
+    public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
+            int sx1, int sy1, int sx2, int sy2, ImageObserver imageObserver) {
+
+        return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null,
+                imageObserver);
+     }
+
+    @Override
+    public void drawImage(BufferedImage bufImage, BufferedImageOp op,
+            int x, int y) {
+
+        if(bufImage == null) {
+            return;
+        }
+
+        if(op == null) {
+            drawImage(bufImage, x, y, null);
+        } else if(op instanceof AffineTransformOp){
+            AffineTransformOp atop = (AffineTransformOp) op;
+            AffineTransform xform = atop.getTransform();
+            Surface srcSurf = Surface.getImageSurface(bufImage);
+            int w = srcSurf.getWidth();
+            int h = srcSurf.getHeight();
+            blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+                    (AffineTransform) transform.clone(), xform,
+                    composite, null, clip);
+        } else {
+            bufImage = op.filter(bufImage, null);
+            Surface srcSurf = Surface.getImageSurface(bufImage);
+            int w = srcSurf.getWidth();
+            int h = srcSurf.getHeight();
+            blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+                    (AffineTransform) transform.clone(),
+                    composite, null, clip);
+        }
+    }
+
+    @Override
+    public boolean drawImage(Image image, AffineTransform trans,
+            ImageObserver imageObserver) {
+
+        if(image == null) {
+            return true;
+        }
+        if(trans == null || trans.isIdentity()) {
+            return drawImage(image, 0, 0, imageObserver);
+        }
+
+        boolean done = false;
+        boolean somebits = false;
+        Surface srcSurf = null;
+        if(image instanceof OffscreenImage){
+            OffscreenImage oi = (OffscreenImage) image;
+            if((oi.getState() & ImageObserver.ERROR) != 0) {
+                return false;
+            }
+            done = oi.prepareImage(imageObserver);
+            somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+            srcSurf = oi.getImageSurface();
+        }else{
+            done = true;
+            srcSurf = Surface.getImageSurface(image);
+        }
+
+        if(done || somebits) {
+            int w = srcSurf.getWidth();
+            int h = srcSurf.getHeight();
+            AffineTransform xform = (AffineTransform) transform.clone();
+            xform.concatenate(trans);
+            blitter.blit(0, 0, srcSurf, 0, 0, dstSurf, w, h, xform, composite,
+                    null, clip);
+        }
+        return done;
+    }
+
+    @Override
+    public void drawLine(int x1, int y1, int x2, int y2) {
+        if (debugOutput) {
+            System.err.println("CommonGraphics2D.drawLine("+x1+", "+y1+", "+x2+", "+y2+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+        }
+
+        if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1) {
+            BasicStroke bstroke = (BasicStroke)stroke;
+            Point p1 = new Point(x1, y1);
+            Point p2 = new Point(x2, y2);
+            transform.transform(p1, p1);
+            transform.transform(p2, p2);
+            JavaLineRasterizer.LineDasher ld = (bstroke.getDashArray() == null)?null:new JavaLineRasterizer.LineDasher(bstroke.getDashArray(), bstroke.getDashPhase());
+            MultiRectArea mra = JavaLineRasterizer.rasterize(p1.x, p1.y, p2.x, p2.y, null, ld, false);
+            fillMultiRectArea(mra);
+            return;
+        }
+        draw(new Line2D.Float(x1, y1, x2, y2));
+    }
+
+    @Override
+    public void drawOval(int x, int y, int width, int height) {
+        if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1 &&
+                ((BasicStroke)stroke).getDashArray() == null && 
+                (transform.isIdentity() || transform.getType() == AffineTransform.TYPE_TRANSLATION)) {
+            Point p = new Point(x, y);
+            transform.transform(p, p);
+            MultiRectArea mra = JavaArcRasterizer.rasterize(x, y, width, height, 0, 360, clip);
+            fillMultiRectArea(mra);
+            return;
+        }
+        draw(new Ellipse2D.Float(x, y, width, height));
+    }
+
+    @Override
+    public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) {
+        draw(new Polygon(xpoints, ypoints, npoints));
+    }
+
+    @Override
+    public void drawPolygon(Polygon polygon) {
+        draw(polygon);
+    }
+
+    @Override
+    public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) {
+        for (int i = 0; i < npoints-1; i++) {
+            drawLine(xpoints[i], ypoints[i], xpoints[i+1], ypoints[i+1]);
+        }
+    }
+
+    @Override
+    public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
+        if (img == null) {
+            return;
+        }
+
+        double scaleX = xform.getScaleX();
+        double scaleY = xform.getScaleY();
+        if (scaleX == 1 && scaleY == 1) {
+            drawRenderedImage(img.createDefaultRendering(), xform);
+        } else {
+            int width = (int)Math.round(img.getWidth()*scaleX);
+            int height = (int)Math.round(img.getHeight()*scaleY);
+            xform = (AffineTransform)xform.clone();
+            xform.scale(1, 1);
+            drawRenderedImage(img.createScaledRendering(width, height, null), xform);
+        }
+    }
+
+    @Override
+    public void drawRenderedImage(RenderedImage rimg, AffineTransform xform) {
+        if (rimg == null) {
+            return;
+        }
+
+        Image img = null;
+
+        if (rimg instanceof Image) {
+            img = (Image)rimg;
+        } else {
+            //TODO: Create new class to provide Image interface for RenderedImage or rewrite this method
+            img = new BufferedImage(rimg.getColorModel(), rimg.copyData(null), false, null);
+        }
+
+        drawImage(img, xform, null);
+    }
+
+    @Override
+    public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+        if (debugOutput) {
+            System.err.println("CommonGraphics2D.drawRoundRect("+x+", "+y+", "+width+", "+height+","+arcWidth+", "+arcHeight+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
+        }
+
+        draw(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
+    }
+
+
+
+
+
+    /***************************************************************************
+     *
+     *  String methods
+     *
+     ***************************************************************************/
+
+    @Override
+    public void drawString(AttributedCharacterIterator iterator, float x, float y) {
+        GlyphVector gv = font.createGlyphVector(frc, iterator);
+        drawGlyphVector(gv, x, y);
+    }
+
+    @Override
+    public void drawString(AttributedCharacterIterator iterator, int x, int y) {
+        drawString(iterator, (float)x, (float)y);
+    }
+
+    @Override
+    public void drawString(String str, int x, int y) {
+        drawString(str, (float)x, (float)y);
+    }
+
+    @Override
+    public void drawString(String str, float x, float y) {
+        if (debugOutput) {
+            System.err.println("CommonGraphics2D.drawString("+str+", "+x+", "+y+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+        }
+
+        AffineTransform at = (AffineTransform)this.getTransform().clone();
+        AffineTransform fontTransform = font.getTransform();
+        at.concatenate(fontTransform);
+
+        double[] matrix = new double[6];
+        if (!at.isIdentity()){
+
+            int atType = at.getType();
+            at.getMatrix(matrix);
+
+            // TYPE_TRANSLATION
+            if (atType == AffineTransform.TYPE_TRANSLATION){
+                jtr.drawString(this, str,
+                        (float)(x+fontTransform.getTranslateX()),
+                        (float)(y+fontTransform.getTranslateY()));
+                return;
+            }
+            // TODO: we use slow type of drawing strings when Font object
+            // in Graphics has transforms, we just fill outlines. New textrenderer
+            // is to be implemented.
+            Shape sh = font.createGlyphVector(this.getFontRenderContext(), str).getOutline(x, y);
+            this.fill(sh);
+
+        } else {
+            jtr.drawString(this, str, x, y);
+        }
+
+    }
+
+    @Override
+    public void drawGlyphVector(GlyphVector gv, float x, float y) {
+
+        AffineTransform at = gv.getFont().getTransform();
+
+        double[] matrix = new double[6];
+        if ((at != null) && (!at.isIdentity())){
+
+            int atType = at.getType();
+            at.getMatrix(matrix);
+
+            // TYPE_TRANSLATION
+            if ((atType == AffineTransform.TYPE_TRANSLATION) &&
+                ((gv.getLayoutFlags() & GlyphVector.FLAG_HAS_TRANSFORMS) == 0)){
+                jtr.drawGlyphVector(this, gv, (int)(x+matrix[4]), (int)(y+matrix[5]));
+                return;
+            }
+        } else {
+            if (((gv.getLayoutFlags() & GlyphVector.FLAG_HAS_TRANSFORMS) == 0)){
+                jtr.drawGlyphVector(this, gv, x, y);
+                return;
+            }
+        }
+
+        // TODO: we use slow type of drawing strings when Font object
+        // in Graphics has transforms, we just fill outlines. New textrenderer
+        // is to be implemented.
+
+        Shape sh = gv.getOutline(x, y);
+        this.fill(sh);
+
+        }
+
+
+
+
+    /***************************************************************************
+     *
+     *  Fill methods
+     *
+     ***************************************************************************/
+
+    @Override
+    public void fill(Shape s) {
+        s = transform.createTransformedShape(s);
+        MultiRectArea mra = jsr.rasterize(s, 0.5);
+        fillMultiRectArea(mra);
+    }
+
+    @Override
+    public void fillArc(int x, int y, int width, int height, int sa, int ea) {
+        fill(new Arc2D.Float(x, y, width, height, sa, ea, Arc2D.PIE));
+    }
+
+    @Override
+    public void fillOval(int x, int y, int width, int height) {
+        fill(new Ellipse2D.Float(x, y, width, height));
+    }
+
+    @Override
+    public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) {
+        fill(new Polygon(xpoints, ypoints, npoints));
+    }
+
+    @Override
+    public void fillPolygon(Polygon polygon) {
+        fill(polygon);
+    }
+
+    @Override
+    public void fillRect(int x, int y, int width, int height) {
+        if (debugOutput) {
+            System.err.println("CommonGraphics2D.fillRect("+x+", "+y+", "+width+", "+height+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+        }
+
+        fill(new Rectangle(x, y, width, height));
+    }
+
+    @Override
+    public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+        if (debugOutput) {
+            System.err.println("CommonGraphics2D.fillRoundRect("+x+", "+y+", "+width+", "+height+","+arcWidth+", "+arcHeight+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
+        }
+
+        fill(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
+    }
+
+
+
+
+    /***************************************************************************
+     *
+     *  Get methods
+     *
+     ***************************************************************************/
+
+    @Override
+    public Color getBackground() {
+        return bgColor;
+    }
+
+    @Override
+    public Shape getClip() {
+        if (clip == null) {
+            return null;
+        }
+
+        MultiRectArea res = new MultiRectArea(clip);
+        res.translate(-Math.round((float)transform.getTranslateX()), -Math.round((float)transform.getTranslateY()));
+        return res;
+    }
+
+    @Override
+    public Rectangle getClipBounds() {
+        if (clip == null) {
+            return null;
+        }
+
+        Rectangle res = (Rectangle) clip.getBounds().clone();
+        res.translate(-Math.round((float)transform.getTranslateX()), -Math.round((float)transform.getTranslateY()));
+        return res;
+    }
+
+    @Override
+    public Color getColor() {
+        return fgColor;
+    }
+
+    @Override
+    public Composite getComposite() {
+        return composite;
+    }
+
+    @Override
+    public Font getFont() {
+        return font;
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public FontMetrics getFontMetrics(Font font) {
+        return Toolkit.getDefaultToolkit().getFontMetrics(font);
+    }
+
+    @Override
+    public FontRenderContext getFontRenderContext() {
+        return frc;
+    }
+
+    @Override
+    public Paint getPaint() {
+        return paint;
+    }
+
+    @Override
+    public Object getRenderingHint(RenderingHints.Key key) {
+        return hints.get(key);
+    }
+
+    @Override
+    public RenderingHints getRenderingHints() {
+        return hints;
+    }
+
+    @Override
+    public Stroke getStroke() {
+        return stroke;
+    }
+
+    @Override
+    public AffineTransform getTransform() {
+        return (AffineTransform)transform.clone();
+    }
+
+    @Override
+    public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
+        //TODO: Implement method....
+        return false;
+    }
+
+
+
+
+    /***************************************************************************
+     *
+     *  Transformation methods
+     *
+     ***************************************************************************/
+
+    @Override
+    public void rotate(double theta) {
+        transform.rotate(theta);
+        transform.getMatrix(matrix);
+    }
+
+    @Override
+    public void rotate(double theta, double x, double y) {
+        transform.rotate(theta, x, y);
+        transform.getMatrix(matrix);
+    }
+
+    @Override
+    public void scale(double sx, double sy) {
+        transform.scale(sx, sy);
+        transform.getMatrix(matrix);
+    }
+
+    @Override
+    public void shear(double shx, double shy) {
+        transform.shear(shx, shy);
+        transform.getMatrix(matrix);
+    }
+
+    @Override
+    public void transform(AffineTransform at) {
+        transform.concatenate(at);
+        transform.getMatrix(matrix);
+    }
+
+    @Override
+    public void translate(double tx, double ty) {
+        if (debugOutput) {
+            System.err.println("CommonGraphics2D.translate("+tx+", "+ty+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+
+        transform.translate(tx, ty);
+        transform.getMatrix(matrix);
+    }
+
+    @Override
+    public void translate(int tx, int ty) {
+        if (debugOutput) {
+            System.err.println("CommonGraphics2D.translate("+tx+", "+ty+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+
+        transform.translate(tx, ty);
+        transform.getMatrix(matrix);
+    }
+
+
+
+
+    /***************************************************************************
+     *
+     *  Set methods
+     *
+     ***************************************************************************/
+
+    @Override
+    public void setBackground(Color color) {
+        bgColor = color;
+    }
+
+    @Override
+    public void setClip(int x, int y, int width, int height) {
+        setClip(new Rectangle(x, y, width, height));
+    }
+
+    @Override
+    public void setClip(Shape s) {
+        if (s == null) {
+            setTransformedClip(null);
+            if (debugOutput) {
+                System.err.println("CommonGraphics2D.setClip(null)"); //$NON-NLS-1$
+            }
+            return;
+        }
+
+        if (debugOutput) {
+            System.err.println("CommonGraphics2D.setClip("+s.getBounds()+")"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        if (s instanceof MultiRectArea) {
+            MultiRectArea nclip = new MultiRectArea((MultiRectArea)s);
+            nclip.translate(Math.round((float)transform.getTranslateX()), Math.round((float)transform.getTranslateY()));
+            setTransformedClip(nclip);
+        } else {
+            int type = transform.getType();
+            if(s instanceof Rectangle && (type & (AffineTransform.TYPE_IDENTITY |
+                AffineTransform.TYPE_TRANSLATION)) != 0){
+                    MultiRectArea nclip = new MultiRectArea((Rectangle)s);
+                    if(type == AffineTransform.TYPE_TRANSLATION){
+                        nclip.translate((int)transform.getTranslateX(), (int)transform.getTranslateY());
+                    }
+                    setTransformedClip(nclip);
+            } else {
+                s = transform.createTransformedShape(s);
+                setTransformedClip(jsr.rasterize(s, 0.5));
+            }
+        }
+    }
+
+    @Override
+    public void setColor(Color color) {
+        if (color != null) {
+            fgColor = color;
+            paint = color;
+        }
+    }
+
+    @Override
+    public void setComposite(Composite composite) {
+        this.composite = composite;
+    }
+
+    @Override
+    public void setFont(Font font) {
+        this.font = font;
+    }
+
+    @Override
+    public void setPaint(Paint paint) {
+        if (paint == null)
+            return;
+            
+        this.paint = paint;
+        if (paint instanceof Color) {
+            fgColor = (Color)paint;
+        }
+    }
+
+    @Override
+    public void setPaintMode() {
+        composite = AlphaComposite.SrcOver;
+    }
+
+    @Override
+    public void setRenderingHint(RenderingHints.Key key, Object value) {
+        hints.put(key, value);
+    }
+
+    @Override
+    public void setRenderingHints(Map<?,?> hints) {
+        this.hints.clear();
+        this.hints.putAll(hints);
+    }
+
+    @Override
+    public void setStroke(Stroke stroke) {
+        this.stroke = stroke;
+    }
+
+    @Override
+    public void setTransform(AffineTransform transform) {
+        this.transform = transform;
+
+        transform.getMatrix(matrix);
+    }
+
+    @Override
+    public void setXORMode(Color color) {
+        composite = new XORComposite(color);
+    }
+
+
+    // Protected methods
+    protected void setTransformedClip(MultiRectArea clip) {
+        this.clip = clip;
+    }
+
+    /**
+     * This method fills the given MultiRectArea with current paint.
+     * It calls fillMultiRectAreaColor and fillMultiRectAreaPaint 
+     * methods depending on the type of current paint.
+     * @param mra MultiRectArea to fill
+     */
+    protected void fillMultiRectArea(MultiRectArea mra) {
+        if (clip != null) {
+            mra.intersect(clip);
+        }
+
+        // Return if all stuff is clipped
+        if (mra.rect[0] < 5) {
+            return;
+        }
+
+        if (debugOutput) {
+            System.err.println("CommonGraphics2D.fillMultiRectArea("+mra+")"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        if (paint instanceof Color){
+            fillMultiRectAreaColor(mra);
+        }else{
+            fillMultiRectAreaPaint(mra);
+        }
+    }
+
+    /**
+     * This method fills the given MultiRectArea with solid color.
+     * @param mra MultiRectArea to fill
+     */
+    protected void fillMultiRectAreaColor(MultiRectArea mra) {
+        fillMultiRectAreaPaint(mra);
+    }
+
+    /**
+     * This method fills the given MultiRectArea with any paint.
+     * @param mra MultiRectArea to fill
+     */
+    protected void fillMultiRectAreaPaint(MultiRectArea mra) {
+        Rectangle rec = mra.getBounds();
+        int x = rec.x;
+        int y = rec.y;
+        int w = rec.width;
+        int h = rec.height;
+        if(w <= 0 || h <= 0) {
+            return;
+        }
+        PaintContext pc = paint.createContext(null, rec, rec, transform, hints);
+        Raster r = pc.getRaster(x, y, w, h);
+        WritableRaster wr;
+        if(r instanceof WritableRaster){
+            wr = (WritableRaster) r;
+        }else{
+            wr = r.createCompatibleWritableRaster();
+            wr.setRect(r);
+        }
+        Surface srcSurf = new ImageSurface(pc.getColorModel(), wr);
+        blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+                composite, null, mra);
+        srcSurf.dispose();
+    }
+
+    /**
+     * Copies graphics class fields. 
+     * Used in create method
+     * 
+     * @param copy Graphics class to copy
+     */
+    protected void copyInternalFields(CommonGraphics2D copy) {
+        if (clip == null) {
+            copy.setTransformedClip(null);
+        } else {
+            copy.setTransformedClip(new MultiRectArea(clip));
+        }
+        copy.setBackground(bgColor);
+        copy.setColor(fgColor);
+        copy.setPaint(paint);
+        copy.setComposite(composite);
+        copy.setStroke(stroke);
+        copy.setFont(font);
+        copy.setTransform(new AffineTransform(transform));
+        //copy.origTransform = new AffineTransform(origTransform);
+        copy.origPoint = new Point(origPoint);
+    }
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java b/awt/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java
new file mode 100644
index 0000000..27e3ef0
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java
@@ -0,0 +1,78 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko, Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.peer.FontPeer;
+
+import org.apache.harmony.awt.gl.font.FontMetricsImpl;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+
+/**
+ * Common GraphicsFactory implementation
+ *
+ */
+public abstract class CommonGraphics2DFactory implements GraphicsFactory {
+    
+    // static instance of CommonGraphics2DFactory
+    public static CommonGraphics2DFactory inst;
+
+    /**
+     * Returns FontMetrics object that keeps metrics of the specified font.
+     * 
+     * @param font specified Font
+     * @return FontMetrics object corresponding to the specified Font object
+     */
+    public FontMetrics getFontMetrics(Font font) {
+        FontMetrics fm;
+        for (FontMetrics element : cacheFM) {
+            fm = element;
+            if (fm == null){
+                break;
+            }
+
+            if (fm.getFont().equals(font)){
+                return fm;
+            }
+        }
+        fm = new FontMetricsImpl(font);
+
+        System.arraycopy(cacheFM, 0, cacheFM, 1, cacheFM.length -1);
+        cacheFM[0] = fm;
+
+        return fm;
+    }
+    // Font methods
+
+    public FontPeer getFontPeer(Font font) {
+        return getFontManager().getFontPeer(font.getName(), font.getStyle(), font.getSize());
+    }
+    
+    /**
+     * Embeds font from gile with specified path into the system. 
+     * 
+     * @param fontFilePath path to the font file 
+     * @return Font object that was created from the file.
+     */
+    public abstract Font embedFont(String fontFilePath);
+
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java b/awt/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java
new file mode 100644
index 0000000..5c78e50
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java
@@ -0,0 +1,67 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko, Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import org.apache.harmony.awt.gl.image.BufferedImageGraphics2D;
+
+/**
+ * Common GraphicsEnvironment implementation
+ *
+ */
+public abstract class CommonGraphicsEnvironment extends GraphicsEnvironment {
+
+    @Override
+    public Graphics2D createGraphics(BufferedImage bufferedImage) {
+        return new BufferedImageGraphics2D(bufferedImage);
+    }
+
+    @Override
+    public String[] getAvailableFontFamilyNames(Locale locale) {
+        Font[] fonts = getAllFonts();
+        ArrayList<String> familyNames = new ArrayList<String>();
+
+        for (Font element : fonts) {
+            String name = element.getFamily(locale);
+            if (!familyNames.contains(name)) {
+                familyNames.add(name);
+            }
+        }
+
+        return familyNames.toArray(new String[familyNames.size()]);
+    }
+
+    @Override
+    public Font[] getAllFonts() {
+        return CommonGraphics2DFactory.inst.getFontManager().getAllFonts();
+    }
+
+    @Override
+    public String[] getAvailableFontFamilyNames() {
+        return CommonGraphics2DFactory.inst.getFontManager().getAllFamilies();
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/Crossing.java b/awt/org/apache/harmony/awt/gl/Crossing.java
new file mode 100644
index 0000000..ae7fb0e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/Crossing.java
@@ -0,0 +1,889 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Shape;
+import java.awt.geom.PathIterator;
+
+public class Crossing {
+
+    /**
+     * Allowable tolerance for bounds comparison
+     */
+    static final double DELTA = 1E-5;
+    
+    /**
+     * If roots have distance less then <code>ROOT_DELTA</code> they are double
+     */
+    static final double ROOT_DELTA = 1E-10;
+    
+    /**
+     * Rectangle cross segment
+     */
+    public static final int CROSSING = 255;
+    
+    /**
+     * Unknown crossing result
+     */
+    static final int UNKNOWN = 254;
+
+    /**
+     * Solves quadratic equation
+     * @param eqn - the coefficients of the equation
+     * @param res - the roots of the equation
+     * @return a number of roots
+     */
+    public static int solveQuad(double eqn[], double res[]) {
+        double a = eqn[2];
+        double b = eqn[1];
+        double c = eqn[0];
+        int rc = 0;
+        if (a == 0.0) {
+            if (b == 0.0) {
+                return -1;
+            }
+            res[rc++] = -c / b;
+        } else {
+            double d = b * b - 4.0 * a * c;
+            // d < 0.0
+            if (d < 0.0) {
+                return 0;
+            }
+            d = Math.sqrt(d);
+            res[rc++] = (- b + d) / (a * 2.0);
+            // d != 0.0
+            if (d != 0.0) {
+                res[rc++] = (- b - d) / (a * 2.0);
+            }
+        }
+        return fixRoots(res, rc);
+    }
+
+    /**
+     * Solves cubic equation
+     * @param eqn - the coefficients of the equation
+     * @param res - the roots of the equation
+     * @return a number of roots
+     */
+    public static int solveCubic(double eqn[], double res[]) {
+        double d = eqn[3];
+        if (d == 0) {
+            return solveQuad(eqn, res);
+        }
+        double a = eqn[2] / d;
+        double b = eqn[1] / d;
+        double c = eqn[0] / d;
+        int rc = 0;
+
+        double Q = (a * a - 3.0 * b) / 9.0;
+        double R = (2.0 * a * a * a - 9.0 * a * b + 27.0 * c) / 54.0;
+        double Q3 = Q * Q * Q;
+        double R2 = R * R;
+        double n = - a / 3.0;
+
+        if (R2 < Q3) {
+            double t = Math.acos(R / Math.sqrt(Q3)) / 3.0;
+            double p = 2.0 * Math.PI / 3.0;
+            double m = -2.0 * Math.sqrt(Q);
+            res[rc++] = m * Math.cos(t) + n;
+            res[rc++] = m * Math.cos(t + p) + n;
+            res[rc++] = m * Math.cos(t - p) + n;
+        } else {
+//          Debug.println("R2 >= Q3 (" + R2 + "/" + Q3 + ")");
+            double A = Math.pow(Math.abs(R) + Math.sqrt(R2 - Q3), 1.0 / 3.0);
+            if (R > 0.0) {
+                A = -A;
+            }
+//          if (A == 0.0) {
+            if (-ROOT_DELTA < A && A < ROOT_DELTA) {
+                res[rc++] = n;
+            } else {
+                double B = Q / A;
+                res[rc++] = A + B + n;
+//              if (R2 == Q3) {
+                double delta = R2 - Q3;
+                if (-ROOT_DELTA < delta && delta < ROOT_DELTA) {
+                    res[rc++] = - (A + B) / 2.0 + n;
+                }
+            }
+
+        }
+        return fixRoots(res, rc);
+    }
+
+    /**
+     * Excludes double roots. Roots are double if they lies enough close with each other. 
+     * @param res - the roots 
+     * @param rc - the roots count
+     * @return new roots count
+     */
+    static int fixRoots(double res[], int rc) {
+        int tc = 0;
+        for(int i = 0; i < rc; i++) {
+            out: {
+                for(int j = i + 1; j < rc; j++) {
+                    if (isZero(res[i] - res[j])) {
+                        break out;
+                    }
+                }
+                res[tc++] = res[i];
+            }
+        }
+        return tc;
+    }
+
+    /**
+     * QuadCurve class provides basic functionality to find curve crossing and calculating bounds
+     */
+    public static class QuadCurve {
+
+        double ax, ay, bx, by;
+        double Ax, Ay, Bx, By;
+
+        public QuadCurve(double x1, double y1, double cx, double cy, double x2, double y2) {
+            ax = x2 - x1;
+            ay = y2 - y1;
+            bx = cx - x1;
+            by = cy - y1;
+
+            Bx = bx + bx;   // Bx = 2.0 * bx
+            Ax = ax - Bx;   // Ax = ax - 2.0 * bx
+
+            By = by + by;   // By = 2.0 * by
+            Ay = ay - By;   // Ay = ay - 2.0 * by
+        }
+
+        int cross(double res[], int rc, double py1, double py2) {
+            int cross = 0;
+
+            for (int i = 0; i < rc; i++) {
+                double t = res[i];
+
+                // CURVE-OUTSIDE
+                if (t < -DELTA || t > 1 + DELTA) {
+                    continue;
+                }
+                // CURVE-START
+                if (t < DELTA) {
+                    if (py1 < 0.0 && (bx != 0.0 ? bx : ax - bx) < 0.0) {
+                        cross--;
+                    }
+                    continue;
+                }
+                // CURVE-END
+                if (t > 1 - DELTA) {
+                    if (py1 < ay && (ax != bx ? ax - bx : bx) > 0.0) {
+                        cross++;
+                    }
+                    continue;
+                }
+                // CURVE-INSIDE
+                double ry = t * (t * Ay + By);
+                // ry = t * t * Ay + t * By
+                if (ry > py2) {
+                    double rxt = t * Ax + bx;
+                    // rxt = 2.0 * t * Ax + Bx = 2.0 * t * Ax + 2.0 * bx
+                    if (rxt > -DELTA && rxt < DELTA) {
+                        continue;
+                    }
+                    cross += rxt > 0.0 ? 1 : -1;
+                }
+            } // for
+
+            return cross;
+        }
+
+        int solvePoint(double res[], double px) {
+            double eqn[] = {-px, Bx, Ax};
+            return solveQuad(eqn, res);
+        }
+
+        int solveExtrem(double res[]) {
+            int rc = 0;
+            if (Ax != 0.0) {
+                res[rc++] = - Bx / (Ax + Ax);
+            }
+            if (Ay != 0.0) {
+                res[rc++] = - By / (Ay + Ay);
+            }
+            return rc;
+        }
+
+        int addBound(double bound[], int bc, double res[], int rc, double minX, double maxX, boolean changeId, int id) {
+            for(int i = 0; i < rc; i++) {
+                double t = res[i];
+                if (t > -DELTA && t < 1 + DELTA) {
+                    double rx = t * (t * Ax + Bx);
+                    if (minX <= rx && rx <= maxX) {
+                        bound[bc++] = t;
+                        bound[bc++] = rx;
+                        bound[bc++] = t * (t * Ay + By);
+                        bound[bc++] = id;
+                        if (changeId) {
+                            id++;
+                        }
+                    }
+                }
+            }
+            return bc;
+        }
+
+    }
+
+    /**
+     * CubicCurve class provides basic functionality to find curve crossing and calculating bounds
+     */
+    public static class CubicCurve {
+
+        double ax, ay, bx, by, cx, cy;
+        double Ax, Ay, Bx, By, Cx, Cy;
+        double Ax3, Bx2;
+
+        public CubicCurve(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2) {
+            ax = x2 - x1;
+            ay = y2 - y1;
+            bx = cx1 - x1;
+            by = cy1 - y1;
+            cx = cx2 - x1;
+            cy = cy2 - y1;
+
+            Cx = bx + bx + bx;           // Cx = 3.0 * bx
+            Bx = cx + cx + cx - Cx - Cx; // Bx = 3.0 * cx - 6.0 * bx
+            Ax = ax - Bx - Cx;           // Ax = ax - 3.0 * cx + 3.0 * bx
+
+            Cy = by + by + by;           // Cy = 3.0 * by
+            By = cy + cy + cy - Cy - Cy; // By = 3.0 * cy - 6.0 * by
+            Ay = ay - By - Cy;           // Ay = ay - 3.0 * cy + 3.0 * by
+
+            Ax3 = Ax + Ax + Ax;
+            Bx2 = Bx + Bx;
+        }
+
+        int cross(double res[], int rc, double py1, double py2) {
+            int cross = 0;
+            for (int i = 0; i < rc; i++) {
+                double t = res[i];
+
+                // CURVE-OUTSIDE
+                if (t < -DELTA || t > 1 + DELTA) {
+                    continue;
+                }
+                // CURVE-START
+                if (t < DELTA) {
+                    if (py1 < 0.0 && (bx != 0.0 ? bx : (cx != bx ? cx - bx : ax - cx)) < 0.0) {
+                        cross--;
+                    }
+                    continue;
+                }
+                // CURVE-END
+                if (t > 1 - DELTA) {
+                    if (py1 < ay && (ax != cx ? ax - cx : (cx != bx ? cx - bx : bx)) > 0.0) {
+                        cross++;
+                    }
+                    continue;
+                }
+                // CURVE-INSIDE
+                double ry = t * (t * (t * Ay + By) + Cy);
+                // ry = t * t * t * Ay + t * t * By + t * Cy
+                if (ry > py2) {
+                    double rxt = t * (t * Ax3 + Bx2) + Cx;
+                    // rxt = 3.0 * t * t * Ax + 2.0 * t * Bx + Cx
+                    if (rxt > -DELTA && rxt < DELTA) {
+                        rxt = t * (Ax3 + Ax3) + Bx2;
+                        // rxt = 6.0 * t * Ax + 2.0 * Bx
+                        if (rxt < -DELTA || rxt > DELTA) {
+                            // Inflection point
+                            continue;
+                        }
+                        rxt = ax;
+                    }
+                    cross += rxt > 0.0 ? 1 : -1;
+                }
+            } //for
+
+            return cross;
+        }
+
+        int solvePoint(double res[], double px) {
+            double eqn[] = {-px, Cx, Bx, Ax};
+            return solveCubic(eqn, res);
+        }
+
+        int solveExtremX(double res[]) {
+            double eqn[] = {Cx, Bx2, Ax3};
+            return solveQuad(eqn, res);
+        }
+
+        int solveExtremY(double res[]) {
+            double eqn[] = {Cy, By + By, Ay + Ay + Ay};
+            return solveQuad(eqn, res);
+        }
+
+        int addBound(double bound[], int bc, double res[], int rc, double minX, double maxX, boolean changeId, int id) {
+            for(int i = 0; i < rc; i++) {
+                double t = res[i];
+                if (t > -DELTA && t < 1 + DELTA) {
+                    double rx = t * (t * (t * Ax + Bx) + Cx);
+                    if (minX <= rx && rx <= maxX) {
+                        bound[bc++] = t;
+                        bound[bc++] = rx;
+                        bound[bc++] = t * (t * (t * Ay + By) + Cy);
+                        bound[bc++] = id;
+                        if (changeId) {
+                            id++;
+                        }
+                    }
+                }
+            }
+            return bc;
+        }
+
+    }
+
+    /**
+     * Returns how many times ray from point (x,y) cross line.
+     */
+    public static int crossLine(double x1, double y1, double x2, double y2, double x, double y) {
+
+        // LEFT/RIGHT/UP/EMPTY
+        if ((x < x1 && x < x2) ||
+            (x > x1 && x > x2) ||
+            (y > y1 && y > y2) ||
+            (x1 == x2))
+        {
+            return 0;
+        }
+
+        // DOWN
+        if (y < y1 && y < y2) {
+        } else {
+            // INSIDE
+            if ((y2 - y1) * (x - x1) / (x2 - x1) <= y - y1) {
+                // INSIDE-UP
+                return 0;
+            }
+        }
+
+        // START
+        if (x == x1) {
+            return x1 < x2 ? 0 : -1;
+        }
+
+        // END
+        if (x == x2) {
+            return x1 < x2 ? 1 : 0;
+        }
+
+        // INSIDE-DOWN
+        return x1 < x2 ? 1 : -1;
+    }
+
+    /**
+     * Returns how many times ray from point (x,y) cross quard curve
+     */
+    public static int crossQuad(double x1, double y1, double cx, double cy, double x2, double y2, double x, double y) {
+
+        // LEFT/RIGHT/UP/EMPTY
+        if ((x < x1 && x < cx && x < x2) ||
+            (x > x1 && x > cx && x > x2) ||
+            (y > y1 && y > cy && y > y2) ||
+            (x1 == cx && cx == x2))
+        {
+            return 0;
+        }
+
+        // DOWN
+        if (y < y1 && y < cy && y < y2 && x != x1 && x != x2) {
+            if (x1 < x2) {
+                return x1 < x && x < x2 ? 1 : 0;
+            }
+            return x2 < x && x < x1 ? -1 : 0;
+        }
+
+        // INSIDE
+        QuadCurve c = new QuadCurve(x1, y1, cx, cy, x2, y2);
+        double px = x - x1;
+        double py = y - y1;
+        double res[] = new double[3];
+        int rc = c.solvePoint(res, px);
+
+        return c.cross(res, rc, py, py);
+    }
+
+    /**
+     * Returns how many times ray from point (x,y) cross cubic curve
+     */
+    public static int crossCubic(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2, double x, double y) {
+
+        // LEFT/RIGHT/UP/EMPTY
+        if ((x < x1 && x < cx1 && x < cx2 && x < x2) ||
+            (x > x1 && x > cx1 && x > cx2 && x > x2) ||
+            (y > y1 && y > cy1 && y > cy2 && y > y2) ||
+            (x1 == cx1 && cx1 == cx2 && cx2 == x2))
+        {
+            return 0;
+        }
+
+        // DOWN
+        if (y < y1 && y < cy1 && y < cy2 && y < y2 && x != x1 && x != x2) {
+            if (x1 < x2) {
+                return x1 < x && x < x2 ? 1 : 0;
+            }
+            return x2 < x && x < x1 ? -1 : 0;
+        }
+
+        // INSIDE
+        CubicCurve c = new CubicCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2);
+        double px = x - x1;
+        double py = y - y1;
+        double res[] = new double[3];
+        int rc = c.solvePoint(res, px);
+        return c.cross(res, rc, py, py);
+    }
+
+    /**
+     * Returns how many times ray from point (x,y) cross path
+     */
+    public static int crossPath(PathIterator p, double x, double y) {
+        int cross = 0;
+        double mx, my, cx, cy;
+        mx = my = cx = cy = 0.0;
+        double coords[] = new double[6];
+
+        while (!p.isDone()) {
+            switch (p.currentSegment(coords)) {
+            case PathIterator.SEG_MOVETO:
+                if (cx != mx || cy != my) {
+                    cross += crossLine(cx, cy, mx, my, x, y);
+                }
+                mx = cx = coords[0];
+                my = cy = coords[1];
+                break;
+            case PathIterator.SEG_LINETO:
+                cross += crossLine(cx, cy, cx = coords[0], cy = coords[1], x, y);
+                break;
+            case PathIterator.SEG_QUADTO:
+                cross += crossQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3], x, y);
+                break;
+            case PathIterator.SEG_CUBICTO:
+                cross += crossCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5], x, y);
+                break;
+            case PathIterator.SEG_CLOSE:
+                if (cy != my || cx != mx) {
+                    cross += crossLine(cx, cy, cx = mx, cy = my, x, y);
+                }
+                break;
+            }
+            p.next();
+        }
+        if (cy != my) {
+            cross += crossLine(cx, cy, mx, my, x, y);
+        }
+        return cross;
+    }
+
+    /**
+     * Returns how many times ray from point (x,y) cross shape
+     */
+    public static int crossShape(Shape s, double x, double y) {
+        if (!s.getBounds2D().contains(x, y)) {
+            return 0;
+        }
+        return crossPath(s.getPathIterator(null), x, y);
+    }
+
+    /**
+     * Returns true if value enough small
+     */
+    public static boolean isZero(double val) {
+        return -DELTA < val && val < DELTA;
+    }
+
+    /**
+     * Sort bound array
+     */
+    static void sortBound(double bound[], int bc) {
+        for(int i = 0; i < bc - 4; i += 4) {
+            int k = i;
+            for(int j = i + 4; j < bc; j += 4) {
+                if (bound[k] > bound[j]) {
+                    k = j;
+                }
+            }
+            if (k != i) {
+                double tmp = bound[i];
+                bound[i] = bound[k];
+                bound[k] = tmp;
+                tmp = bound[i + 1];
+                bound[i + 1] = bound[k + 1];
+                bound[k + 1] = tmp;
+                tmp = bound[i + 2];
+                bound[i + 2] = bound[k + 2];
+                bound[k + 2] = tmp;
+                tmp = bound[i + 3];
+                bound[i + 3] = bound[k + 3];
+                bound[k + 3] = tmp;
+            }
+        }
+    }
+    
+    /**
+     * Returns are bounds intersect or not intersect rectangle 
+     */
+    static int crossBound(double bound[], int bc, double py1, double py2) {
+
+        // LEFT/RIGHT
+        if (bc == 0) {
+            return 0;
+        }
+
+        // Check Y coordinate
+        int up = 0;
+        int down = 0;
+        for(int i = 2; i < bc; i += 4) {
+            if (bound[i] < py1) {
+                up++;
+                continue;
+            }
+            if (bound[i] > py2) {
+                down++;
+                continue;
+            }
+            return CROSSING;
+        }
+
+        // UP
+        if (down == 0) {
+            return 0;
+        }
+
+        if (up != 0) {
+            // bc >= 2
+            sortBound(bound, bc);
+            boolean sign = bound[2] > py2;
+            for(int i = 6; i < bc; i += 4) {
+                boolean sign2 = bound[i] > py2;
+                if (sign != sign2 && bound[i + 1] != bound[i - 3]) {
+                    return CROSSING;
+                }
+                sign = sign2;
+            }
+        }
+        return UNKNOWN;
+    }
+
+    /**
+     * Returns how many times rectangle stripe cross line or the are intersect
+     */
+    public static int intersectLine(double x1, double y1, double x2, double y2, double rx1, double ry1, double rx2, double ry2) {
+
+        // LEFT/RIGHT/UP
+        if ((rx2 < x1 && rx2 < x2) ||
+            (rx1 > x1 && rx1 > x2) ||
+            (ry1 > y1 && ry1 > y2))
+        {
+            return 0;
+        }
+
+        // DOWN
+        if (ry2 < y1 && ry2 < y2) {
+        } else {
+
+            // INSIDE
+            if (x1 == x2) {
+                return CROSSING;
+            }
+
+            // Build bound
+            double bx1, bx2;
+            if (x1 < x2) {
+                bx1 = x1 < rx1 ? rx1 : x1;
+                bx2 = x2 < rx2 ? x2 : rx2;
+            } else {
+                bx1 = x2 < rx1 ? rx1 : x2;
+                bx2 = x1 < rx2 ? x1 : rx2;
+            }
+            double k = (y2 - y1) / (x2 - x1);
+            double by1 = k * (bx1 - x1) + y1;
+            double by2 = k * (bx2 - x1) + y1;
+
+            // BOUND-UP
+            if (by1 < ry1 && by2 < ry1) {
+                return 0;
+            }
+
+            // BOUND-DOWN
+            if (by1 > ry2 && by2 > ry2) {
+            } else {
+                return CROSSING;
+            }
+        }
+
+        // EMPTY
+        if (x1 == x2) {
+            return 0;
+        }
+
+        // CURVE-START
+        if (rx1 == x1) {
+            return x1 < x2 ? 0 : -1;
+        }
+
+        // CURVE-END
+        if (rx1 == x2) {
+            return x1 < x2 ? 1 : 0;
+        }
+
+        if (x1 < x2) {
+            return x1 < rx1 && rx1 < x2 ? 1 : 0;
+        }
+        return x2 < rx1 && rx1 < x1 ? -1 : 0;
+
+    }
+
+    /**
+     * Returns how many times rectangle stripe cross quad curve or the are intersect
+     */
+    public static int intersectQuad(double x1, double y1, double cx, double cy, double x2, double y2, double rx1, double ry1, double rx2, double ry2) {
+
+        // LEFT/RIGHT/UP ------------------------------------------------------
+        if ((rx2 < x1 && rx2 < cx && rx2 < x2) ||
+            (rx1 > x1 && rx1 > cx && rx1 > x2) ||
+            (ry1 > y1 && ry1 > cy && ry1 > y2))
+        {
+            return 0;
+        }
+
+        // DOWN ---------------------------------------------------------------
+        if (ry2 < y1 && ry2 < cy && ry2 < y2 && rx1 != x1 && rx1 != x2) {
+            if (x1 < x2) {
+                return x1 < rx1 && rx1 < x2 ? 1 : 0;
+            }
+            return x2 < rx1 && rx1 < x1 ? -1 : 0;
+        }
+
+        // INSIDE -------------------------------------------------------------
+        QuadCurve c = new QuadCurve(x1, y1, cx, cy, x2, y2);
+        double px1 = rx1 - x1;
+        double py1 = ry1 - y1;
+        double px2 = rx2 - x1;
+        double py2 = ry2 - y1;
+
+        double res1[] = new double[3];
+        double res2[] = new double[3];
+        int rc1 = c.solvePoint(res1, px1);
+        int rc2 = c.solvePoint(res2, px2);
+
+        // INSIDE-LEFT/RIGHT
+        if (rc1 == 0 && rc2 == 0) {
+            return 0;
+        }
+
+        // Build bound --------------------------------------------------------
+        double minX = px1 - DELTA;
+        double maxX = px2 + DELTA;
+        double bound[] = new double[28];
+        int bc = 0;
+        // Add roots
+        bc = c.addBound(bound, bc, res1, rc1, minX, maxX, false, 0);
+        bc = c.addBound(bound, bc, res2, rc2, minX, maxX, false, 1);
+        // Add extremal points`
+        rc2 = c.solveExtrem(res2);
+        bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 2);
+        // Add start and end
+        if (rx1 < x1 && x1 < rx2) {
+            bound[bc++] = 0.0;
+            bound[bc++] = 0.0;
+            bound[bc++] = 0.0;
+            bound[bc++] = 4;
+        }
+        if (rx1 < x2 && x2 < rx2) {
+            bound[bc++] = 1.0;
+            bound[bc++] = c.ax;
+            bound[bc++] = c.ay;
+            bound[bc++] = 5;
+        }
+        // End build bound ----------------------------------------------------
+
+        int cross = crossBound(bound, bc, py1, py2);
+        if (cross != UNKNOWN) {
+            return cross;
+        }
+        return c.cross(res1, rc1, py1, py2);
+    }
+
+    /**
+     * Returns how many times rectangle stripe cross cubic curve or the are intersect
+     */
+    public static int intersectCubic(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2, double rx1, double ry1, double rx2, double ry2) {
+
+        // LEFT/RIGHT/UP
+        if ((rx2 < x1 && rx2 < cx1 && rx2 < cx2 && rx2 < x2) ||
+            (rx1 > x1 && rx1 > cx1 && rx1 > cx2 && rx1 > x2) ||
+            (ry1 > y1 && ry1 > cy1 && ry1 > cy2 && ry1 > y2))
+        {
+            return 0;
+        }
+
+        // DOWN
+        if (ry2 < y1 && ry2 < cy1 && ry2 < cy2 && ry2 < y2 && rx1 != x1 && rx1 != x2) {
+            if (x1 < x2) {
+                return x1 < rx1 && rx1 < x2 ? 1 : 0;
+            }
+            return x2 < rx1 && rx1 < x1 ? -1 : 0;
+        }
+
+        // INSIDE
+        CubicCurve c = new CubicCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2);
+        double px1 = rx1 - x1;
+        double py1 = ry1 - y1;
+        double px2 = rx2 - x1;
+        double py2 = ry2 - y1;
+
+        double res1[] = new double[3];
+        double res2[] = new double[3];
+        int rc1 = c.solvePoint(res1, px1);
+        int rc2 = c.solvePoint(res2, px2);
+
+        // LEFT/RIGHT
+        if (rc1 == 0 && rc2 == 0) {
+            return 0;
+        }
+
+        double minX = px1 - DELTA;
+        double maxX = px2 + DELTA;
+
+        // Build bound --------------------------------------------------------
+        double bound[] = new double[40];
+        int bc = 0;
+        // Add roots
+        bc = c.addBound(bound, bc, res1, rc1, minX, maxX, false, 0);
+        bc = c.addBound(bound, bc, res2, rc2, minX, maxX, false, 1);
+        // Add extrimal points
+        rc2 = c.solveExtremX(res2);
+        bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 2);
+        rc2 = c.solveExtremY(res2);
+        bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 4);
+        // Add start and end
+        if (rx1 < x1 && x1 < rx2) {
+            bound[bc++] = 0.0;
+            bound[bc++] = 0.0;
+            bound[bc++] = 0.0;
+            bound[bc++] = 6;
+        }
+        if (rx1 < x2 && x2 < rx2) {
+            bound[bc++] = 1.0;
+            bound[bc++] = c.ax;
+            bound[bc++] = c.ay;
+            bound[bc++] = 7;
+        }
+        // End build bound ----------------------------------------------------
+
+        int cross = crossBound(bound, bc, py1, py2);
+        if (cross != UNKNOWN) {
+            return cross;
+        }
+        return c.cross(res1, rc1, py1, py2);
+    }
+
+    /**
+     * Returns how many times rectangle stripe cross path or the are intersect
+     */
+    public static int intersectPath(PathIterator p, double x, double y, double w, double h) {
+
+        int cross = 0;
+        int count;
+        double mx, my, cx, cy;
+        mx = my = cx = cy = 0.0;
+        double coords[] = new double[6];
+
+        double rx1 = x;
+        double ry1 = y;
+        double rx2 = x + w;
+        double ry2 = y + h;
+
+        while (!p.isDone()) {
+            count = 0;
+            switch (p.currentSegment(coords)) {
+            case PathIterator.SEG_MOVETO:
+                if (cx != mx || cy != my) {
+                    count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+                }
+                mx = cx = coords[0];
+                my = cy = coords[1];
+                break;
+            case PathIterator.SEG_LINETO:
+                count = intersectLine(cx, cy, cx = coords[0], cy = coords[1], rx1, ry1, rx2, ry2);
+                break;
+            case PathIterator.SEG_QUADTO:
+                count = intersectQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3], rx1, ry1, rx2, ry2);
+                break;
+            case PathIterator.SEG_CUBICTO:
+                count = intersectCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5], rx1, ry1, rx2, ry2);
+                break;
+            case PathIterator.SEG_CLOSE:
+                if (cy != my || cx != mx) {
+                    count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+                }
+                cx = mx;
+                cy = my;
+                break;
+            }
+            if (count == CROSSING) {
+                return CROSSING;
+            }
+            cross += count;
+            p.next();
+        }
+        if (cy != my) {
+            count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+            if (count == CROSSING) {
+                return CROSSING;
+            }
+            cross += count;
+        }
+        return cross;
+    }
+
+    /**
+     * Returns how many times rectangle stripe cross shape or the are intersect
+     */
+    public static int intersectShape(Shape s, double x, double y, double w, double h) {
+        if (!s.getBounds2D().intersects(x, y, w, h)) {
+            return 0;
+        }
+        return intersectPath(s.getPathIterator(null), x, y, w, h);
+    }
+
+    /**
+     * Returns true if cross count correspond inside location for non zero path rule
+     */
+    public static boolean isInsideNonZero(int cross) {
+        return cross != 0;
+    }
+
+    /**
+     * Returns true if cross count correspond inside location for even-odd path rule
+     */
+    public static boolean isInsideEvenOdd(int cross) {
+        return (cross & 1) != 0;
+    }
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/GLVolatileImage.java b/awt/org/apache/harmony/awt/gl/GLVolatileImage.java
new file mode 100644
index 0000000..177be23
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/GLVolatileImage.java
@@ -0,0 +1,30 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.image.*;
+
+import org.apache.harmony.awt.gl.Surface;
+
+public abstract class GLVolatileImage extends VolatileImage {
+
+    public abstract Surface getImageSurface();
+}
diff --git a/awt/org/apache/harmony/awt/gl/ICompositeContext.java b/awt/org/apache/harmony/awt/gl/ICompositeContext.java
new file mode 100644
index 0000000..fc5631f
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/ICompositeContext.java
@@ -0,0 +1,90 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.gl.render.NativeImageBlitter;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * This class represent implementation of the CompositeContext interface
+ */
+public class ICompositeContext implements CompositeContext {
+    Composite composite;
+    ColorModel srcCM, dstCM;
+    ImageSurface srcSurf, dstSurf;
+
+    public ICompositeContext(Composite comp, ColorModel src, ColorModel dst){
+        composite = comp;
+        srcCM = src;
+        dstCM = dst;
+    }
+
+    public void dispose() {
+        srcSurf.dispose();
+        dstSurf.dispose();
+    }
+
+    public void compose(Raster srcIn, Raster dstIn, WritableRaster dstOut) {
+
+        if(!srcCM.isCompatibleRaster(srcIn)) {
+            // awt.48=The srcIn raster is incompatible with src ColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.48")); //$NON-NLS-1$
+        }
+
+        if(!dstCM.isCompatibleRaster(dstIn)) {
+            // awt.49=The dstIn raster is incompatible with dst ColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.49")); //$NON-NLS-1$
+        }
+
+        if(dstIn != dstOut){
+            if(!dstCM.isCompatibleRaster(dstOut)) {
+                // awt.4A=The dstOut raster is incompatible with dst ColorModel
+                throw new IllegalArgumentException(Messages.getString("awt.4A")); //$NON-NLS-1$
+            }
+            dstOut.setDataElements(0, 0, dstIn);
+        }
+        WritableRaster src;
+        if(srcIn instanceof WritableRaster){
+            src = (WritableRaster) srcIn;
+        }else{
+            src = srcIn.createCompatibleWritableRaster();
+            src.setDataElements(0, 0, srcIn);
+        }
+        srcSurf = new ImageSurface(srcCM, src);
+        dstSurf = new ImageSurface(dstCM, dstOut);
+
+        int w = Math.min(srcIn.getWidth(), dstOut.getWidth());
+        int h = Math.min(srcIn.getHeight(), dstOut.getHeight());
+
+        NativeImageBlitter.getInstance().blit(0, 0, srcSurf, 0, 0, dstSurf,
+                w, h, composite, null, null);
+
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/ImageSurface.java b/awt/org/apache/harmony/awt/gl/ImageSurface.java
new file mode 100644
index 0000000..6368dd8
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/ImageSurface.java
@@ -0,0 +1,323 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 10.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.BandedSampleModel;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DirectColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.MultiPixelPackedSampleModel;
+import java.awt.image.PixelInterleavedSampleModel;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+import org.apache.harmony.awt.gl.image.DataBufferListener;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * This class represent Surface for different types of Images (BufferedImage, 
+ * OffscreenImage and so on) 
+ */
+public class ImageSurface extends Surface implements DataBufferListener {
+
+    boolean nativeDrawable = true;
+    int surfaceType;
+    int csType;
+    ColorModel cm;
+    WritableRaster raster;
+    Object data;
+    
+    boolean needToRefresh = true;
+    boolean dataTaken = false;
+    
+    private long cachedDataPtr;       // Pointer for cached Image Data
+    private boolean alphaPre;         // Cached Image Data alpha premultiplied 
+
+    public ImageSurface(ColorModel cm, WritableRaster raster){
+        this(cm, raster, Surface.getType(cm, raster));
+    }
+
+    public ImageSurface(ColorModel cm, WritableRaster raster, int type){
+        if (!cm.isCompatibleRaster(raster)) {
+            // awt.4D=The raster is incompatible with this ColorModel
+            throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
+        }
+        this.cm = cm;
+        this.raster = raster;
+        surfaceType = type;
+
+        data = AwtImageBackdoorAccessor.getInstance().
+        getData(raster.getDataBuffer());
+        ColorSpace cs = cm.getColorSpace();
+        transparency = cm.getTransparency();
+        width = raster.getWidth();
+        height = raster.getHeight();
+
+        // For the moment we can build natively only images which have 
+        // sRGB, Linear_RGB, Linear_Gray Color Space and type different
+        // from BufferedImage.TYPE_CUSTOM
+        if(cs == LUTColorConverter.sRGB_CS){
+            csType = sRGB_CS;
+        }else if(cs == LUTColorConverter.LINEAR_RGB_CS){
+            csType = Linear_RGB_CS;
+        }else if(cs == LUTColorConverter.LINEAR_GRAY_CS){
+            csType = Linear_Gray_CS;
+        }else{
+            csType = Custom_CS;
+            nativeDrawable = false;
+        }
+
+        if(type == BufferedImage.TYPE_CUSTOM){
+            nativeDrawable = false;
+        }
+    }
+
+    @Override
+    public ColorModel getColorModel() {
+        return cm;
+    }
+
+    @Override
+    public WritableRaster getRaster() {
+        return raster;
+    }
+
+    @Override
+    public long getSurfaceDataPtr() {
+        if(surfaceDataPtr == 0L && nativeDrawable){
+            createSufaceStructure();
+        }
+        return surfaceDataPtr;
+    }
+
+    @Override
+    public Object getData(){
+        return data;
+    }
+
+    @Override
+    public boolean isNativeDrawable(){
+        return nativeDrawable;
+    }
+
+    @Override
+    public int getSurfaceType() {
+        return surfaceType;
+    }
+
+    /**
+     * Creates native Surface structure which used for native blitting
+     */
+    private void createSufaceStructure(){
+        int cmType = 0;
+        int numComponents = cm.getNumComponents();
+        boolean hasAlpha = cm.hasAlpha();
+        boolean isAlphaPre = cm.isAlphaPremultiplied();
+        int transparency = cm.getTransparency();
+        int bits[] = cm.getComponentSize();
+        int pixelStride = cm.getPixelSize();
+        int masks[] = null;
+        int colorMap[] = null;
+        int colorMapSize = 0;
+        int transpPixel = -1;
+        boolean isGrayPallete = false;
+        SampleModel sm = raster.getSampleModel();
+        int smType = 0;
+        int dataType = sm.getDataType();
+        int scanlineStride = 0;
+        int bankIndeces[] = null;
+        int bandOffsets[] = null;
+        int offset = raster.getDataBuffer().getOffset();
+
+        if(cm instanceof DirectColorModel){
+            cmType = DCM;
+            DirectColorModel dcm = (DirectColorModel) cm;
+            masks = dcm.getMasks();
+            smType = SPPSM;
+            SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+            scanlineStride = sppsm.getScanlineStride();
+
+        }else if(cm instanceof IndexColorModel){
+            cmType = ICM;
+            IndexColorModel icm = (IndexColorModel) cm;
+            colorMapSize = icm.getMapSize();
+            colorMap = new int[colorMapSize];
+            icm.getRGBs(colorMap);
+            transpPixel = icm.getTransparentPixel();
+            isGrayPallete = Surface.isGrayPallete(icm);
+
+            if(sm instanceof MultiPixelPackedSampleModel){
+                smType = MPPSM;
+                MultiPixelPackedSampleModel mppsm =
+                    (MultiPixelPackedSampleModel) sm;
+                scanlineStride = mppsm.getScanlineStride();
+            }else if(sm instanceof ComponentSampleModel){
+                smType = CSM;
+                ComponentSampleModel csm =
+                    (ComponentSampleModel) sm;
+                scanlineStride = csm.getScanlineStride();
+            }else{
+                // awt.4D=The raster is incompatible with this ColorModel
+                throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
+            }
+
+        }else if(cm instanceof ComponentColorModel){
+            cmType = CCM;
+            if(sm instanceof ComponentSampleModel){
+                ComponentSampleModel csm = (ComponentSampleModel) sm;
+                scanlineStride = csm.getScanlineStride();
+                bankIndeces = csm.getBankIndices();
+                bandOffsets = csm.getBandOffsets();
+                if(sm instanceof PixelInterleavedSampleModel){
+                    smType = PISM;
+                }else if(sm instanceof BandedSampleModel){
+                    smType = BSM;
+                }else{
+                    smType = CSM;
+                }
+            }else{
+                // awt.4D=The raster is incompatible with this ColorModel
+                throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
+            }
+
+        }else{
+            surfaceDataPtr = 0L;
+            return;
+        }
+        surfaceDataPtr = createSurfStruct(surfaceType, width, height, cmType, csType, smType, dataType,
+                numComponents, pixelStride, scanlineStride, bits, masks, colorMapSize,
+                colorMap, transpPixel, isGrayPallete, bankIndeces, bandOffsets,
+                offset, hasAlpha, isAlphaPre, transparency);
+    }
+
+    @Override
+    public void dispose() {
+        if(surfaceDataPtr != 0L){
+            dispose(surfaceDataPtr);
+            surfaceDataPtr = 0L;
+        }
+    }
+    
+    public long getCachedData(boolean alphaPre){
+        if(nativeDrawable){
+            if(cachedDataPtr == 0L || needToRefresh || this.alphaPre != alphaPre){
+                cachedDataPtr = updateCache(getSurfaceDataPtr(), data, alphaPre);
+                this.alphaPre = alphaPre;
+                validate(); 
+            }
+        }
+        return cachedDataPtr;
+    }
+
+    private native long createSurfStruct(int surfaceType, int width, int height, 
+            int cmType, int csType, int smType, int dataType,
+            int numComponents, int pixelStride, int scanlineStride,
+            int bits[], int masks[], int colorMapSize, int colorMap[],
+            int transpPixel, boolean isGrayPalette, int bankIndeces[], 
+            int bandOffsets[], int offset, boolean hasAlpha, boolean isAlphaPre,
+            int transparency);
+
+    private native void dispose(long structPtr);
+
+    private native void setImageSize(long structPtr, int width, int height);
+
+    private native long updateCache(long structPtr, Object data, boolean alphaPre);
+    
+    /**
+     * Supposes that new raster is compatible with an old one
+     * @param r
+     */
+    public void setRaster(WritableRaster r) {
+        raster = r;
+        data = AwtImageBackdoorAccessor.getInstance().getData(r.getDataBuffer());
+        if (surfaceDataPtr != 0) {
+            setImageSize(surfaceDataPtr, r.getWidth(), r.getHeight());
+        }
+        this.width = r.getWidth();
+        this.height = r.getHeight();
+    }
+
+    @Override
+    public long lock() {
+        // TODO
+        return 0;
+    }
+
+    @Override
+    public void unlock() {
+        //TODO
+    }
+
+    @Override
+    public Surface getImageSurface() {
+        return this;
+    }
+
+    public void dataChanged() {
+        needToRefresh = true;
+        clearValidCaches();
+    }
+
+    public void dataTaken() {
+        dataTaken = true;
+        needToRefresh = true;
+        clearValidCaches();
+    }
+    
+    public void dataReleased(){
+        dataTaken = false;
+        needToRefresh = true;
+        clearValidCaches();
+    }
+    
+    @Override
+    public void invalidate(){
+        needToRefresh = true;
+        clearValidCaches();
+    }
+    
+    @Override
+    public void validate(){
+        if(!needToRefresh) {
+            return;
+        }
+        if(!dataTaken){
+            needToRefresh = false;
+            AwtImageBackdoorAccessor ba = AwtImageBackdoorAccessor.getInstance();
+            ba.validate(raster.getDataBuffer());
+        }
+        
+    }
+    
+    @Override
+    public boolean invalidated(){
+        return needToRefresh;
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/MultiRectArea.java b/awt/org/apache/harmony/awt/gl/MultiRectArea.java
new file mode 100644
index 0000000..c4267f3
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/MultiRectArea.java
@@ -0,0 +1,836 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class MultiRectArea implements Shape {
+
+    /**
+     * If CHECK is true validation check active
+     */
+    private static final boolean CHECK = false;
+
+    boolean sorted = true;
+    
+    /**
+     * Rectangle buffer
+     */
+    public int[] rect;
+    
+    /**
+     * Bounding box
+     */
+    Rectangle bounds;
+    
+    /**
+     * Result rectangle array
+     */
+    Rectangle[] rectangles;
+
+    /**
+     * LineCash provides creating MultiRectArea line by line. Used in JavaShapeRasterizer.
+     */
+    public static class LineCash extends MultiRectArea {
+
+        int lineY;
+        int bottomCount;
+        int[] bottom;
+
+        public LineCash(int size) {
+            super();
+            bottom = new int[size];
+            bottomCount = 0;
+        }
+
+        public void setLine(int y) {
+            lineY = y;
+        }
+
+        public void skipLine() {
+            lineY++;
+            bottomCount = 0;
+        }
+
+        public void addLine(int[] points, int pointCount) {
+            int bottomIndex = 0;
+            int pointIndex = 0;
+            int rectIndex = 0;
+            int pointX1 = 0;
+            int pointX2 = 0;
+            int bottomX1 = 0;
+            int bottomX2 = 0;
+            boolean appendRect = false;
+            boolean deleteRect = false;
+            int lastCount = bottomCount;
+
+            while (bottomIndex < lastCount || pointIndex < pointCount) {
+
+                appendRect = false;
+                deleteRect = false;
+
+                if (bottomIndex < lastCount) {
+                    rectIndex = bottom[bottomIndex];
+                    bottomX1 = rect[rectIndex];
+                    bottomX2 = rect[rectIndex + 2];
+                } else {
+                    appendRect = true;
+                }
+
+                if (pointIndex < pointCount) {
+                    pointX1 = points[pointIndex];
+                    pointX2 = points[pointIndex + 1];
+                } else {
+                    deleteRect = true;
+                }
+
+                if (!deleteRect && !appendRect) {
+                    if (pointX1 == bottomX1 && pointX2 == bottomX2) {
+                        rect[rectIndex + 3] = rect[rectIndex + 3] + 1;
+                        pointIndex += 2;
+                        bottomIndex++;
+                        continue;
+                    }
+                    deleteRect = pointX2 >= bottomX1;
+                    appendRect = pointX1 <= bottomX2;
+                }
+
+                if (deleteRect) {
+                    if (bottomIndex < bottomCount - 1) {
+                        System.arraycopy(bottom, bottomIndex + 1, bottom, bottomIndex, bottomCount - bottomIndex - 1);
+                        rectIndex -= 4;
+                    }
+                    bottomCount--;
+                    lastCount--;
+                }
+
+                if (appendRect) {
+                    int i = rect[0];
+                    bottom[bottomCount++] = i;
+                    rect = MultiRectAreaOp.checkBufSize(rect, 4);
+                    rect[i++] = pointX1;
+                    rect[i++] = lineY;
+                    rect[i++] = pointX2;
+                    rect[i++] = lineY;
+                    pointIndex += 2;
+                }
+            }
+            lineY++;
+
+            invalidate();
+        }
+
+    }
+
+    /**
+     * RectCash provides simple creating MultiRectArea
+     */
+    public static class RectCash extends MultiRectArea {
+
+        int[] cash;
+
+        public RectCash() {
+            super();
+            cash = new int[MultiRectAreaOp.RECT_CAPACITY];
+            cash[0] = 1;
+        }
+
+        public void addRectCashed(int x1, int y1, int x2, int y2) {
+            addRect(x1, y1, x2, y2);
+            invalidate();
+/*
+            // Exclude from cash unnecessary rectangles
+            int i = 1;
+            while(i < cash[0]) {
+                if (rect[cash[i] + 3] >= y1 - 1) {
+                    if (i > 1) {
+                        System.arraycopy(cash, i, cash, 1, cash[0] - i);
+                    }
+                    break;
+                }
+                i++;
+            }
+            cash[0] -= i - 1;
+
+            // Find in cash rectangle to concatinate
+            i = 1;
+            while(i < cash[0]) {
+                int index = cash[i];
+                if (rect[index + 3] != y1 - 1) {
+                    break;
+                }
+                if (rect[index] == x1 && rect[index + 2] == x2) {
+                    rect[index + 3] += y2 - y1 + 1;
+
+                    int pos = i + 1;
+                    while(pos < cash[0]) {
+                        if (rect[index + 3] <= rect[cash[i] + 3]) {
+                            System.arraycopy(cash, i + 1, cash, i, pos - i);
+                            break;
+                        }
+                        i++;
+                    }
+                    cash[pos - 1] = index;
+
+                    invalidate();
+                    return;
+                }
+                i++;
+            }
+
+            // Add rectangle to buffer
+            int index = rect[0];
+            rect = MultiRectAreaOp.checkBufSize(rect, 4);
+            rect[index + 0] = x1;
+            rect[index + 1] = y1;
+            rect[index + 2] = x2;
+            rect[index + 3] = y2;
+
+            // Add rectangle to cash
+            int length = cash[0];
+            cash = MultiRectAreaOp.checkBufSize(cash, 1);
+            while(i < length) {
+                if (y2 <= rect[cash[i] + 3]) {
+                    System.arraycopy(cash, i, cash, i + 1, length - i);
+                    break;
+                }
+                i++;
+            }
+            cash[i] = index;
+            invalidate();
+*/
+        }
+
+        public void addRectCashed(int[] rect, int rectOff, int rectLength) {
+            for(int i = rectOff; i < rectOff + rectLength;) {
+                addRect(rect[i++], rect[i++], rect[i++], rect[i++]);
+//              addRectCashed(rect[i++], rect[i++], rect[i++], rect[i++]);
+            }
+        }
+
+    }
+
+    /**
+     * MultiRectArea path iterator
+     */
+    class Iterator implements PathIterator {
+
+        int type;
+        int index;
+        int pos;
+
+        int[] rect;
+        AffineTransform t;
+
+        Iterator(MultiRectArea mra, AffineTransform t) {
+            rect = new int[mra.rect[0] - 1];
+            System.arraycopy(mra.rect, 1, rect, 0, rect.length);
+            this.t = t;
+        }
+
+        public int getWindingRule() {
+            return WIND_NON_ZERO;
+        }
+
+        public boolean isDone() {
+            return pos >= rect.length;
+        }
+
+        public void next() {
+            if (index == 4) {
+                pos += 4;
+            }
+            index = (index + 1) % 5;
+        }
+
+        public int currentSegment(double[] coords) {
+            if (isDone()) {
+                // awt.4B=Iiterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            int type = 0;
+
+            switch(index) {
+            case 0 :
+                type = SEG_MOVETO;
+                coords[0] = rect[pos + 0];
+                coords[1] = rect[pos + 1];
+                break;
+            case 1:
+                type = SEG_LINETO;
+                coords[0] = rect[pos + 2];
+                coords[1] = rect[pos + 1];
+                break;
+            case 2:
+                type = SEG_LINETO;
+                coords[0] = rect[pos + 2];
+                coords[1] = rect[pos + 3];
+                break;
+            case 3:
+                type = SEG_LINETO;
+                coords[0] = rect[pos + 0];
+                coords[1] = rect[pos + 3];
+                break;
+            case 4:
+                type = SEG_CLOSE;
+                break;
+            }
+
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, 1);
+            }
+            return type;
+        }
+
+        public int currentSegment(float[] coords) {
+            if (isDone()) {
+                // awt.4B=Iiterator out of bounds
+                throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+            }
+            int type = 0;
+
+            switch(index) {
+            case 0 :
+                type = SEG_MOVETO;
+                coords[0] = rect[pos + 0];
+                coords[1] = rect[pos + 1];
+                break;
+            case 1:
+                type = SEG_LINETO;
+                coords[0] = rect[pos + 2];
+                coords[1] = rect[pos + 1];
+                break;
+            case 2:
+                type = SEG_LINETO;
+                coords[0] = rect[pos + 2];
+                coords[1] = rect[pos + 3];
+                break;
+            case 3:
+                type = SEG_LINETO;
+                coords[0] = rect[pos + 0];
+                coords[1] = rect[pos + 3];
+                break;
+            case 4:
+                type = SEG_CLOSE;
+                break;
+            }
+
+            if (t != null) {
+                t.transform(coords, 0, coords, 0, 1);
+            }
+            return type;
+        }
+
+    }
+
+    /**
+     * Constructs a new empty MultiRectArea 
+     */
+    public MultiRectArea() {
+        rect = MultiRectAreaOp.createBuf(0);
+    }
+
+    public MultiRectArea(boolean sorted) {
+       this();
+       this.sorted = sorted;
+    }
+    
+    /**
+     * Constructs a new MultiRectArea as a copy of another one 
+     */
+    public MultiRectArea(MultiRectArea mra) {
+        if (mra == null) {
+            rect = MultiRectAreaOp.createBuf(0);
+        } else {
+            rect = new int[mra.rect.length];
+            System.arraycopy(mra.rect, 0, rect, 0, mra.rect.length);
+            check(this, "MultiRectArea(MRA)"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Constructs a new MultiRectArea consists of single rectangle 
+     */
+    public MultiRectArea(Rectangle r) {
+        rect = MultiRectAreaOp.createBuf(0);
+        if (r != null && !r.isEmpty()) {
+            rect[0] = 5;
+            rect[1] = r.x;
+            rect[2] = r.y;
+            rect[3] = r.x + r.width - 1;
+            rect[4] = r.y + r.height - 1;
+        }
+        check(this, "MultiRectArea(Rectangle)"); //$NON-NLS-1$
+    }
+
+    /**
+     * Constructs a new MultiRectArea consists of single rectangle
+     */
+    public MultiRectArea(int x0, int y0, int x1, int y1) {
+        rect = MultiRectAreaOp.createBuf(0);
+        if (x1 >= x0 && y1 >= y0) {
+            rect[0] = 5;
+            rect[1] = x0;
+            rect[2] = y0;
+            rect[3] = x1;
+            rect[4] = y1;
+        }
+        check(this, "MultiRectArea(Rectangle)"); //$NON-NLS-1$
+    }
+
+    /**
+     * Constructs a new MultiRectArea and append rectangle from buffer
+     */
+    public MultiRectArea(Rectangle[] buf) {
+        this();
+        for (Rectangle element : buf) {
+            add(element);
+        }
+    }
+
+    /**
+     * Constructs a new MultiRectArea and append rectangle from array
+     */
+    public MultiRectArea(ArrayList<Rectangle> buf) {
+        this();
+        for(int i = 0; i < buf.size(); i++) {
+            add(buf.get(i));
+        }
+    }
+
+    /**
+     * Sort rectangle buffer
+     */
+    void resort() {
+        int[] buf = new int[4];
+        for(int i = 1; i < rect[0]; i += 4) {
+            int k = i;
+            int x1 = rect[k];
+            int y1 = rect[k + 1];
+            for(int j = i + 4; j < rect[0]; j += 4) {
+                int x2 = rect[j];
+                int y2 = rect[j + 1];
+                if (y1 > y2 || (y1 == y2 && x1 > x2)) {
+                    x1 = x2;
+                    y1 = y2;
+                    k = j;
+                }
+            }
+            if (k != i) {
+                System.arraycopy(rect, i, buf, 0, 4);
+                System.arraycopy(rect, k, rect, i, 4);
+                System.arraycopy(buf, 0, rect, k, 4);
+            }
+        }
+        invalidate();
+    }
+
+    /**
+     * Tests equals with another object
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof MultiRectArea) {
+            MultiRectArea mra = (MultiRectArea) obj;
+            for(int i = 0; i < rect[0]; i++) {
+                if (rect[i] != mra.rect[i]) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Checks validation of MultiRectArea object
+     */
+    static MultiRectArea check(MultiRectArea mra, String msg) {
+        if (CHECK && mra != null) {
+            if (MultiRectArea.checkValidation(mra.getRectangles(), mra.sorted) != -1) {
+                // awt.4C=Invalid MultiRectArea in method {0}
+                new RuntimeException(Messages.getString("awt.4C", msg)); //$NON-NLS-1$
+            }
+        }
+        return mra;
+    }
+
+    /**
+     * Checks validation of MultiRectArea object
+     */
+    public static int checkValidation(Rectangle[] r, boolean sorted) {
+
+        // Check width and height
+        for(int i = 0; i < r.length; i++) {
+            if (r[i].width <= 0 || r[i].height <= 0) {
+                return i;
+            }
+        }
+
+        // Check order
+        if (sorted) {
+            for(int i = 1; i < r.length; i++) {
+                if (r[i - 1].y > r[i].y) {
+                    return i;
+                }
+                if (r[i - 1].y == r[i].y) {
+                    if (r[i - 1].x > r[i].x) {
+                        return i;
+                    }
+                }
+            }
+        }
+
+        // Check override
+        for(int i = 0; i < r.length; i++) {
+            for(int j = i + 1; j < r.length; j++) {
+                if (r[i].intersects(r[j])) {
+                    return i;
+                }
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Assigns rectangle from another buffer
+     */
+    protected void setRect(int[] buf, boolean copy) {
+        if (copy) {
+            rect = new int[buf.length];
+            System.arraycopy(buf, 0, rect, 0, buf.length);
+        } else {
+            rect = buf;
+        }
+        invalidate();
+    }
+
+    /**
+     * Union with another MultiRectArea object
+     */
+    public void add(MultiRectArea mra) {
+        setRect(union(this, mra).rect, false);
+        invalidate();
+    }
+
+    /**
+     * Intersect with another MultiRectArea object
+     */
+    public void intersect(MultiRectArea mra) {
+        setRect(intersect(this, mra).rect, false);
+        invalidate();
+    }
+
+    /**
+     * Subtract another MultiRectArea object
+     */
+    public void substract(MultiRectArea mra) {
+        setRect(subtract(this, mra).rect, false);
+        invalidate();
+    }
+
+    /**
+     * Union with Rectangle object
+     */
+    public void add(Rectangle rect) {
+        setRect(union(this, new MultiRectArea(rect)).rect, false);
+        invalidate();
+    }
+
+    /**
+     * Intersect with Rectangle object
+     */
+    public void intersect(Rectangle rect) {
+        setRect(intersect(this, new MultiRectArea(rect)).rect, false);
+        invalidate();
+    }
+
+    /**
+     * Subtract rectangle object
+     */
+    public void substract(Rectangle rect) {
+        setRect(subtract(this, new MultiRectArea(rect)).rect, false);
+    }
+
+    /**
+     * Union two MutliRectareArea objects
+     */
+    public static MultiRectArea intersect(MultiRectArea src1, MultiRectArea src2) {
+        MultiRectArea res = check(MultiRectAreaOp.Intersection.getResult(src1, src2), "intersect(MRA,MRA)"); //$NON-NLS-1$
+        return res;
+    }
+
+    /**
+     * Intersect two MultiRectArea objects
+     */
+    public static MultiRectArea union(MultiRectArea src1, MultiRectArea src2) {
+        MultiRectArea res = check(new MultiRectAreaOp.Union().getResult(src1, src2), "union(MRA,MRA)"); //$NON-NLS-1$
+        return res;
+    }
+
+    /**
+     * Subtract two MultiRectArea objects
+     */
+    public static MultiRectArea subtract(MultiRectArea src1, MultiRectArea src2) {
+        MultiRectArea res = check(MultiRectAreaOp.Subtraction.getResult(src1, src2), "subtract(MRA,MRA)"); //$NON-NLS-1$
+        return res;
+    }
+
+    /**
+     * Print MultiRectArea object to output stream
+     */
+    public static void print(MultiRectArea mra, String msg) {
+        if (mra == null) {
+            System.out.println(msg + "=null"); //$NON-NLS-1$
+        } else {
+            Rectangle[] rects = mra.getRectangles();
+            System.out.println(msg + "(" + rects.length + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+            for (Rectangle element : rects) {
+                System.out.println(
+                        element.x + "," + //$NON-NLS-1$
+                        element.y + "," + //$NON-NLS-1$
+                        (element.x + element.width - 1) + "," + //$NON-NLS-1$
+                        (element.y + element.height - 1));
+            }
+        }
+    }
+
+    /**
+     * Translate MultiRectArea object by (x, y)
+     */
+    public void translate(int x, int y) {
+        for(int i = 1; i < rect[0];) {
+            rect[i++] += x;
+            rect[i++] += y;
+            rect[i++] += x;
+            rect[i++] += y;
+        }
+
+        if (bounds != null && !bounds.isEmpty()) {
+            bounds.translate(x, y);
+        }
+
+        if (rectangles != null) {
+            for (Rectangle element : rectangles) {
+                element.translate(x, y);
+            }
+        }
+    }
+
+    /**
+     * Add rectangle to the buffer without any checking
+     */
+    public void addRect(int x1, int y1, int x2, int y2) {
+        int i = rect[0];
+        rect = MultiRectAreaOp.checkBufSize(rect, 4);
+        rect[i++] = x1;
+        rect[i++] = y1;
+        rect[i++] = x2;
+        rect[i++] = y2;
+    }
+
+    /**
+     * Tests is MultiRectArea empty 
+     */
+    public boolean isEmpty() {
+        return rect[0] == 1;
+    }
+
+    void invalidate() {
+        bounds = null;
+        rectangles = null;
+    }
+
+    /**
+     * Returns bounds of MultiRectArea object
+     */
+    public Rectangle getBounds() {
+        if (bounds != null) {
+            return bounds;
+        }
+
+        if (isEmpty()) {
+            return bounds = new Rectangle();
+        }
+
+        int x1 = rect[1];
+        int y1 = rect[2];
+        int x2 = rect[3];
+        int y2 = rect[4];
+        
+        for(int i = 5; i < rect[0]; i += 4) {
+            int rx1 = rect[i + 0];
+            int ry1 = rect[i + 1];
+            int rx2 = rect[i + 2];
+            int ry2 = rect[i + 3];
+            if (rx1 < x1) {
+                x1 = rx1;
+            }
+            if (rx2 > x2) {
+                x2 = rx2;
+            }
+            if (ry1 < y1) {
+                y1 = ry1;
+            }
+            if (ry2 > y2) {
+                y2 = ry2;
+            }
+        }
+        
+        return bounds = new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+    }
+
+    /**
+     * Recturn rectangle count in the buffer
+     */
+    public int getRectCount() {
+        return (rect[0] - 1) / 4;
+    }
+
+    /**
+     * Returns Rectangle array 
+     */
+    public Rectangle[] getRectangles() {
+        if (rectangles != null) {
+            return rectangles;
+        }
+
+        rectangles = new Rectangle[(rect[0] - 1) / 4];
+        int j = 0;
+        for(int i = 1; i < rect[0]; i += 4) {
+            rectangles[j++] = new Rectangle(
+                    rect[i],
+                    rect[i + 1],
+                    rect[i + 2] - rect[i] + 1,
+                    rect[i + 3] - rect[i + 1] + 1);
+        }
+        return rectangles;
+    }
+
+    /**
+     * Returns Bounds2D
+     */
+    public Rectangle2D getBounds2D() {
+        return getBounds();
+    }
+
+    /**
+     * Tests does point lie inside MultiRectArea object
+     */
+    public boolean contains(double x, double y) {
+        for(int i = 1; i < rect[0]; i+= 4) {
+            if (rect[i] <= x && x <= rect[i + 2] && rect[i + 1] <= y && y <= rect[i + 3]) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Tests does Point2D lie inside MultiRectArea object
+     */
+    public boolean contains(Point2D p) {
+        return contains(p.getX(), p.getY());
+    }
+
+    /**
+     * Tests does rectangle lie inside MultiRectArea object
+     */
+    public boolean contains(double x, double y, double w, double h) {
+        throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+    }
+
+    /**
+     * Tests does Rectangle2D lie inside MultiRectArea object
+     */
+    public boolean contains(Rectangle2D r) {
+        throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+    }
+
+    /**
+     * Tests does rectangle intersect MultiRectArea object
+     */
+    public boolean intersects(double x, double y, double w, double h) {
+        Rectangle r = new Rectangle();
+        r.setRect(x, y, w, h);
+        return intersects(r);
+    }
+
+    /**
+     * Tests does Rectangle2D intersect MultiRectArea object
+     */
+    public boolean intersects(Rectangle2D r) {
+        if (r == null || r.isEmpty()) {
+            return false;
+        }
+        for(int i = 1; i < rect[0]; i+= 4) {
+            if (r.intersects(rect[i], rect[i+1], rect[i + 2]-rect[i]+1, rect[i + 3]-rect[i + 1]+1)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns path iterator
+     */
+    public PathIterator getPathIterator(AffineTransform t, double flatness) {
+        return new Iterator(this, t);
+    }
+
+    /**
+     * Returns path iterator
+     */
+    public PathIterator getPathIterator(AffineTransform t) {
+        return new Iterator(this, t);
+    }
+
+    /**
+     * Returns MultiRectArea object converted to string 
+     */
+    @Override
+    public String toString() {
+        int cnt = getRectCount();
+        StringBuffer sb = new StringBuffer((cnt << 5) + 128);
+        sb.append(getClass().getName()).append(" ["); //$NON-NLS-1$
+        for(int i = 1; i < rect[0]; i += 4) {
+            sb.append(i > 1 ? ", [" : "[").append(rect[i]).append(", ").append(rect[i + 1]). //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+            append(", ").append(rect[i + 2] - rect[i] + 1).append(", "). //$NON-NLS-1$ //$NON-NLS-2$
+            append(rect[i + 3] - rect[i + 1] + 1).append("]"); //$NON-NLS-1$
+        }
+        return sb.append("]").toString(); //$NON-NLS-1$
+    }
+
+}
+
diff --git a/awt/org/apache/harmony/awt/gl/MultiRectAreaOp.java b/awt/org/apache/harmony/awt/gl/MultiRectAreaOp.java
new file mode 100644
index 0000000..c75e203
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/MultiRectAreaOp.java
@@ -0,0 +1,837 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Rectangle;
+
+public class MultiRectAreaOp {
+
+    /**
+     * Rectangle buffer capacity
+     */
+    public static final int RECT_CAPACITY = 16;
+    
+    /**
+     * If number of rectangle in MultiRectArea object less than MAX_SIMPLE simple algorithm applies 
+     */
+    private static final int MAX_SIMPLE = 8;
+
+    /**
+     * Create buffer
+     */
+    public static int[] createBuf(int capacity) {
+        if (capacity == 0) {
+            capacity = RECT_CAPACITY;
+        }
+        int[] buf = new int[capacity];
+        buf[0] = 1;
+        return buf;
+    }
+
+    /**
+     * Checks buffer size and reallocate if necessary  
+     */
+    public static int[] checkBufSize(int[] buf, int capacity) {
+        if (buf[0] + capacity >= buf.length) {
+            int length = buf[0] + (capacity > RECT_CAPACITY ? capacity : RECT_CAPACITY);
+            int[] tmp = new int[length];
+            System.arraycopy(buf, 0, tmp, 0, buf[0]);
+            buf = tmp;
+        }
+        buf[0] += capacity;
+        return buf;
+    }
+
+    /**
+     * Region class provides basic functionlity for MultiRectArea objects to make logical operations 
+     */
+    static class Region {
+
+        int[] region;
+        int[] active;
+        int[] bottom;
+        int index;
+
+        public Region(int[] region) {
+            this.region = region;
+            active = new int[RECT_CAPACITY];
+            bottom = new int[RECT_CAPACITY];
+            active[0] = 1;
+            bottom[0] = 1;
+            index = 1;
+        }
+
+        void addActive(int index) {
+            int length = active[0];
+            active = checkBufSize(active, 4);
+            int i = 1;
+
+            while(i < length) {
+                if (region[index] < active[i]) {
+                    // Insert
+                    System.arraycopy(active, i, active, i + 4, length - i);
+                    length = i;
+                    break;
+                }
+                i += 4;
+            }
+            System.arraycopy(region, index, active, length, 4);
+
+        }
+
+        void findActive(int top, int bottom) {
+            while(index < region[0]) {
+                if (region[index + 1] > bottom) { // y1 > bottom
+                    return;
+                }
+                if (region[index + 3] >= top) { // y2 >= top
+                    addActive(index);
+                }
+                index += 4;
+            }
+        }
+
+        void deleteActive(int bottom) {
+            int length = active[0];
+            for(int i = 1; i < length;) {
+                if (active[i + 3] == bottom) {
+                    length -= 4;
+                    if (i < length) {
+                        System.arraycopy(active, i + 4, active, i, length - i);
+                    }
+                } else {
+                     i += 4;
+                }
+            }
+            active[0] = length;
+        }
+
+        void deleteActive() {
+            int length = active[0];
+            for(int i = length - 4; i > 0; i -= 4) {
+                if (active[i + 1] > active[i + 3]) {
+                    length -= 4;
+                    if (i < length) {
+                        System.arraycopy(active, i + 4, active, i, length - i);
+                    }
+                }
+            }
+            active[0] = length;
+        }
+
+        void createLevel(int[] level) {
+            int levelCount = 1;
+            int topIndex = 1;
+            int i = 1;
+            while(i < region[0]) {
+
+                int top = region[i + 1];
+                int bottom = region[i + 3] + 1;
+                int j = topIndex;
+
+                addTop: {
+                    while(j < levelCount) {
+                        if (level[j] == top) {
+                            break addTop;
+                        }
+                        if (level[j] > top) {
+                            System.arraycopy(level, j, level, j + 1, levelCount - j);
+                            break;
+                        }
+                        j++;
+                    }
+
+                    level[j] = top;
+                    levelCount++;
+                    topIndex = j;
+                }
+
+                addBottom: {
+                    while(j < levelCount) {
+                        if (level[j] == bottom) {
+                            break addBottom;
+                        }
+                        if (level[j] > bottom) {
+                            System.arraycopy(level, j, level, j + 1, levelCount - j);
+                            break;
+                        }
+                        j++;
+                    };
+
+                    level[j] = bottom;
+                    levelCount++;
+                }
+
+                i += 4;
+            }
+            level[0] = levelCount;
+        }
+
+        static void sortOrdered(int[] src1, int[] src2, int[] dst) {
+            int length1 = src1[0];
+            int length2 = src2[0];
+            int count = 1;
+            int i1 = 1;
+            int i2 = 1;
+            int v1 = src1[1];
+            int v2 = src2[1];
+            while(true) {
+
+                LEFT: {
+                    while(i1 < length1) {
+                        v1 = src1[i1];
+                        if (v1 >= v2) {
+                            break LEFT;
+                        }
+                        dst[count++] = v1;
+                        i1++;
+                    }
+                    while(i2 < length2) {
+                        dst[count++] = src2[i2++];
+                    }
+                    dst[0] = count;
+                    return;
+                }
+
+                RIGHT: {
+                    while(i2 < length2) {
+                        v2 = src2[i2];
+                        if (v2 >= v1) {
+                            break RIGHT;
+                        }
+                        dst[count++] = v2;
+                        i2++;
+                    }
+                    while(i1 < length1) {
+                        dst[count++] = src1[i1++];
+                    }
+                    dst[0] = count;
+                    return;
+                }
+
+                if (v1 == v2) {
+                    dst[count++] = v1;
+                    i1++;
+                    i2++;
+                    if (i1 < length1) {
+                        v1 = src1[i1];
+                    }
+                    if (i2 < length2 - 1) {
+                        v2 = src2[i2];
+                    }
+                }
+            }
+            // UNREACHABLE
+        }
+
+    }
+
+    /**
+     * Intersection class provides intersection of two MultiRectAre aobjects
+     */
+    static class Intersection {
+
+        static void intersectRegions(int[] reg1, int[] reg2, MultiRectArea.RectCash dst, int height1, int height2) {
+
+            Region d1 = new Region(reg1);
+            Region d2 = new Region(reg2);
+
+            int[] level = new int[height1 + height2];
+            int[] level1 = new int[height1];
+            int[] level2 = new int[height2];
+            d1.createLevel(level1);
+            d2.createLevel(level2);
+            Region.sortOrdered(level1, level2, level);
+
+            int top;
+            int bottom = level[1] - 1;
+            for(int i = 2; i < level[0]; i++) {
+
+                top = bottom + 1;
+                bottom = level[i] - 1;
+
+                d1.findActive(top, bottom);
+                d2.findActive(top, bottom);
+
+                int i1 = 1;
+                int i2 = 1;
+
+                while(i1 < d1.active[0] && i2 < d2.active[0]) {
+
+                    int x11 = d1.active[i1];
+                    int x12 = d1.active[i1 + 2];
+                    int x21 = d2.active[i2];
+                    int x22 = d2.active[i2 + 2];
+
+                    if (x11 <= x21) {
+                        if (x12 >= x21) {
+                            if (x12 <= x22) {
+                                dst.addRectCashed(x21, top, x12, bottom);
+                                i1 += 4;
+                            } else {
+                                dst.addRectCashed(x21, top, x22, bottom);
+                                i2 += 4;
+                            }
+                        } else {
+                            i1 += 4;
+                        }
+                    } else {
+                        if (x22 >= x11) {
+                            if (x22 <= x12) {
+                                dst.addRectCashed(x11, top, x22, bottom);
+                                i2 += 4;
+                            } else {
+                                dst.addRectCashed(x11, top, x12, bottom);
+                                i1 += 4;
+                            }
+                        } else {
+                            i2 += 4;
+                        }
+                    }
+                }
+
+                d1.deleteActive(bottom);
+                d2.deleteActive(bottom);
+            }
+        }
+
+        static int[] simpleIntersect(MultiRectArea src1, MultiRectArea src2) {
+            int[] rect1 = src1.rect;
+            int[] rect2 = src2.rect;
+            int[] rect = createBuf(0);
+
+            int k = 1;
+            for(int i = 1; i < rect1[0];) {
+
+                int x11 = rect1[i++];
+                int y11 = rect1[i++];
+                int x12 = rect1[i++];
+                int y12 = rect1[i++];
+
+                for(int j = 1; j < rect2[0];) {
+
+                    int x21 = rect2[j++];
+                    int y21 = rect2[j++];
+                    int x22 = rect2[j++];
+                    int y22 = rect2[j++];
+
+                    if (x11 <= x22 && x12 >= x21 &&
+                        y11 <= y22 && y12 >= y21)
+                    {
+                        rect = checkBufSize(rect, 4);
+                        rect[k++] = x11 > x21 ? x11 : x21;
+                        rect[k++] = y11 > y21 ? y11 : y21;
+                        rect[k++] = x12 > x22 ? x22 : x12;
+                        rect[k++] = y12 > y22 ? y22 : y12;
+                    }
+                }
+            }
+
+            rect[0] = k;
+            return rect;
+        }
+
+        public static MultiRectArea getResult(MultiRectArea src1, MultiRectArea src2) {
+
+            if (src1 == null || src2 == null || src1.isEmpty() || src2.isEmpty()) {
+                return new MultiRectArea();
+            }
+
+            MultiRectArea.RectCash dst = new MultiRectArea.RectCash();
+
+            if (!src1.sorted || !src2.sorted || 
+               src1.getRectCount() <= MAX_SIMPLE || src2.getRectCount() <= MAX_SIMPLE) 
+            {
+                dst.setRect(simpleIntersect(src1, src2), false);
+            } else {
+                Rectangle bounds1 = src1.getBounds();
+                Rectangle bounds2 = src2.getBounds();
+                Rectangle bounds3 = bounds1.intersection(bounds2);
+                if (bounds3.width > 0 && bounds3.height > 0) {
+                    intersectRegions(src1.rect, src2.rect, dst, bounds1.height + 2, bounds2.height + 2);
+                }
+            }
+
+            return dst;
+        }
+
+    }
+
+    /**
+     * Union class provides union of two MultiRectAre aobjects
+     */
+    static class Union {
+
+        int rx1, rx2;
+        int top, bottom;
+        MultiRectArea.RectCash dst;
+
+        boolean next(Region d, int index) {
+            int x1 = d.active[index];
+            int x2 = d.active[index + 2];
+            boolean res = false;
+
+            if (x2 < rx1 - 1) {
+                res = true;
+                dst.addRectCashed(x1, top, x2, bottom);
+            } else
+                if (x1 > rx2 + 1) {
+                    res = false;
+                    dst.addRectCashed(rx1, top, rx2, bottom);
+                    rx1 = x1;
+                    rx2 = x2;
+                } else {
+                    res = x2 <= rx2;
+                    rx1 = Math.min(x1, rx1);
+                    rx2 = Math.max(x2, rx2);
+                }
+
+            // Top
+            if (d.active[index + 1] < top) {
+                dst.addRectCashed(x1, d.active[index + 1], x2, top - 1);
+            }
+            // Bottom
+            if (d.active[index + 3] > bottom) {
+                d.active[index + 1] = bottom + 1;
+            }
+            return res;
+        }
+
+        void check(Region d, int index, boolean t) {
+            int x1 = d.active[index];
+            int x2 = d.active[index + 2];
+            // Top
+            if (d.active[index + 1] < top) {
+                dst.addRectCashed(x1, d.active[index + 1], x2, top - 1);
+            }
+            if (t) {
+                dst.addRectCashed(x1, top, x2, bottom);
+            }
+            // Bottom
+            if (d.active[index + 3] > bottom) {
+                d.active[index + 1] = bottom + 1;
+            }
+        }
+
+        void unionRegions(int[] reg1, int[] reg2, int height1, int height2) {
+            Region d1 = new Region(reg1);
+            Region d2 = new Region(reg2);
+
+            int[] level = new int[height1 + height2];
+            int[] level1 = new int[height1];
+            int[] level2 = new int[height2];
+            d1.createLevel(level1);
+            d2.createLevel(level2);
+            Region.sortOrdered(level1, level2, level);
+
+            bottom = level[1] - 1;
+            for(int i = 2; i < level[0]; i++) {
+
+                top = bottom + 1;
+                bottom = level[i] - 1;
+
+                d1.findActive(top, bottom);
+                d2.findActive(top, bottom);
+
+                int i1 = 1;
+                int i2 = 1;
+                boolean res1, res2;
+
+                if (d1.active[0] > 1) {
+                    check(d1, 1, false);
+                    rx1 = d1.active[1];
+                    rx2 = d1.active[3];
+                    i1 += 4;
+                    res1 = false;
+                    res2 = true;
+                } else
+                    if (d2.active[0] > 1) {
+                        check(d2, 1, false);
+                        rx1 = d2.active[1];
+                        rx2 = d2.active[3];
+                        i2 += 4;
+                        res1 = true;
+                        res2 = false;
+                    } else {
+                        continue;
+                    }
+
+            outer:
+                while(true) {
+
+                    while (res1) {
+                        if (i1 >= d1.active[0]) {
+                            dst.addRectCashed(rx1, top, rx2, bottom);
+                            while(i2 < d2.active[0]) {
+                                check(d2, i2, true);
+                                i2 += 4;
+                            }
+                            break outer;
+                        }
+                        res1 = next(d1, i1);
+                        i1 += 4;
+                    }
+
+                    while (res2) {
+                        if (i2 >= d2.active[0]) {
+                            dst.addRectCashed(rx1, top, rx2, bottom);
+                            while(i1 < d1.active[0]) {
+                                check(d1, i1, true);
+                                i1 += 4;
+                            }
+                            break outer;
+                        }
+                        res2 = next(d2, i2);
+                        i2 += 4;
+                    }
+
+                    res1 = true;
+                    res2 = true;
+                } // while
+
+                d1.deleteActive(bottom);
+                d2.deleteActive(bottom);
+
+            }
+        }
+
+        static void simpleUnion(MultiRectArea src1, MultiRectArea src2, MultiRectArea dst) {
+            if (src1.getRectCount() < src2.getRectCount()) {
+                simpleUnion(src2, src1, dst);
+            } else {
+                Subtraction.simpleSubtract(src1, src2, dst);
+                int pos = dst.rect[0];
+                int size = src2.rect[0] - 1;
+                dst.rect = checkBufSize(dst.rect, size);
+                System.arraycopy(src2.rect,1, dst.rect, pos, size);
+                dst.resort();
+            }
+        }
+
+        MultiRectArea getResult(MultiRectArea src1, MultiRectArea src2) {
+
+            if (src1 == null || src1.isEmpty()) {
+                return new MultiRectArea(src2);
+            }
+
+            if (src2 == null || src2.isEmpty()) {
+                return new MultiRectArea(src1);
+            }
+
+            dst = new MultiRectArea.RectCash();
+
+            if (!src1.sorted || !src2.sorted ||
+               src1.getRectCount() <= MAX_SIMPLE || src2.getRectCount() <= MAX_SIMPLE) 
+            {
+                simpleUnion(src1, src2, dst);
+            } else {
+                Rectangle bounds1 = src1.getBounds();
+                Rectangle bounds2 = src2.getBounds();
+                Rectangle bounds3 = bounds1.intersection(bounds2);
+
+                if (bounds3.width < 0 || bounds3.height < 0) {
+                    if (bounds1.y + bounds1.height < bounds2.y) {
+                        dst.setRect(addVerRegion(src1.rect, src2.rect), false);
+                    } else
+                        if (bounds2.y + bounds2.height < bounds1.y) {
+                            dst.setRect(addVerRegion(src2.rect, src1.rect), false);
+                        } else
+                            if (bounds1.x < bounds2.x) {
+                                dst.setRect(addHorRegion(src1.rect, src2.rect), false);
+                            } else {
+                                dst.setRect(addHorRegion(src2.rect, src1.rect), false);
+                            }
+                } else {
+                    unionRegions(src1.rect, src2.rect, bounds1.height + 2, bounds2.height + 2);
+                }
+            }
+
+            return dst;
+        }
+
+        int[] addVerRegion(int[] top, int[] bottom) {
+            int length = top[0] + bottom[0] - 1;
+            int[] dst = new int[length];
+            dst[0] = length;
+            System.arraycopy(top, 1, dst, 1, top[0] - 1);
+            System.arraycopy(bottom, 1, dst, top[0], bottom[0] - 1);
+            return dst;
+        }
+
+        int[] addHorRegion(int[] left, int[] right) {
+            int count1 = left[0];
+            int count2 = right[0];
+            int[] dst = new int[count1 + count2 + 1];
+            int count = 1;
+            int index1 = 1;
+            int index2 = 1;
+
+            int top1 = left[2];
+            int top2 = right[2];
+            int pos1, pos2;
+
+            while(true) {
+
+                if (index1 >= count1) {
+                    System.arraycopy(right, index2, dst, count, count2 - index2);
+                    count += count2 - index2;
+                    break;
+                }
+                if (index2 >= count2) {
+                    System.arraycopy(left, index1, dst, count, count1 - index1);
+                    count += count1 - index1;
+                    break;
+                }
+
+                if (top1 < top2) {
+                    pos1 = index1;
+                    do {
+                        index1 += 4;
+                    } while (index1 < count1 && (top1 = left[index1 + 1]) < top2);
+                    System.arraycopy(left, pos1, dst, count, index1 - pos1);
+                    count += index1 - pos1;
+                    continue;
+                }
+
+                if (top1 > top2) {
+                    pos2 = index2;
+                    do {
+                        index2 += 4;
+                    } while (index2 < count2 && (top2 = right[index2 + 1]) < top1);
+                    System.arraycopy(right, pos2, dst, count, index2 - pos2);
+                    count += index2 - pos2;
+                    continue;
+                }
+
+                int top = top1;
+                pos1 = index1;
+                pos2 = index2;
+                do  {
+                    index1 += 4;
+                } while(index1 < count1 && (top1 = left[index1 + 1]) == top);
+                do {
+                    index2 += 4;
+                } while(index2 < count2 && (top2 = right[index2 + 1]) == top);
+
+                System.arraycopy(left, pos1, dst, count, index1 - pos1);
+                count += index1 - pos1;
+                System.arraycopy(right, pos2, dst, count, index2 - pos2);
+                count += index2 - pos2;
+            }
+
+            dst[0] = count;
+            return dst;
+        }
+
+    }
+
+    /**
+     * Subtraction class provides subtraction of two MultiRectAre aobjects
+     */
+    static class Subtraction {
+
+        static void subtractRegions(int[] reg1, int[] reg2, MultiRectArea.RectCash dst, int height1, int height2) {
+            Region d1 = new Region(reg1);
+            Region d2 = new Region(reg2);
+
+            int[] level = new int[height1 + height2];
+            int[] level1 = new int[height1];
+            int[] level2 = new int[height2];
+            d1.createLevel(level1);
+            d2.createLevel(level2);
+            Region.sortOrdered(level1, level2, level);
+
+            int top;
+            int bottom = level[1] - 1;
+            for(int i = 2; i < level[0]; i++) {
+
+                top = bottom + 1;
+                bottom = level[i] - 1;
+
+                d1.findActive(top, bottom);
+                if (d1.active[0] == 1) {
+                    d2.deleteActive(bottom);
+                    continue;
+                }
+
+                d2.findActive(top, bottom);
+
+                int i1 = 1;
+                int i2 = 1;
+
+                int rx1 = 0;
+                int rx2 = 0;
+
+                boolean next = true;
+
+                while(true) {
+
+                    if (next) {
+                        next = false;
+                        if (i1 >= d1.active[0]) {
+                            break;
+                        }
+                        // Bottom
+                        d1.active[i1 + 1] = bottom + 1;
+                        rx1 = d1.active[i1];
+                        rx2 = d1.active[i1 + 2];
+                        i1 += 4;
+                    }
+
+                    if (i2 >= d2.active[0]) {
+                        dst.addRectCashed(rx1, top, rx2, bottom);
+                        for(int j = i1; j < d1.active[0]; j += 4) {
+                            dst.addRectCashed(d1.active[j], top, d1.active[j + 2], bottom);
+                            d1.active[j + 1] = bottom + 1;
+                        }
+                        break;
+                    }
+
+                    int x1 = d2.active[i2];
+                    int x2 = d2.active[i2 + 2];
+
+                    if (rx1 < x1) {
+                        if (rx2 >= x1) {
+                            if (rx2 <= x2) {
+                                //  [-----------]
+                                //       [-------------]
+                                dst.addRectCashed(rx1, top, x1 - 1, bottom);
+                                next = true;
+                            } else {
+                                // [-----------------]
+                                //      [------]
+                                dst.addRectCashed(rx1, top, x1 - 1, bottom);
+                                rx1 = x2 + 1;
+                                i2 += 4;
+                            }
+                        } else {
+                            // [-----]
+                            //         [----]
+                            dst.addRectCashed(rx1, top, rx2, bottom);
+                            next = true;
+                        }
+                    } else {
+                        if (rx1 <= x2) {
+                            if (rx2 <= x2) {
+                                //    [------]
+                                //  [-----------]
+                                next = true;
+                            } else {
+                                //     [------------]
+                                // [---------]
+                                rx1 = x2 + 1;
+                                i2 += 4;
+                            }
+                        } else {
+                            //         [----]
+                            // [-----]
+                            i2 += 4;
+                        }
+                    }
+
+                }
+                d1.deleteActive();
+                d2.deleteActive(bottom);
+            }
+        }
+
+        static void subtractRect(int x11, int y11, int x12, int y12, int[] rect, int index, MultiRectArea dst) {
+
+            for(int i = index; i < rect[0]; i += 4) {
+                int x21 = rect[i + 0];
+                int y21 = rect[i + 1];
+                int x22 = rect[i + 2];
+                int y22 = rect[i + 3];
+
+                if (x11 <= x22 && x12 >= x21 && y11 <= y22 && y12 >= y21) {
+                    int top, bottom;
+                    if (y11 < y21) {
+                        subtractRect(x11, y11, x12, y21 - 1, rect, i + 4, dst);
+                        top = y21;
+                    } else {
+                        top = y11;
+                    }
+                    if (y12 > y22) {
+                        subtractRect(x11, y22 + 1, x12, y12, rect, i + 4, dst);
+                        bottom = y22;
+                    } else {
+                        bottom = y12;
+                    }
+                    if (x11 < x21) {
+                        subtractRect(x11, top, x21 - 1, bottom, rect, i + 4, dst);
+                    }
+                    if (x12 > x22) {
+                        subtractRect(x22 + 1, top, x12, bottom, rect, i + 4, dst);
+                    }
+                    return;
+                }
+            }
+            dst.addRect(x11, y11, x12, y12);
+        }
+
+        static void simpleSubtract(MultiRectArea src1, MultiRectArea src2, MultiRectArea dst) {
+            for(int i = 1; i < src1.rect[0]; i += 4) {
+                subtractRect(
+                        src1.rect[i + 0],
+                        src1.rect[i + 1],
+                        src1.rect[i + 2],
+                        src1.rect[i + 3],
+                        src2.rect,
+                        1,
+                        dst);
+            }
+            dst.resort();
+        }
+
+        public static MultiRectArea getResult(MultiRectArea src1, MultiRectArea src2) {
+
+            if (src1 == null || src1.isEmpty()) {
+                return new MultiRectArea();
+            }
+
+            if (src2 == null || src2.isEmpty()) {
+                return new MultiRectArea(src1);
+            }
+
+            MultiRectArea.RectCash dst = new MultiRectArea.RectCash();
+
+            if (!src1.sorted || !src2.sorted ||
+               src1.getRectCount() <= MAX_SIMPLE || src2.getRectCount() <= MAX_SIMPLE) 
+            {
+                simpleSubtract(src1, src2, dst);
+            } else {
+                Rectangle bounds1 = src1.getBounds();
+                Rectangle bounds2 = src2.getBounds();
+                Rectangle bounds3 = bounds1.intersection(bounds2);
+
+                if (bounds3.width > 0 && bounds3.height > 0) {
+                    subtractRegions(src1.rect, src2.rect, dst, bounds1.height + 2, bounds2.height + 2);
+                } else {
+                    dst.setRect(src1.rect, true);
+                }
+            }
+
+            return dst;
+        }
+
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/Surface.java b/awt/org/apache/harmony/awt/gl/Surface.java
new file mode 100644
index 0000000..8b0ae38
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/Surface.java
@@ -0,0 +1,309 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 10.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Image;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.MultiPixelPackedSampleModel;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+
+
+/**
+ * This class is super class for others types of Surfaces. 
+ * Surface is storing data and data format description, that are using
+ * in blitting operations    
+ */
+public abstract class Surface implements Transparency{
+
+    // Color Space Types
+    public static final int sRGB_CS = 1;
+    public static final int Linear_RGB_CS = 2;
+    public static final int Linear_Gray_CS = 3;
+    public static final int Custom_CS = 0;
+    
+    // Color Model Types
+    public static final int DCM = 1;  // Direct Color Model
+    public static final int ICM = 2;  // Index Color Model
+    public static final int CCM = 3;  // Component Color Model
+
+    // Sample Model Types
+    public static final int SPPSM = 1;  // Single Pixel Packed Sample Model
+    public static final int MPPSM = 2;  // Multi Pixel Packed Sample Model
+    public static final int CSM   = 3;  // Component Sample Model
+    public static final int PISM  = 4;  // Pixel Interleaved Sample Model
+    public static final int BSM   = 5;  // Banded Sample Model
+
+    // Surface Types
+    private static final int ALPHA_MASK = 0xff000000;
+    private static final int RED_MASK = 0x00ff0000;
+    private static final int GREEN_MASK = 0x0000ff00;
+    private static final int BLUE_MASK = 0x000000ff;
+    private static final int RED_BGR_MASK = 0x000000ff;
+    private static final int GREEN_BGR_MASK = 0x0000ff00;
+    private static final int BLUE_BGR_MASK = 0x00ff0000;
+    private static final int RED_565_MASK = 0xf800;
+    private static final int GREEN_565_MASK = 0x07e0;
+    private static final int BLUE_565_MASK = 0x001f;
+    private static final int RED_555_MASK = 0x7c00;
+    private static final int GREEN_555_MASK = 0x03e0;
+    private static final int BLUE_555_MASK = 0x001f;
+
+    static{
+        //???AWT
+        /*
+        System.loadLibrary("gl"); //$NON-NLS-1$
+        initIDs();
+        */
+    }
+
+
+    protected long surfaceDataPtr;        // Pointer for Native Surface data
+    protected int transparency = OPAQUE;
+    protected int width;
+    protected int height;
+
+    /**
+     * This list contains caches with the data of this surface that are valid at the moment.
+     * Surface should clear this list when its data is updated.
+     * Caches may check if they are still valid using isCacheValid method.
+     * When cache gets data from the surface, it should call addValidCache method of the surface.
+     */
+    private final ArrayList<Object> validCaches = new ArrayList<Object>();
+
+    public abstract ColorModel getColorModel();
+    public abstract WritableRaster getRaster();
+    public abstract int getSurfaceType(); // Syrface type. It is equal 
+                                          // BufferedImge type
+    /**
+     * Lock Native Surface data
+     */
+    public abstract long lock();     
+    
+    /**
+     * Unlock Native Surface data 
+     */
+    public abstract void unlock();
+    
+    /**
+     * Dispose Native Surface data
+     */
+    public abstract void dispose();
+    public abstract Surface getImageSurface();
+
+    public long getSurfaceDataPtr(){
+        return surfaceDataPtr;
+    }
+
+    public final boolean isCaheValid(Object cache) {
+        return validCaches.contains(cache);
+    }
+
+    public final void addValidCache(Object cache) {
+        validCaches.add(cache);
+    }
+
+    protected final void clearValidCaches() {
+        validCaches.clear();
+    }
+
+    /**
+     * Returns could or coldn't the Surface be blit by Native blitter 
+     * @return - true if the Surface could be blit by Native blitter, 
+     *           false in other case
+     */
+    public boolean isNativeDrawable(){
+        return true;
+    }
+
+    public int getTransparency() {
+        return transparency;
+    }
+
+    public int getWidth(){
+        return width;
+    }
+
+    public int getHeight(){
+        return height;
+    }
+    
+    /**
+     * If Surface has Raster, this method returns data array of Raster's DataBuffer
+     * @return - data array
+     */
+    public Object getData(){
+        return null;
+    }
+    
+    public boolean invalidated(){
+        return true;
+    }
+    
+    public void validate(){}
+    
+    public void invalidate(){}
+
+    /**
+     * Computation type of BufferedImage or Surface
+     * @param cm - ColorModel
+     * @param raster - WritableRaste
+     * @return - type of BufferedImage
+     */
+    public static int getType(ColorModel cm, WritableRaster raster){
+        int transferType = cm.getTransferType();
+        boolean hasAlpha = cm.hasAlpha();
+        ColorSpace cs = cm.getColorSpace();
+        int csType = cs.getType();
+        SampleModel sm = raster.getSampleModel();
+
+        if(csType == ColorSpace.TYPE_RGB){
+            if(cm instanceof DirectColorModel){
+                DirectColorModel dcm = (DirectColorModel) cm;
+                switch (transferType) {
+                case DataBuffer.TYPE_INT:
+                    if (dcm.getRedMask() == RED_MASK &&
+                            dcm.getGreenMask() == GREEN_MASK &&
+                            dcm.getBlueMask() == BLUE_MASK) {
+                        if (!hasAlpha) {
+                            return BufferedImage.TYPE_INT_RGB;
+                        }
+                        if (dcm.getAlphaMask() == ALPHA_MASK) {
+                            if (dcm.isAlphaPremultiplied()) {
+                                return BufferedImage.TYPE_INT_ARGB_PRE;
+                            }
+                            return BufferedImage.TYPE_INT_ARGB;
+                        }
+                        return BufferedImage.TYPE_CUSTOM;
+                    } else if (dcm.getRedMask() == RED_BGR_MASK &&
+                            dcm.getGreenMask() == GREEN_BGR_MASK &&
+                            dcm.getBlueMask() == BLUE_BGR_MASK) {
+                        if (!hasAlpha) {
+                            return BufferedImage.TYPE_INT_BGR;
+                        }
+                    } else {
+                        return BufferedImage.TYPE_CUSTOM;
+                    }
+                case DataBuffer.TYPE_USHORT:
+                    if (dcm.getRedMask() == RED_555_MASK &&
+                            dcm.getGreenMask() == GREEN_555_MASK &&
+                            dcm.getBlueMask() == BLUE_555_MASK && !hasAlpha) {
+                        return BufferedImage.TYPE_USHORT_555_RGB;
+                    } else if (dcm.getRedMask() == RED_565_MASK &&
+                            dcm.getGreenMask() == GREEN_565_MASK &&
+                            dcm.getBlueMask() == BLUE_565_MASK) {
+                        return BufferedImage.TYPE_USHORT_565_RGB;
+                    }
+                default:
+                    return BufferedImage.TYPE_CUSTOM;
+                }
+            }else if(cm instanceof IndexColorModel){
+                IndexColorModel icm = (IndexColorModel) cm;
+                int pixelBits = icm.getPixelSize();
+                if(transferType == DataBuffer.TYPE_BYTE){
+                    if(sm instanceof MultiPixelPackedSampleModel && !hasAlpha &&
+                        pixelBits < 5){
+                            return BufferedImage.TYPE_BYTE_BINARY;
+                    }else if(pixelBits == 8){
+                        return BufferedImage.TYPE_BYTE_INDEXED;
+                    }
+                }
+                return BufferedImage.TYPE_CUSTOM;
+            }else if(cm instanceof ComponentColorModel){
+                ComponentColorModel ccm = (ComponentColorModel) cm;
+                if(transferType == DataBuffer.TYPE_BYTE &&
+                        sm instanceof ComponentSampleModel){
+                    ComponentSampleModel csm =
+                        (ComponentSampleModel) sm;
+                    int[] offsets = csm.getBandOffsets();
+                    int[] bits = ccm.getComponentSize();
+                    boolean isCustom = false;
+                    for (int i = 0; i < bits.length; i++) {
+                        if (bits[i] != 8 ||
+                               offsets[i] != offsets.length - 1 - i) {
+                            isCustom = true;
+                            break;
+                        }
+                    }
+                    if (!isCustom) {
+                        if (!ccm.hasAlpha()) {
+                            return BufferedImage.TYPE_3BYTE_BGR;
+                        } else if (ccm.isAlphaPremultiplied()) {
+                            return BufferedImage.TYPE_4BYTE_ABGR_PRE;
+                        } else {
+                            return BufferedImage.TYPE_4BYTE_ABGR;
+                        }
+                    }
+                }
+                return BufferedImage.TYPE_CUSTOM;
+            }
+            return BufferedImage.TYPE_CUSTOM;
+        }else if(cs == LUTColorConverter.LINEAR_GRAY_CS){
+            if(cm instanceof ComponentColorModel &&
+                    cm.getNumComponents() == 1){
+                int bits[] = cm.getComponentSize();
+                if(transferType == DataBuffer.TYPE_BYTE &&
+                        bits[0] == 8){
+                    return BufferedImage.TYPE_BYTE_GRAY;
+                }else if(transferType == DataBuffer.TYPE_USHORT &&
+                        bits[0] == 16){
+                    return BufferedImage.TYPE_USHORT_GRAY;
+                }else{
+                    return BufferedImage.TYPE_CUSTOM;
+                }
+            }
+            return BufferedImage.TYPE_CUSTOM;
+        }
+        return BufferedImage.TYPE_CUSTOM;
+    }
+
+    public static Surface getImageSurface(Image image){
+        return AwtImageBackdoorAccessor.getInstance().getImageSurface(image);
+    }
+
+    @Override
+    protected void finalize() throws Throwable{
+        dispose();
+    }
+
+    public static boolean isGrayPallete(IndexColorModel icm){
+        return AwtImageBackdoorAccessor.getInstance().isGrayPallete(icm);
+    }
+
+    /**
+     * Initialization of Native data
+     * 
+     */
+    //???AWT: private static native void initIDs();
+}
diff --git a/awt/org/apache/harmony/awt/gl/TextRenderer.java b/awt/org/apache/harmony/awt/gl/TextRenderer.java
new file mode 100644
index 0000000..f57952d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/TextRenderer.java
@@ -0,0 +1,59 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Graphics2D;
+import java.awt.font.GlyphVector;
+
+public abstract class TextRenderer {
+    
+    /**
+     * Draws string on specified Graphics at desired position.
+     * 
+     * @param g specified Graphics2D object
+     * @param str String object to draw
+     * @param x start X position to draw
+     * @param y start Y position to draw
+     */
+    public abstract void drawString(Graphics2D g, String str, float x, float y);
+
+    /**
+     * Draws string on specified Graphics at desired position.
+     * 
+     * @param g specified Graphics2D object
+     * @param str String object to draw
+     * @param x start X position to draw
+     * @param y start Y position to draw
+     */    
+    public void drawString(Graphics2D g, String str, int x, int y){
+        drawString(g, str, (float)x, (float)y);
+    }
+
+    /**
+     * Draws GlyphVector on specified Graphics at desired position.
+     * 
+     * @param g specified Graphics2D object
+     * @param glyphVector GlyphVector object to draw
+     * @param x start X position to draw
+     * @param y start Y position to draw
+     */
+    public abstract void drawGlyphVector(Graphics2D g, GlyphVector glyphVector, float x, float y);
+}
diff --git a/awt/org/apache/harmony/awt/gl/XORComposite.java b/awt/org/apache/harmony/awt/gl/XORComposite.java
new file mode 100644
index 0000000..e27e1d3
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/XORComposite.java
@@ -0,0 +1,48 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 21.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.RenderingHints;
+import java.awt.image.ColorModel;
+
+public class XORComposite implements Composite {
+
+    Color xorcolor;
+
+    public XORComposite(Color xorcolor){
+        this.xorcolor = xorcolor;
+    }
+
+    public CompositeContext createContext(ColorModel srcCM, ColorModel dstCM,
+            RenderingHints hints) {
+
+        return new ICompositeContext(this, srcCM, dstCM);
+    }
+
+    public Color getXORColor(){
+        return xorcolor;
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/color/ColorConverter.java b/awt/org/apache/harmony/awt/gl/color/ColorConverter.java
new file mode 100644
index 0000000..c98e114
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/ColorConverter.java
@@ -0,0 +1,257 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+/**
+ * This class combines ColorScaler, ICC_Transform and NativeImageFormat functionality
+ * in the workflows for different types of input/output pixel data.
+ */
+public class ColorConverter {
+    private ColorScaler scaler = new ColorScaler();
+
+    public void loadScalingData(ColorSpace cs) {
+        scaler.loadScalingData(cs);
+    }
+
+    /**
+     * Translates pixels, stored in source buffered image and writes the data
+     * to the destination image.
+     * @param t - ICC transform
+     * @param src - source image
+     * @param dst - destination image
+     */
+    public void translateColor(ICC_Transform t,
+            BufferedImage src, BufferedImage dst) {
+      NativeImageFormat srcIF = NativeImageFormat.createNativeImageFormat(src);
+      NativeImageFormat dstIF = NativeImageFormat.createNativeImageFormat(dst);
+
+      if (srcIF != null && dstIF != null) {
+          t.translateColors(srcIF, dstIF);
+          return;
+      }
+
+        srcIF = createImageFormat(src);
+        dstIF = createImageFormat(dst);
+
+        short srcChanData[] = (short[]) srcIF.getChannelData();
+        short dstChanData[] = (short[]) dstIF.getChannelData();
+
+        ColorModel srcCM = src.getColorModel();
+        int nColorChannels = srcCM.getNumColorComponents();
+        scaler.loadScalingData(srcCM.getColorSpace()); // input scaling data
+        ColorModel dstCM = dst.getColorModel();
+
+        // Prepare array for alpha channel
+        float alpha[] = null;
+        boolean saveAlpha = srcCM.hasAlpha() && dstCM.hasAlpha();
+        if (saveAlpha) {
+            alpha = new float[src.getWidth()*src.getHeight()];
+        }
+
+        WritableRaster wr = src.getRaster();
+        int srcDataPos = 0, alphaPos = 0;
+        float normalizedVal[];
+        for (int row=0, nRows = srcIF.getNumRows(); row<nRows; row++) {
+            for (int col=0, nCols = srcIF.getNumCols(); col<nCols; col++) {
+                normalizedVal = srcCM.getNormalizedComponents(
+                    wr.getDataElements(col, row, null),
+                    null, 0);
+                // Save alpha channel
+                if (saveAlpha) {
+                    // We need nColorChannels'th element cause it's nChannels - 1
+                    alpha[alphaPos++] = normalizedVal[nColorChannels];
+                }
+                scaler.scale(normalizedVal, srcChanData, srcDataPos);
+                srcDataPos += nColorChannels;
+            }
+        }
+
+        t.translateColors(srcIF, dstIF);
+
+        nColorChannels = dstCM.getNumColorComponents();
+        boolean fillAlpha = dstCM.hasAlpha();
+        scaler.loadScalingData(dstCM.getColorSpace()); // output scaling data
+        float dstPixel[] = new float[dstCM.getNumComponents()];
+        int dstDataPos = 0;
+        alphaPos = 0;
+        wr = dst.getRaster();
+
+        for (int row=0, nRows = dstIF.getNumRows(); row<nRows; row++) {
+            for (int col=0, nCols = dstIF.getNumCols(); col<nCols; col++) {
+                scaler.unscale(dstPixel, dstChanData, dstDataPos);
+                dstDataPos += nColorChannels;
+                if (fillAlpha) {
+                    if (saveAlpha) {
+                        dstPixel[nColorChannels] = alpha[alphaPos++];
+                    } else {
+                        dstPixel[nColorChannels] = 1f;
+                    }
+                }
+                wr.setDataElements(col, row,
+                        dstCM.getDataElements(dstPixel, 0 , null));
+            }
+        }
+    }
+
+    /**
+     * Translates pixels, stored in the float data buffer.
+     * Each pixel occupies separate array. Input pixels passed in the buffer
+     * are replaced by output pixels and then the buffer is returned
+     * @param t - ICC transform
+     * @param buffer - data buffer
+     * @param srcCS - source color space
+     * @param dstCS - destination color space
+     * @param nPixels - number of pixels
+     * @return translated pixels
+     */
+    public float[][] translateColor(ICC_Transform t,
+            float buffer[][],
+            ColorSpace srcCS,
+            ColorSpace dstCS,
+            int nPixels) {
+        // Scale source data
+        if (srcCS != null) { // if it is null use old scaling data
+            scaler.loadScalingData(srcCS);
+        }
+        int nSrcChannels = t.getNumInputChannels();
+        short srcShortData[] = new short[nPixels*nSrcChannels];
+        for (int i=0, srcDataPos = 0; i<nPixels; i++) {
+            scaler.scale(buffer[i], srcShortData, srcDataPos);
+            srcDataPos += nSrcChannels;
+        }
+
+        // Apply transform
+        short dstShortData[] = this.translateColor(t, srcShortData, null);
+
+        int nDstChannels = t.getNumOutputChannels();
+        int bufferSize = buffer[0].length;
+        if (bufferSize < nDstChannels + 1) { // Re-allocate buffer if needed
+            for (int i=0; i<nPixels; i++) {
+                // One extra element reserved for alpha
+                buffer[i] = new float[nDstChannels + 1];
+            }
+        }
+
+        // Unscale destination data
+        if (dstCS != null) { // if it is null use old scaling data
+            scaler.loadScalingData(dstCS);
+        }
+        for (int i=0, dstDataPos = 0; i<nPixels; i++) {
+            scaler.unscale(buffer[i], dstShortData, dstDataPos);
+            dstDataPos += nDstChannels;
+        }
+
+        return buffer;
+    }
+
+    /**
+     * Translates pixels stored in a raster.
+     * All data types are supported
+     * @param t - ICC transform
+     * @param src - source pixels
+     * @param dst - destination pixels
+     */
+   public void translateColor(ICC_Transform t, Raster src, WritableRaster dst) {
+        try{
+            NativeImageFormat srcFmt = NativeImageFormat.createNativeImageFormat(src);
+            NativeImageFormat dstFmt = NativeImageFormat.createNativeImageFormat(dst);
+
+          if (srcFmt != null && dstFmt != null) {
+              t.translateColors(srcFmt, dstFmt);
+              return;
+          }
+        } catch (IllegalArgumentException e) {
+      }
+
+        // Go ahead and rescale the source image
+        scaler.loadScalingData(src, t.getSrc());
+        short srcData[] = scaler.scale(src);
+
+        short dstData[] = translateColor(t, srcData, null);
+
+        scaler.loadScalingData(dst, t.getDst());
+        scaler.unscale(dstData, dst);
+   }
+
+    /**
+     * Translates pixels stored in an array of shorts.
+     * Samples are stored one-by-one, i.e. array structure is like following: RGBRGBRGB...
+     * The number of pixels is (size of the array) / (number of components).
+     * @param t - ICC transform
+     * @param src - source pixels
+     * @param dst - destination pixels
+     * @return destination pixels, stored in the array, passed in dst
+     */
+    public short[] translateColor(ICC_Transform t, short src[], short dst[]) {
+        NativeImageFormat srcFmt = createImageFormat(t, src, 0, true);
+        NativeImageFormat dstFmt = createImageFormat(t, dst, srcFmt.getNumCols(), false);
+
+        t.translateColors(srcFmt, dstFmt);
+
+        return (short[]) dstFmt.getChannelData();
+    }
+
+
+    /**
+     * Creates NativeImageFormat from buffered image.
+     * @param bi - buffered image
+     * @return created NativeImageFormat
+     */
+    private NativeImageFormat createImageFormat(BufferedImage bi) {
+        int nRows = bi.getHeight();
+        int nCols = bi.getWidth();
+        int nComps = bi.getColorModel().getNumColorComponents();
+        short imgData[] = new short[nRows*nCols*nComps];
+        return new NativeImageFormat(
+                imgData, nComps, nRows, nCols);
+    }
+
+    /**
+     * Creates one-row NativeImageFormat, using either nCols if it is positive,
+     * or arr.length to determine the number of pixels
+     *
+     * @param t - transform
+     * @param arr - short array or null if nCols is positive
+     * @param nCols - number of pixels in the array or 0 if array is not null
+     * @param in - is it an input or output array
+     * @return one-row NativeImageFormat
+     */
+    private NativeImageFormat createImageFormat(
+            ICC_Transform t, short arr[], int nCols, boolean in
+    ) {
+        int nComponents = in ? t.getNumInputChannels() : t.getNumOutputChannels();
+
+        if (arr == null || arr.length < nCols*nComponents) {
+            arr = new short[nCols*nComponents];
+        }
+
+        if (nCols == 0)
+            nCols = arr.length / nComponents;
+
+        return new NativeImageFormat(arr, nComponents, 1, nCols);
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/color/ColorScaler.java b/awt/org/apache/harmony/awt/gl/color/ColorScaler.java
new file mode 100644
index 0000000..a1cc169
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/ColorScaler.java
@@ -0,0 +1,355 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_Profile;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+
+/**
+ * This class provides functionality for scaling color data when
+ * ranges of the source and destination color values differs. 
+ */
+public class ColorScaler {
+    private static final float MAX_SHORT = 0xFFFF;
+    private static final float MAX_SIGNED_SHORT = 0x7FFF;
+
+    private static final float MAX_XYZ = 1f + (32767f/32768f);
+
+    // Cached values for scaling color data
+    private float[] channelMinValues = null;
+    private float[] channelMulipliers = null; // for scale
+    private float[] invChannelMulipliers = null; // for unscale
+
+    int nColorChannels = 0;
+
+    // For scaling rasters, false if transfer type is double or float
+    boolean isTTypeIntegral = false;
+
+    /**
+     * Loads scaling data for raster. Note, if profile pf is null,
+     * for non-integral data types multipliers are not initialized.
+     * @param r - raster
+     * @param pf - profile which helps to determine the ranges of the color data
+     */
+    public void loadScalingData(Raster r, ICC_Profile pf) {
+        boolean isSrcTTypeIntegral =
+            r.getTransferType() != DataBuffer.TYPE_FLOAT &&
+            r.getTransferType() != DataBuffer.TYPE_DOUBLE;
+        if (isSrcTTypeIntegral)
+            loadScalingData(r.getSampleModel());
+        else if (pf != null)
+            loadScalingData(pf);
+    }
+
+    /**
+     * Use this method only for integral transfer types.
+     * Extracts min/max values from the sample model
+     * @param sm - sample model
+     */
+    public void loadScalingData(SampleModel sm) {
+        // Supposing integral transfer type
+        isTTypeIntegral = true;
+
+        nColorChannels = sm.getNumBands();
+
+        channelMinValues = new float[nColorChannels];
+        channelMulipliers = new float[nColorChannels];
+        invChannelMulipliers = new float[nColorChannels];
+
+        boolean isSignedShort =
+            (sm.getTransferType() == DataBuffer.TYPE_SHORT);
+
+        float maxVal;
+        for (int i=0; i<nColorChannels; i++) {
+            channelMinValues[i] = 0;
+            if (isSignedShort) {
+                channelMulipliers[i] = MAX_SHORT / MAX_SIGNED_SHORT;
+                invChannelMulipliers[i] = MAX_SIGNED_SHORT / MAX_SHORT;
+            } else {
+                maxVal = ((1 << sm.getSampleSize(i)) - 1);
+                channelMulipliers[i] = MAX_SHORT / maxVal;
+                invChannelMulipliers[i] = maxVal / MAX_SHORT;
+            }
+        }
+    }
+
+    /**
+     * Use this method only for double of float transfer types.
+     * Extracts scaling data from the color space signature
+     * and other tags, stored in the profile
+     * @param pf - ICC profile
+     */
+    public void loadScalingData(ICC_Profile pf) {
+        // Supposing double or float transfer type
+        isTTypeIntegral = false;
+
+        nColorChannels = pf.getNumComponents();
+
+        // Get min/max values directly from the profile
+        // Very much like fillMinMaxValues in ICC_ColorSpace
+        float maxValues[] = new float[nColorChannels];
+        float minValues[] = new float[nColorChannels];
+
+        switch (pf.getColorSpaceType()) {
+            case ColorSpace.TYPE_XYZ:
+                minValues[0] = 0;
+                minValues[1] = 0;
+                minValues[2] = 0;
+                maxValues[0] = MAX_XYZ;
+                maxValues[1] = MAX_XYZ;
+                maxValues[2] = MAX_XYZ;
+                break;
+            case ColorSpace.TYPE_Lab:
+                minValues[0] = 0;
+                minValues[1] = -128;
+                minValues[2] = -128;
+                maxValues[0] = 100;
+                maxValues[1] = 127;
+                maxValues[2] = 127;
+                break;
+            default:
+                for (int i=0; i<nColorChannels; i++) {
+                    minValues[i] = 0;
+                    maxValues[i] = 1;
+                }
+        }
+
+        channelMinValues = minValues;
+        channelMulipliers = new float[nColorChannels];
+        invChannelMulipliers = new float[nColorChannels];
+
+        for (int i = 0; i < nColorChannels; i++) {
+            channelMulipliers[i] =
+                MAX_SHORT / (maxValues[i] - channelMinValues[i]);
+
+            invChannelMulipliers[i] =
+                (maxValues[i] - channelMinValues[i]) / MAX_SHORT;
+        }
+    }
+
+    /**
+     * Extracts scaling data from the color space
+     * @param cs - color space
+     */
+    public void loadScalingData(ColorSpace cs) {
+        nColorChannels = cs.getNumComponents();
+
+        channelMinValues = new float[nColorChannels];
+        channelMulipliers = new float[nColorChannels];
+        invChannelMulipliers = new float[nColorChannels];
+
+        for (int i = 0; i < nColorChannels; i++) {
+            channelMinValues[i] = cs.getMinValue(i);
+
+            channelMulipliers[i] =
+                MAX_SHORT / (cs.getMaxValue(i) - channelMinValues[i]);
+
+            invChannelMulipliers[i] =
+                (cs.getMaxValue(i) - channelMinValues[i]) / MAX_SHORT;
+        }
+    }
+
+    /**
+     * Scales and normalizes the whole raster and returns the result
+     * in the float array
+     * @param r - source raster
+     * @return scaled and normalized raster data
+     */
+    public float[][] scaleNormalize(Raster r) {
+        int width = r.getWidth();
+        int height = r.getHeight();
+        float result[][] = new float[width*height][nColorChannels];
+        float normMultipliers[] = new float[nColorChannels];
+
+        int pos = 0;
+        if (isTTypeIntegral) {
+            // Change max value from MAX_SHORT to 1f
+            for (int i=0; i<nColorChannels; i++) {
+                normMultipliers[i] = channelMulipliers[i] / MAX_SHORT;
+            }
+
+            int sample;
+            for (int row=r.getMinX(); row<width; row++) {
+                for (int col=r.getMinY(); col<height; col++) {
+                    for (int chan = 0; chan < nColorChannels; chan++) {
+                        sample = r.getSample(row, col, chan);
+                        result[pos][chan] = (sample * normMultipliers[chan]);
+                    }
+                    pos++;
+                }
+            }
+        } else { // Just get the samples...
+            for (int row=r.getMinX(); row<width; row++) {
+                for (int col=r.getMinY(); col<height; col++) {
+                    for (int chan = 0; chan < nColorChannels; chan++) {
+                        result[pos][chan] = r.getSampleFloat(row, col, chan);
+                    }
+                    pos++;
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Unscale the whole float array and put the result
+     * in the raster
+     * @param r - destination raster
+     * @param data - input pixels
+     */
+    public void unscaleNormalized(WritableRaster r, float data[][]) {
+        int width = r.getWidth();
+        int height = r.getHeight();
+        float normMultipliers[] = new float[nColorChannels];
+
+        int pos = 0;
+        if (isTTypeIntegral) {
+            // Change max value from MAX_SHORT to 1f
+            for (int i=0; i<nColorChannels; i++) {
+                normMultipliers[i] = invChannelMulipliers[i] * MAX_SHORT;
+            }
+
+            int sample;
+            for (int row=r.getMinX(); row<width; row++) {
+                for (int col=r.getMinY(); col<height; col++) {
+                    for (int chan = 0; chan < nColorChannels; chan++) {
+                        sample = (int) (data[pos][chan] * normMultipliers[chan] + 0.5f);
+                        r.setSample(row, col, chan, sample);
+                    }
+                    pos++;
+                }
+            }
+        } else { // Just set the samples...
+            for (int row=r.getMinX(); row<width; row++) {
+                for (int col=r.getMinY(); col<height; col++) {
+                    for (int chan = 0; chan < nColorChannels; chan++) {
+                        r.setSample(row, col, chan, data[pos][chan]);
+                    }
+                    pos++;
+                }
+            }
+        }
+    }
+
+    /**
+     * Scales the whole raster to short and returns the result
+     * in the array
+     * @param r - source raster
+     * @return scaled and normalized raster data
+     */
+    public short[] scale(Raster r) {
+        int width = r.getWidth();
+        int height = r.getHeight();
+        short result[] = new short[width*height*nColorChannels];
+
+        int pos = 0;
+        if (isTTypeIntegral) {
+            int sample;
+            for (int row=r.getMinX(); row<width; row++) {
+                for (int col=r.getMinY(); col<height; col++) {
+                    for (int chan = 0; chan < nColorChannels; chan++) {
+                        sample = r.getSample(row, col, chan);
+                        result[pos++] =
+                            (short) (sample * channelMulipliers[chan] + 0.5f);
+                    }
+                }
+            }
+        } else {
+            float sample;
+            for (int row=r.getMinX(); row<width; row++) {
+                for (int col=r.getMinY(); col<height; col++) {
+                    for (int chan = 0; chan < nColorChannels; chan++) {
+                        sample = r.getSampleFloat(row, col, chan);
+                        result[pos++] = (short) ((sample - channelMinValues[chan])
+                            * channelMulipliers[chan] + 0.5f);
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Unscales the whole data array and puts obtained values to the raster
+     * @param data - input data
+     * @param wr - destination raster
+     */
+    public void unscale(short[] data, WritableRaster wr) {
+        int width = wr.getWidth();
+        int height = wr.getHeight();
+
+        int pos = 0;
+        if (isTTypeIntegral) {
+            int sample;
+            for (int row=wr.getMinX(); row<width; row++) {
+                for (int col=wr.getMinY(); col<height; col++) {
+                    for (int chan = 0; chan < nColorChannels; chan++) {
+                         sample = (int) ((data[pos++] & 0xFFFF) *
+                                invChannelMulipliers[chan] + 0.5f);
+                         wr.setSample(row, col, chan, sample);
+                    }
+                }
+            }
+        } else {
+            float sample;
+            for (int row=wr.getMinX(); row<width; row++) {
+                for (int col=wr.getMinY(); col<height; col++) {
+                    for (int chan = 0; chan < nColorChannels; chan++) {
+                         sample = (data[pos++] & 0xFFFF) *
+                            invChannelMulipliers[chan] + channelMinValues[chan];
+                         wr.setSample(row, col, chan, sample);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Scales one pixel and puts obtained values to the chanData
+     * @param pixelData - input pixel
+     * @param chanData - output buffer
+     * @param chanDataOffset - output buffer offset
+     */
+    public void scale(float[] pixelData, short[] chanData, int chanDataOffset) {
+        for (int chan = 0; chan < nColorChannels; chan++) {
+            chanData[chanDataOffset + chan] =
+                    (short) ((pixelData[chan] - channelMinValues[chan]) *
+                        channelMulipliers[chan] + 0.5f);
+        }
+    }
+
+    /**
+     * Unscales one pixel and puts obtained values to the pixelData
+     * @param pixelData - output pixel
+     * @param chanData - input buffer
+     * @param chanDataOffset - input buffer offset
+     */
+    public void unscale(float[] pixelData, short[] chanData, int chanDataOffset) {
+        for (int chan = 0; chan < nColorChannels; chan++) {
+            pixelData[chan] = (chanData[chanDataOffset + chan] & 0xFFFF)
+                * invChannelMulipliers[chan] + channelMinValues[chan];
+        }
+    }
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/color/ICC_ProfileHelper.java b/awt/org/apache/harmony/awt/gl/color/ICC_ProfileHelper.java
new file mode 100644
index 0000000..2f7e519
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/ICC_ProfileHelper.java
@@ -0,0 +1,82 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ICC_Profile;
+
+/**
+ * Includes utility methods for reading ICC profile data.
+ * Created to provide public access to ICC_Profile methods
+ * for classes outside of java.awt.color
+ */
+public class ICC_ProfileHelper {
+    /**
+     * Utility method.
+     * Gets integer value from the byte array
+     * @param byteArray - byte array
+     * @param idx - byte offset
+     * @return integer value
+     */
+    public static int getIntFromByteArray(byte[] byteArray, int idx) {
+        return (byteArray[idx] & 0xFF)|
+               ((byteArray[idx+1] & 0xFF) << 8) |
+               ((byteArray[idx+2] & 0xFF) << 16)|
+               ((byteArray[idx+3] & 0xFF) << 24);
+    }
+
+    /**
+     * Utility method.
+     * Gets big endian integer value from the byte array
+     * @param byteArray - byte array
+     * @param idx - byte offset
+     * @return integer value
+     */
+    public static int getBigEndianFromByteArray(byte[] byteArray, int idx) {
+        return ((byteArray[idx] & 0xFF) << 24)   |
+               ((byteArray[idx+1] & 0xFF) << 16) |
+               ((byteArray[idx+2] & 0xFF) << 8)  |
+               ( byteArray[idx+3] & 0xFF);
+    }
+
+    /**
+     * Utility method.
+     * Gets short value from the byte array
+     * @param byteArray - byte array
+     * @param idx - byte offset
+     * @return short value
+     */
+    public static short getShortFromByteArray(byte[] byteArray, int idx) {
+        return (short) ((byteArray[idx] & 0xFF) |
+                       ((byteArray[idx+1] & 0xFF) << 8));
+    }
+
+    /**
+     * Used in ICC_Transform class to check the rendering intent of the profile
+     * @param profile - ICC profile
+     * @return rendering intent
+     */
+    public static int getRenderingIntent(ICC_Profile profile) {
+        return getIntFromByteArray(
+                profile.getData(ICC_Profile.icSigHead), // pf header
+                ICC_Profile.icHdrRenderingIntent
+            );
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/color/ICC_Transform.java b/awt/org/apache/harmony/awt/gl/color/ICC_Transform.java
new file mode 100644
index 0000000..27646c4
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/ICC_Transform.java
@@ -0,0 +1,156 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ICC_Profile;
+
+import org.apache.harmony.awt.gl.color.NativeCMM;
+
+/**
+ * This class encapsulates native ICC transform object, is responsible for its
+ * creation, destruction and passing its handle to the native CMM.
+ */
+public class ICC_Transform {
+    private long transformHandle;
+    private int numInputChannels;
+    private int numOutputChannels;
+    private ICC_Profile src;
+    private ICC_Profile dst;
+
+
+    /**
+     * @return Returns the number of input channels.
+     */
+    public int getNumInputChannels() {
+        return numInputChannels;
+    }
+
+    /**
+     * @return Returns the number of output channels.
+     */
+    public int getNumOutputChannels() {
+        return numOutputChannels;
+    }
+
+    /**
+     * @return Returns the dst.
+     */
+    public ICC_Profile getDst() {
+        return dst;
+    }
+
+    /**
+     * @return Returns the src.
+     */
+    public ICC_Profile getSrc() {
+        return src;
+    }
+
+    /**
+     * Constructs a multiprofile ICC transform
+     * @param profiles - list of ICC profiles
+     * @param renderIntents - only hints for CMM
+     */
+    public ICC_Transform(ICC_Profile[] profiles, int[] renderIntents) {
+        int numProfiles = profiles.length;
+
+        long[] profileHandles = new long[numProfiles];
+        for (int i=0; i<numProfiles; i++) {
+            profileHandles[i] = NativeCMM.getHandle(profiles[i]);
+        }
+
+        transformHandle = NativeCMM.cmmCreateMultiprofileTransform(
+                profileHandles,
+                renderIntents);
+
+        src = profiles[0];
+        dst = profiles[numProfiles-1];
+        numInputChannels = src.getNumComponents();
+        numOutputChannels = dst.getNumComponents();
+    }
+
+    /**
+     * This constructor is able to set intents by default
+     * @param profiles - list of ICC profiles
+     */
+    public ICC_Transform(ICC_Profile[] profiles) {
+        int numProfiles = profiles.length;
+        int[] renderingIntents = new int[numProfiles];
+
+        // Default is perceptual
+        int currRenderingIntent = ICC_Profile.icPerceptual;
+
+        // render as colorimetric for output device
+        if (profiles[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) {
+            currRenderingIntent = ICC_Profile.icRelativeColorimetric;
+        }
+
+        // get the transforms from each profile
+        for (int i = 0; i < numProfiles; i++) {
+            // first or last profile cannot be abstract
+            // if profile is abstract, the only possible way is
+            // use AToB0Tag (perceptual), see ICC spec
+            if (i != 0 &&
+               i != numProfiles - 1 &&
+               profiles[i].getProfileClass() == ICC_Profile.CLASS_ABSTRACT
+            ) {
+                currRenderingIntent = ICC_Profile.icPerceptual;
+            }
+
+            renderingIntents[i] = currRenderingIntent;
+            // use current rendering intent
+            // to select LUT from the next profile (chaining)
+            currRenderingIntent =
+                ICC_ProfileHelper.getRenderingIntent(profiles[i]);
+        }
+
+        // Get the profile handles and go ahead
+        long[] profileHandles = new long[numProfiles];
+        for (int i=0; i<numProfiles; i++) {
+            profileHandles[i] = NativeCMM.getHandle(profiles[i]);
+        }
+
+        transformHandle = NativeCMM.cmmCreateMultiprofileTransform(
+                profileHandles,
+                renderingIntents);
+
+        src = profiles[0];
+        dst = profiles[numProfiles-1];
+        numInputChannels = src.getNumComponents();
+        numOutputChannels = dst.getNumComponents();
+    }
+
+    @Override
+    protected void finalize() {
+        if (transformHandle != 0) {
+            NativeCMM.cmmDeleteTransform(transformHandle);
+        }
+    }
+
+    /**
+     * Invokes native color conversion
+     * @param src - source image format
+     * @param dst - destination image format
+     */
+    public void translateColors(NativeImageFormat src, NativeImageFormat dst) {
+        NativeCMM.cmmTranslateColors(transformHandle, src, dst);
+    }
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/color/LUTColorConverter.java b/awt/org/apache/harmony/awt/gl/color/LUTColorConverter.java
new file mode 100644
index 0000000..5ea6d25
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/LUTColorConverter.java
@@ -0,0 +1,148 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 02.11.2004
+ *
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ColorSpace;
+
+public class LUTColorConverter {
+
+    private static byte from8lRGBtosRGB_LUT[];
+
+    private static byte from16lRGBtosRGB_LUT[];
+
+    private static byte fromsRGBto8lRGB_LUT[];
+
+    private static short fromsRGBto16lRGB_LUT[];
+
+    private static byte fromsRGBto8sRGB_LUTs[][];
+
+    public static ColorSpace LINEAR_RGB_CS;
+
+    public static ColorSpace LINEAR_GRAY_CS;
+
+    public static ColorSpace sRGB_CS;
+
+    public LUTColorConverter() {
+    }
+
+    /*
+     * This class prepared and returned lookup tables for conversion color 
+     * values from Linear RGB Color Space to sRGB and vice versa.
+     * Conversion is producing according to sRGB Color Space definition.
+     * "A Standard Default Color Space for the Internet - sRGB",
+     *  Michael Stokes (Hewlett-Packard), Matthew Anderson (Microsoft), 
+     * Srinivasan Chandrasekar (Microsoft), Ricardo Motta (Hewlett-Packard) 
+     * Version 1.10, November 5, 1996 
+     * This document is available: http://www.w3.org/Graphics/Color/sRGB
+     */
+    public static byte[] getFrom8lRGBtosRGB_LUT() {
+        if (from8lRGBtosRGB_LUT == null) {
+            from8lRGBtosRGB_LUT = new byte[256];
+            float v;
+            for (int i = 0; i < 256; i++) {
+                v = (float)i / 255;
+                v = (v <= 0.04045f) ? v / 12.92f :
+                    (float) Math.pow((v + 0.055) / 1.055, 2.4);
+                from8lRGBtosRGB_LUT[i] = (byte) Math.round(v * 255.0f);
+            }
+        }
+        return from8lRGBtosRGB_LUT;
+    }
+
+    public static byte[] getFrom16lRGBtosRGB_LUT() {
+        if (from16lRGBtosRGB_LUT == null) {
+            from16lRGBtosRGB_LUT = new byte[65536];
+            float v;
+            for (int i = 0; i < 65536; i++) {
+                v = (float) i / 65535;
+                v = (v <= 0.04045f) ? v / 12.92f :
+                    (float) Math.pow((v + 0.055) / 1.055, 2.4);
+                from16lRGBtosRGB_LUT[i] = (byte) Math.round(v * 255.0f);
+            }
+        }
+        return from16lRGBtosRGB_LUT;
+    }
+
+    public static byte[] getFromsRGBto8lRGB_LUT() {
+        if (fromsRGBto8lRGB_LUT == null) {
+            fromsRGBto8lRGB_LUT = new byte[256];
+            float v;
+            for (int i = 0; i < 256; i++) {
+                v = (float) i / 255;
+                v = (v <= 0.0031308f) ? v * 12.92f :
+                    ((float) Math.pow(v, 1.0 / 2.4)) * 1.055f - 0.055f;
+                fromsRGBto8lRGB_LUT[i] = (byte) Math.round(v * 255.0f);
+            }
+        }
+        return fromsRGBto8lRGB_LUT;
+    }
+
+    public static short[] getFromsRGBto16lRGB_LUT() {
+        if (fromsRGBto16lRGB_LUT == null) {
+            fromsRGBto16lRGB_LUT = new short[256];
+            float v;
+            for (int i = 0; i < 256; i++) {
+                v = (float) i / 255;
+                v = (v <= 0.0031308f) ? v * 12.92f :
+                    ((float) Math.pow(v, 1.0 / 2.4)) * 1.055f - 0.055f;
+                fromsRGBto16lRGB_LUT[i] = (short) Math.round(v * 65535.0f);
+            }
+        }
+        return fromsRGBto16lRGB_LUT;
+    }
+
+    public static byte[] getsRGBLUT(int bits) {
+        if (bits < 1) return null;
+        int idx = bits -1;
+        if(fromsRGBto8sRGB_LUTs == null) fromsRGBto8sRGB_LUTs = new byte[16][];
+
+        if(fromsRGBto8sRGB_LUTs[idx] == null){
+            fromsRGBto8sRGB_LUTs[idx] = createLUT(bits);
+        }
+        return fromsRGBto8sRGB_LUTs[idx];
+    }
+
+    private static byte[] createLUT(int bits) {
+        int lutSize = (1 << bits);
+        byte lut[] = new byte[lutSize];
+        for (int i = 0; i < lutSize; i++) {
+            lut[i] = (byte) (255.0f / (lutSize - 1) + 0.5f);
+        }
+        return lut;
+    }
+
+    public static boolean is_LINEAR_RGB_CS(ColorSpace cs) {
+        return (cs == LINEAR_RGB_CS);
+    }
+
+    public static boolean is_LINEAR_GRAY_CS(ColorSpace cs) {
+        return (cs == LINEAR_GRAY_CS);
+    }
+
+    public static boolean is_sRGB_CS(ColorSpace cs) {
+        return (cs == sRGB_CS);
+    }
+
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/color/NativeCMM.java b/awt/org/apache/harmony/awt/gl/color/NativeCMM.java
new file mode 100644
index 0000000..7f8c7e6
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/NativeCMM.java
@@ -0,0 +1,92 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ICC_Profile;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+
+/**
+ * This class is a wrapper for the native CMM library
+ */
+public class NativeCMM {
+
+    /**
+     * Storage for profile handles, since they are private
+     * in ICC_Profile, but we need access to them.
+     */
+    private static HashMap<ICC_Profile, Long> profileHandles = new HashMap<ICC_Profile, Long>();
+
+    private static boolean isCMMLoaded;
+
+    public static void addHandle(ICC_Profile key, long handle) {
+        profileHandles.put(key, new Long(handle));
+    }
+
+    public static void removeHandle(ICC_Profile key) {
+        profileHandles.remove(key);
+    }
+
+    public static long getHandle(ICC_Profile key) {
+        return profileHandles.get(key).longValue();
+    }
+
+    /* ICC profile management */
+    public static native long cmmOpenProfile(byte[] data);
+    public static native void cmmCloseProfile(long profileID);
+    public static native int cmmGetProfileSize(long profileID);
+    public static native void cmmGetProfile(long profileID, byte[] data);
+    public static native int cmmGetProfileElementSize(long profileID, int signature);
+    public static native void cmmGetProfileElement(long profileID, int signature,
+                                           byte[] data);
+    public static native void cmmSetProfileElement(long profileID, int tagSignature,
+                                           byte[] data);
+
+
+    /* ICC transforms */
+    public static native long cmmCreateMultiprofileTransform(
+            long[] profileHandles,
+            int[] renderingIntents
+        );
+    public static native void cmmDeleteTransform(long transformHandle);
+    public static native void cmmTranslateColors(long transformHandle,
+            NativeImageFormat src,
+            NativeImageFormat dest);
+
+    static void loadCMM() {
+        if (!isCMMLoaded) {
+            AccessController.doPrivileged(
+                  new PrivilegedAction<Void>() {
+                    public Void run() {
+                        System.loadLibrary("lcmm"); //$NON-NLS-1$
+                        return null;
+                    }
+            } );
+            isCMMLoaded = true;
+        }
+    }
+
+    /* load native CMM library */
+    static {
+        loadCMM();
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/color/NativeImageFormat.java b/awt/org/apache/harmony/awt/gl/color/NativeImageFormat.java
new file mode 100644
index 0000000..9594047
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/NativeImageFormat.java
@@ -0,0 +1,642 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * This class converts java color/sample models to the LCMS pixel formats.
+ * It also encapsulates all the information about the image format, which native CMM
+ * needs to have in order to read/write data.
+ *
+ * At present planar formats (multiple bands) are not supported
+ * and they are handled as a common (custom) case.
+ * Samples other than 1 - 7 bytes and multiple of 8 bits are
+ * also handled as custom (and won't be supported in the nearest future).
+ */
+class NativeImageFormat {
+    //////////////////////////////////////////////
+    //  LCMS Pixel types
+    private static final int PT_ANY = 0;    // Don't check colorspace
+    // 1 & 2 are reserved
+    private static final int PT_GRAY     = 3;
+    private static final int PT_RGB      = 4;
+    // Skipping other since we don't use them here
+    ///////////////////////////////////////////////
+
+    // Conversion of predefined BufferedImage formats to LCMS formats
+    private static final int INT_RGB_LCMS_FMT =
+        colorspaceSh(PT_RGB)|
+        extraSh(1)|
+        channelsSh(3)|
+        bytesSh(1)|
+        doswapSh(1)|
+        swapfirstSh(1);
+
+    private static final int INT_ARGB_LCMS_FMT = INT_RGB_LCMS_FMT;
+
+    private static final int INT_BGR_LCMS_FMT =
+        colorspaceSh(PT_RGB)|
+        extraSh(1)|
+        channelsSh(3)|
+        bytesSh(1);
+
+    private static final int THREE_BYTE_BGR_LCMS_FMT =
+        colorspaceSh(PT_RGB)|
+        channelsSh(3)|
+        bytesSh(1)|
+        doswapSh(1);
+
+    private static final int FOUR_BYTE_ABGR_LCMS_FMT =
+        colorspaceSh(PT_RGB)|
+        extraSh(1)|
+        channelsSh(3)|
+        bytesSh(1)|
+        doswapSh(1);
+
+    private static final int BYTE_GRAY_LCMS_FMT =
+        colorspaceSh(PT_GRAY)|
+        channelsSh(1)|
+        bytesSh(1);
+
+    private static final int USHORT_GRAY_LCMS_FMT =
+        colorspaceSh(PT_GRAY)|
+        channelsSh(1)|
+        bytesSh(2);
+
+    // LCMS format packed into 32 bit value. For description
+    // of this format refer to LCMS documentation.
+    private int cmmFormat = 0;
+
+    // Dimensions
+    private int rows = 0;
+    private int cols = 0;
+
+    //  Scanline may contain some padding in the end
+    private int scanlineStride = -1;
+
+    private Object imageData;
+    // It's possible to have offset from the beginning of the array
+    private int dataOffset;
+
+    // Has the image alpha channel? If has - here its band band offset goes
+    private int alphaOffset = -1;
+
+    // initializes proper field IDs
+    private static native void initIDs();
+
+    static {
+        NativeCMM.loadCMM();
+        initIDs();
+    }
+
+    ////////////////////////////////////
+    // LCMS image format encoders
+    ////////////////////////////////////
+    private static int colorspaceSh(int s) {
+        return (s << 16);
+    }
+
+    private static int swapfirstSh(int s) {
+        return (s << 14);
+    }
+
+    private static int flavorSh(int s) {
+        return (s << 13);
+    }
+
+    private static int planarSh(int s) {
+        return (s << 12);
+    }
+
+    private static int endianSh(int s) {
+        return (s << 11);
+    }
+
+    private static int doswapSh(int s) {
+        return (s << 10);
+    }
+
+    private static int extraSh(int s) {
+        return (s << 7);
+    }
+
+    private static int channelsSh(int s) {
+        return (s << 3);
+    }
+
+    private static int bytesSh(int s) {
+        return s;
+    }
+    ////////////////////////////////////
+    // End of LCMS image format encoders
+    ////////////////////////////////////
+
+    // Accessors
+    Object getChannelData() {
+        return imageData;
+    }
+
+    int getNumCols() {
+        return cols;
+    }
+
+    int getNumRows() {
+        return rows;
+    }
+
+    // Constructors
+    public NativeImageFormat() {
+    }
+
+    /**
+     * Simple image layout for common case with
+     * not optimized workflow.
+     *
+     * For hifi colorspaces with 5+ color channels imgData
+     * should be <code>byte</code> array.
+     *
+     * For common colorspaces with up to 4 color channels it
+     * should be <code>short</code> array.
+     *
+     * Alpha channel is handled by caller, not by CMS.
+     *
+     * Color channels are in their natural order (not BGR but RGB).
+     *
+     * @param imgData - array of <code>byte</code> or <code>short</code>
+     * @param nChannels - number of channels
+     * @param nRows - number of scanlines in the image
+     * @param nCols - number of pixels in one row of the image
+     */
+    public NativeImageFormat(Object imgData, int nChannels, int nRows, int nCols) {
+        if (imgData instanceof short[]) {
+            cmmFormat |= bytesSh(2);
+        }
+        else if (imgData instanceof byte[]) {
+            cmmFormat |= bytesSh(1);
+        }
+        else
+            // awt.47=First argument should be byte or short array
+            throw new IllegalArgumentException(Messages.getString("awt.47")); //$NON-NLS-1$
+
+        cmmFormat |= channelsSh(nChannels);
+
+        rows = nRows;
+        cols = nCols;
+
+        imageData = imgData;
+
+        dataOffset = 0;
+    }
+
+    /**
+     * Deduces image format from the buffered image type
+     * or color and sample models.
+     * @param bi - image
+     * @return image format object
+     */
+    public static NativeImageFormat createNativeImageFormat(BufferedImage bi) {
+        NativeImageFormat fmt = new NativeImageFormat();
+
+        switch (bi.getType()) {
+            case BufferedImage.TYPE_INT_RGB: {
+                fmt.cmmFormat = INT_RGB_LCMS_FMT;
+                break;
+            }
+
+            case BufferedImage.TYPE_INT_ARGB:
+            case BufferedImage.TYPE_INT_ARGB_PRE: {
+                fmt.cmmFormat = INT_ARGB_LCMS_FMT;
+                fmt.alphaOffset = 3;
+                break;
+            }
+
+            case BufferedImage.TYPE_INT_BGR: {
+                fmt.cmmFormat = INT_BGR_LCMS_FMT;
+                break;
+            }
+
+            case BufferedImage.TYPE_3BYTE_BGR: {
+                fmt.cmmFormat = THREE_BYTE_BGR_LCMS_FMT;
+                break;
+            }
+
+            case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+            case BufferedImage.TYPE_4BYTE_ABGR: {
+                fmt.cmmFormat = FOUR_BYTE_ABGR_LCMS_FMT;
+                fmt.alphaOffset = 0;
+                break;
+            }
+
+            case BufferedImage.TYPE_BYTE_GRAY: {
+                fmt.cmmFormat = BYTE_GRAY_LCMS_FMT;
+                break;
+            }
+
+            case BufferedImage.TYPE_USHORT_GRAY: {
+                fmt.cmmFormat = USHORT_GRAY_LCMS_FMT;
+                break;
+            }
+
+            case BufferedImage.TYPE_BYTE_BINARY:
+            case BufferedImage.TYPE_USHORT_565_RGB:
+            case BufferedImage.TYPE_USHORT_555_RGB:
+            case BufferedImage.TYPE_BYTE_INDEXED: {
+                // A bunch of unsupported formats
+                return null;
+            }
+
+            default:
+                break; // Try to look at sample model and color model
+        }
+
+
+        if (fmt.cmmFormat == 0) {
+            ColorModel cm = bi.getColorModel();
+            SampleModel sm = bi.getSampleModel();
+
+            if (sm instanceof ComponentSampleModel) {
+                ComponentSampleModel csm = (ComponentSampleModel) sm;
+                fmt.cmmFormat = getFormatFromComponentModel(csm, cm.hasAlpha());
+                fmt.scanlineStride = calculateScanlineStrideCSM(csm, bi.getRaster());
+            } else if (sm instanceof SinglePixelPackedSampleModel) {
+                SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+                fmt.cmmFormat = getFormatFromSPPSampleModel(sppsm, cm.hasAlpha());
+                fmt.scanlineStride = calculateScanlineStrideSPPSM(sppsm, bi.getRaster());
+            }
+
+            if (cm.hasAlpha())
+                fmt.alphaOffset = calculateAlphaOffset(sm, bi.getRaster());
+        }
+
+        if (fmt.cmmFormat == 0)
+            return null;
+
+        if (!fmt.setImageData(bi.getRaster().getDataBuffer())) {
+            return null;
+        }
+
+        fmt.rows = bi.getHeight();
+        fmt.cols = bi.getWidth();
+
+        fmt.dataOffset = bi.getRaster().getDataBuffer().getOffset();
+
+        return fmt;
+    }
+
+    /**
+     * Deduces image format from the raster sample model.
+     * @param r - raster
+     * @return image format object
+     */
+    public static NativeImageFormat createNativeImageFormat(Raster r) {
+        NativeImageFormat fmt = new NativeImageFormat();
+        SampleModel sm = r.getSampleModel();
+
+        // Assume that there's no alpha
+        if (sm instanceof ComponentSampleModel) {
+            ComponentSampleModel csm = (ComponentSampleModel) sm;
+            fmt.cmmFormat = getFormatFromComponentModel(csm, false);
+            fmt.scanlineStride = calculateScanlineStrideCSM(csm, r);
+        } else if (sm instanceof SinglePixelPackedSampleModel) {
+            SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+            fmt.cmmFormat = getFormatFromSPPSampleModel(sppsm, false);
+            fmt.scanlineStride = calculateScanlineStrideSPPSM(sppsm, r);
+        }
+
+        if (fmt.cmmFormat == 0)
+            return null;
+
+        fmt.cols = r.getWidth();
+        fmt.rows = r.getHeight();
+        fmt.dataOffset = r.getDataBuffer().getOffset();
+
+        if (!fmt.setImageData(r.getDataBuffer()))
+            return null;
+
+        return fmt;
+    }
+
+    /**
+     * Obtains LCMS format from the component sample model
+     * @param sm - sample model
+     * @param hasAlpha - true if there's an alpha channel
+     * @return LCMS format
+     */
+    private static int getFormatFromComponentModel(ComponentSampleModel sm, boolean hasAlpha) {
+        // Multiple data arrays (banks) not supported
+        int bankIndex = sm.getBankIndices()[0];
+        for (int i=1; i < sm.getNumBands(); i++) {
+            if (sm.getBankIndices()[i] != bankIndex) {
+                return 0;
+            }
+        }
+
+        int channels = hasAlpha ? sm.getNumBands()-1 : sm.getNumBands();
+        int extra = hasAlpha ? 1 : 0;
+        int bytes = 1;
+        switch (sm.getDataType()) {
+            case DataBuffer.TYPE_BYTE:
+                bytes = 1; break;
+            case DataBuffer.TYPE_SHORT:
+            case DataBuffer.TYPE_USHORT:
+                bytes = 2; break;
+            case DataBuffer.TYPE_INT:
+                bytes = 4; break;
+            case DataBuffer.TYPE_DOUBLE:
+                bytes = 0; break;
+            default:
+                return 0; // Unsupported data type
+        }
+
+        int doSwap = 0;
+        int swapFirst = 0;
+        boolean knownFormat = false;
+
+        int i;
+
+        // "RGBA"
+        for (i=0; i < sm.getNumBands(); i++) {
+            if (sm.getBandOffsets()[i] != i) break;
+        }
+        if (i == sm.getNumBands()) { // Ok, it is it
+            doSwap = 0;
+            swapFirst = 0;
+            knownFormat = true;
+        }
+
+        // "ARGB"
+        if (!knownFormat) {
+            for (i=0; i < sm.getNumBands()-1; i++) {
+                if (sm.getBandOffsets()[i] != i+1) break;
+            }
+            if (sm.getBandOffsets()[i] == 0) i++;
+            if (i == sm.getNumBands()) { // Ok, it is it
+                doSwap = 0;
+                swapFirst = 1;
+                knownFormat = true;
+            }
+        }
+
+        // "BGRA"
+        if (!knownFormat) {
+            for (i=0; i < sm.getNumBands()-1; i++) {
+                if (sm.getBandOffsets()[i] != sm.getNumBands() - 2 - i) break;
+            }
+            if (sm.getBandOffsets()[i] == sm.getNumBands()-1) i++;
+            if (i == sm.getNumBands()) { // Ok, it is it
+                doSwap = 1;
+                swapFirst = 1;
+                knownFormat = true;
+            }
+        }
+
+        // "ABGR"
+        if (!knownFormat) {
+            for (i=0; i < sm.getNumBands(); i++) {
+                if (sm.getBandOffsets()[i] != sm.getNumBands() - 1 - i) break;
+            }
+            if (i == sm.getNumBands()) { // Ok, it is it
+                doSwap = 1;
+                swapFirst = 0;
+                knownFormat = true;
+            }
+        }
+
+        // XXX - Planar formats are not supported yet
+        if (!knownFormat)
+            return 0;
+
+        return
+            channelsSh(channels) |
+            bytesSh(bytes) |
+            extraSh(extra) |
+            doswapSh(doSwap) |
+            swapfirstSh(swapFirst);
+    }
+
+    /**
+     * Obtains LCMS format from the single pixel packed sample model
+     * @param sm - sample model
+     * @param hasAlpha - true if there's an alpha channel
+     * @return LCMS format
+     */
+    private static int getFormatFromSPPSampleModel(SinglePixelPackedSampleModel sm,
+            boolean hasAlpha) {
+        // Can we extract bytes?
+        int mask = sm.getBitMasks()[0] >>> sm.getBitOffsets()[0];
+        if (!(mask == 0xFF || mask == 0xFFFF || mask == 0xFFFFFFFF))
+            return 0;
+
+        // All masks are same?
+        for (int i = 1; i < sm.getNumBands(); i++) {
+            if ((sm.getBitMasks()[i] >>> sm.getBitOffsets()[i]) != mask)
+                return 0;
+        }
+
+        int pixelSize = 0;
+        // Check if data type is supported
+        if (sm.getDataType() == DataBuffer.TYPE_USHORT)
+            pixelSize = 2;
+        else if (sm.getDataType() == DataBuffer.TYPE_INT)
+            pixelSize = 4;
+        else
+            return 0;
+
+
+        int bytes = 0;
+        switch (mask) {
+            case 0xFF:
+                bytes = 1;
+                break;
+            case 0xFFFF:
+                bytes = 2;
+                break;
+            case 0xFFFFFFFF:
+                bytes = 4;
+                break;
+            default: return 0;
+        }
+
+
+        int channels = hasAlpha ? sm.getNumBands()-1 : sm.getNumBands();
+        int extra = hasAlpha ? 1 : 0;
+        extra +=  pixelSize/bytes - sm.getNumBands(); // Unused bytes?
+
+        // Form an ArrayList containing offset for each band
+        ArrayList<Integer> offsetsLst = new ArrayList<Integer>();
+        for (int k=0; k < sm.getNumBands(); k++) {
+            offsetsLst.add(new Integer(sm.getBitOffsets()[k]/(bytes*8)));
+        }
+
+        // Add offsets for unused space
+        for (int i=0; i<pixelSize/bytes; i++) {
+            if (offsetsLst.indexOf(new Integer(i)) < 0)
+                offsetsLst.add(new Integer(i));
+        }
+
+        int offsets[] = new int[pixelSize/bytes];
+        for (int i=0; i<offsetsLst.size(); i++) {
+            offsets[i] = offsetsLst.get(i).intValue();
+        }
+
+        int doSwap = 0;
+        int swapFirst = 0;
+        boolean knownFormat = false;
+
+        int i;
+
+        // "RGBA"
+        for (i=0; i < pixelSize; i++) {
+            if (offsets[i] != i) break;
+        }
+        if (i == pixelSize) { // Ok, it is it
+            doSwap = 0;
+            swapFirst = 0;
+            knownFormat = true;
+        }
+
+        // "ARGB"
+        if (!knownFormat) {
+            for (i=0; i < pixelSize-1; i++) {
+                if (offsets[i] != i+1) break;
+            }
+            if (offsets[i] == 0) i++;
+            if (i == pixelSize) { // Ok, it is it
+                doSwap = 0;
+                swapFirst = 1;
+                knownFormat = true;
+            }
+        }
+
+        // "BGRA"
+        if (!knownFormat) {
+            for (i=0; i < pixelSize-1; i++) {
+                if (offsets[i] != pixelSize - 2 - i) break;
+            }
+            if (offsets[i] == pixelSize-1) i++;
+            if (i == pixelSize) { // Ok, it is it
+                doSwap = 1;
+                swapFirst = 1;
+                knownFormat = true;
+            }
+        }
+
+        // "ABGR"
+        if (!knownFormat) {
+            for (i=0; i < pixelSize; i++) {
+                if (offsets[i] != pixelSize - 1 - i) break;
+            }
+            if (i == pixelSize) { // Ok, it is it
+                doSwap = 1;
+                swapFirst = 0;
+                knownFormat = true;
+            }
+        }
+
+        // XXX - Planar formats are not supported yet
+        if (!knownFormat)
+            return 0;
+
+        return
+            channelsSh(channels) |
+            bytesSh(bytes) |
+            extraSh(extra) |
+            doswapSh(doSwap) |
+            swapfirstSh(swapFirst);
+    }
+
+    /**
+     * Obtains data array from the DataBuffer object
+     * @param db - data buffer
+     * @return - true if successful
+     */
+    private boolean setImageData(DataBuffer db) {
+        AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+        try {
+            imageData = dbAccess.getData(db);
+        } catch (IllegalArgumentException e) {
+            return false; // Unknown data buffer type
+        }
+
+        return true;
+    }
+
+    /**
+     * Calculates scanline stride in bytes
+     * @param csm - component sample model
+     * @param r - raster
+     * @return scanline stride in bytes
+     */
+    private static int calculateScanlineStrideCSM(ComponentSampleModel csm, Raster r) {
+        if (csm.getScanlineStride() != csm.getPixelStride()*csm.getWidth()) {
+            int dataTypeSize = DataBuffer.getDataTypeSize(r.getDataBuffer().getDataType()) / 8;
+            return csm.getScanlineStride()*dataTypeSize;
+        }
+        return -1;
+    }
+
+    /**
+     * Calculates scanline stride in bytes
+     * @param sppsm - sample model
+     * @param r - raster
+     * @return scanline stride in bytes
+     */
+    private static int calculateScanlineStrideSPPSM(SinglePixelPackedSampleModel sppsm, Raster r) {
+        if (sppsm.getScanlineStride() != sppsm.getWidth()) {
+            int dataTypeSize = DataBuffer.getDataTypeSize(r.getDataBuffer().getDataType()) / 8;
+            return sppsm.getScanlineStride()*dataTypeSize;
+        }
+        return -1;
+    }
+
+    /**
+     * Calculates byte offset of the alpha channel from the beginning of the pixel data
+     * @param sm - sample model
+     * @param r - raster
+     * @return byte offset of the alpha channel
+     */
+    private static int calculateAlphaOffset(SampleModel sm, Raster r) {
+        if (sm instanceof ComponentSampleModel) {
+            ComponentSampleModel csm = (ComponentSampleModel) sm;
+            int dataTypeSize =
+                DataBuffer.getDataTypeSize(r.getDataBuffer().getDataType()) / 8;
+            return
+                csm.getBandOffsets()[csm.getBandOffsets().length - 1] * dataTypeSize;
+        } else if (sm instanceof SinglePixelPackedSampleModel) {
+            SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+            return sppsm.getBitOffsets()[sppsm.getBitOffsets().length - 1] / 8;
+        } else {
+            return -1; // No offset, don't copy alpha
+        }
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidFont.java b/awt/org/apache/harmony/awt/gl/font/AndroidFont.java
new file mode 100644
index 0000000..e8ad1bb
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidFont.java
@@ -0,0 +1,254 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.io.File;
+import java.util.Hashtable;
+import java.util.Locale;
+
+import org.apache.harmony.awt.gl.font.FontManager;
+import org.apache.harmony.awt.gl.font.FontPeerImpl;
+import org.apache.harmony.awt.gl.font.Glyph;
+import org.apache.harmony.awt.gl.font.LineMetricsImpl;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * Linux platform font peer implementation based on Xft and FreeType libraries.
+ */
+public class AndroidFont extends FontPeerImpl {
+
+    // Pairs of [begin, end],[..].. unicode ranges values 
+    private int[] fontUnicodeRanges;
+    
+    // table with loaded cached Glyphs
+    private Hashtable glyphs = new Hashtable();
+    
+    // X11 display value
+    private long display = 0;
+
+    // X11 screen value
+    private int screen = 0;
+    
+    public AndroidFont(String fontName, int fontStyle, int fontSize) {
+        /*
+         * Workaround : to initialize awt platform-dependent fields and libraries.
+         */
+        Toolkit.getDefaultToolkit();
+        this.name = fontName;
+        this.size = fontSize;
+        this.style = fontStyle;
+       
+        initAndroidFont();
+    }
+
+    /**
+     * Initializes some native dependent font information, e.g. number of glyphs, 
+     * font metrics, italic angle etc. 
+     */
+    public void initAndroidFont(){
+        this.nlm = new AndroidLineMetrics(this, null, " "); //$NON-NLS-1$
+        this.ascent = nlm.getLogicalAscent();
+        this.descent = nlm.getLogicalDescent();
+        this.height = nlm.getHeight();
+        this.leading = nlm.getLogicalLeading();
+        this.maxAdvance = nlm.getLogicalMaxCharWidth();
+
+        if (this.fontType == FontManager.FONT_TYPE_T1){
+            this.defaultChar = 1;
+        } else {
+            this.defaultChar = 0;
+        }
+
+        this.maxCharBounds = new Rectangle2D.Float(0, -nlm.getAscent(), nlm.getMaxCharWidth(), this.height);
+    }
+
+
+    public boolean canDisplay(char chr) {
+        // TODO: to improve performance there is a sence to implement get
+        // unicode ranges to check if char can be displayed without
+        // native calls in isGlyphExists() method
+
+        return isGlyphExists(chr);
+    }
+
+    public LineMetrics getLineMetrics(String str, FontRenderContext frc, AffineTransform at) {
+
+        // Initialize baseline offsets
+        nlm.getBaselineOffsets();
+        
+        LineMetricsImpl lm = (LineMetricsImpl)(this.nlm.clone());
+        lm.setNumChars(str.length());
+
+        if ((at != null) && (!at.isIdentity())){
+            lm.scale((float)at.getScaleX(), (float)at.getScaleY());
+        }
+
+        return lm;
+    }
+
+    public String getPSName() {
+        return psName;
+    }
+
+    public String getFamily(Locale l) {
+        // TODO: implement localized family
+        if (fontType == FontManager.FONT_TYPE_TT){
+            return this.getFamily();
+        }
+
+        return this.fontFamilyName;
+    }
+
+    public String getFontName(Locale l) {
+        if ((pFont == 0) || (this.fontType == FontManager.FONT_TYPE_T1)){
+            return this.name;
+        }
+
+        return this.getFontName();
+    }
+
+
+    public int getMissingGlyphCode() {
+        return getDefaultGlyph().getGlyphCode();
+    }
+
+    public Glyph getGlyph(char index) {
+        Glyph result = null;
+
+        Object key = new Integer(index);
+        if (glyphs.containsKey(key)) {
+            result = (Glyph) glyphs.get(key);
+        } else {
+            if (this.addGlyph(index)) {
+                result = (Glyph) glyphs.get(key);
+            } else {
+                result = this.getDefaultGlyph();
+            }
+        }
+
+        return result;
+    }
+
+    public Glyph getDefaultGlyph() {
+    	throw new RuntimeException("DefaultGlyphs not implemented!");
+    }
+
+    /**
+     * Disposes native font handle. If this font peer was created from InputStream 
+     * temporary created font resource file is deleted.
+     */
+    public void dispose(){
+        String tempDirName;
+        if (pFont != 0){
+            pFont = 0;
+
+            if (isCreatedFromStream()) {
+                File fontFile = new File(getTempFontFileName());
+                tempDirName = fontFile.getParent();
+                fontFile.delete();
+            }
+        }
+    }
+
+    /**
+     * Add glyph to cached Glyph objects in this LinuxFont object.
+     * 
+     * @param uChar the specified character
+     * @return true if glyph of the specified character exists in this
+     * LinuxFont or this character is escape sequence character.
+     */
+    public boolean addGlyph(char uChar) {
+    	throw new RuntimeException("Not implemented!");    	
+    }
+
+   /**
+    * Adds range of existing glyphs to this LinuxFont object
+    * 
+    * @param uFirst the lowest range's bound, inclusive 
+    * @param uLast the highest range's bound, exclusive
+    */
+    public void addGlyphs(char uFirst, char uLast) {
+    	
+        char index = uFirst;
+        if (uLast < uFirst) {
+            // awt.09=min range bound value is grater than max range bound
+            throw new IllegalArgumentException(Messages.getString("awt.09")); //$NON-NLS-1$
+        }
+        while (index < uLast) {
+            addGlyph(index);
+            index++;
+        }
+        
+    }
+
+    /**
+     * Returns true if specified character has corresopnding glyph, false otherwise.  
+     * 
+     * @param uIndex specified char
+     */
+    public boolean isGlyphExists(char uIndex) {
+    	throw new RuntimeException("DefaultGlyphs not implemented!");
+    }
+
+    /**
+     *  Returns an array of unicode ranges that are supported by this LinuxFont. 
+     */
+    public int[] getUnicodeRanges() {
+        int[] ranges = new int[fontUnicodeRanges.length];
+        System.arraycopy(fontUnicodeRanges, 0, ranges, 0,
+                fontUnicodeRanges.length);
+
+        return ranges;
+    }
+
+    /**
+     * Return Font object if it was successfully embedded in System
+     */
+    public static Font embedFont(String absolutePath){
+    	throw new RuntimeException("embedFont not implemented!");
+    }
+
+    public String getFontName(){
+        if ((pFont != 0) && (faceName == null)){
+            if (this.fontType == FontManager.FONT_TYPE_T1){
+                faceName = getFamily();
+            }
+        }
+        return faceName;
+    }
+
+    public String getFamily() {
+        return fontFamilyName;
+    }
+    
+    /**
+     * Returns initiated FontExtraMetrics instance of this WindowsFont.
+     */
+    public FontExtraMetrics getExtraMetrics(){
+    	throw new RuntimeException("Not implemented!");
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidFontManager.java b/awt/org/apache/harmony/awt/gl/font/AndroidFontManager.java
new file mode 100644
index 0000000..063a256
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidFontManager.java
@@ -0,0 +1,277 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.peer.FontPeer;
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.harmony.awt.gl.font.FontManager;
+import org.apache.harmony.awt.gl.font.FontProperty;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+import android.util.Log;
+
+public class AndroidFontManager extends FontManager {
+
+    // set of all available faces supported by a system
+    String faces[];
+
+    // weight names according to xlfd structure
+    public static final String[] LINUX_WEIGHT_NAMES = {
+            "black", "bold", "demibold", "medium", "light" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+    };
+
+    // slant names according to xlfd structure
+    public static final String[] LINUX_SLANT_NAMES = {
+            "i", "o", "r" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    };
+
+    /** Singleton AndroidFontManager instance */
+    public static final AndroidFontManager inst = new AndroidFontManager();
+
+    private AndroidFontManager() {
+        super();
+        faces = new String[] {/*"PLAIN",*/ "NORMAL", "BOLD", "ITALIC", "BOLDITALIC"};
+        initFontProperties();
+    }
+
+    public void initLCIDTable(){
+    	throw new RuntimeException("Not implemented!");
+    }
+
+    /**
+     * Returns temporary File object to store data from InputStream.
+     * This File object saved to `~/.fonts/' folder that is included in the 
+     * list of folders searched for font files, and this is where user-specific 
+     * font files should be installed.
+     */
+    public File getTempFontFile()throws IOException{
+        File fontFile = File.createTempFile("jFont", ".ttf", new File(System.getProperty("user.home") +"/.fonts")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+        fontFile.deleteOnExit();
+
+        return fontFile;
+    }
+
+    /**
+     * Initializes fProperties array field for the current system configuration font
+     * property file.
+     * 
+     * RuntimeException is thrown if font property contains incorrect format of 
+     * xlfd string.
+     * 
+     * @return true is success, false if font property doesn't exist or doesn't
+     * contain roperties. 
+     */
+    public boolean initFontProperties(){
+        File fpFile = getFontPropertyFile();
+        if (fpFile == null){
+            return false;
+        }
+
+        Properties props = getProperties(fpFile);
+        if (props == null){
+            return false;
+        }
+
+        for (int i=0; i < LOGICAL_FONT_NAMES.length; i++){
+            String lName = LOGICAL_FONT_NAMES[i];
+            for (int j=0; j < STYLE_NAMES.length; j++){
+                String styleName = STYLE_NAMES[j];
+                Vector propsVector = new Vector();
+
+                // Number of entries for a logical font
+                int numComp = 0;
+                // Is more entries for this style and logical font name left
+                boolean moreEntries = true;
+                String value = null;
+
+                while(moreEntries){
+                    // Component Font Mappings property name
+                    String property = FONT_MAPPING_KEYS[0].replaceAll("LogicalFontName", lName).replaceAll("StyleName", styleName).replaceAll("ComponentIndex", String.valueOf(numComp)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                    value = props.getProperty(property);
+
+                    // If the StyleName is omitted, it's assumed to be plain
+                    if ((j == 0) && (value == null)){
+                        property = FONT_MAPPING_KEYS[1].replaceAll("LogicalFontName", lName).replaceAll("ComponentIndex", String.valueOf(numComp)); //$NON-NLS-1$ //$NON-NLS-2$
+                        value = props.getProperty(property);
+                    }
+
+                    if (value != null){
+                        String[] fields = parseXLFD(value);
+
+                        if (fields == null){
+                            // awt.08=xfld parse string error: {0}
+                            throw new RuntimeException(Messages.getString("awt.08", value)); //$NON-NLS-1$
+                        }
+                        
+                        String fontName = fields[1];
+                        String weight = fields[2];
+                        String italic = fields[3];
+
+                        int style = getBoldStyle(weight) | getItalicStyle(italic);
+                        // Component Font Character Encodings property value
+                        String encoding = props.getProperty(FONT_CHARACTER_ENCODING.replaceAll("LogicalFontName", lName).replaceAll("ComponentIndex", String.valueOf(numComp))); //$NON-NLS-1$ //$NON-NLS-2$
+
+                        // Exclusion Ranges property value
+                        String exclString = props.getProperty(EXCLUSION_RANGES.replaceAll("LogicalFontName", lName).replaceAll("ComponentIndex", String.valueOf(numComp))); //$NON-NLS-1$ //$NON-NLS-2$
+                        int[] exclRange = parseIntervals(exclString);
+
+                        FontProperty fp = new AndroidFontProperty(lName, styleName, null, fontName, value, style, exclRange, encoding);
+
+                        propsVector.add(fp);
+                        numComp++;
+                    } else {
+                        moreEntries = false;
+                    }
+                }
+                fProperties.put(LOGICAL_FONT_NAMES[i] + "." + j, propsVector); //$NON-NLS-1$
+            }
+        }
+
+        return true;
+
+    }
+
+    /**
+     * Returns style according to the xlfd weight string.
+     * If weight string is incorrect returned value is Font.PLAIN
+     * 
+     * @param str weight name String
+     */
+    private int getBoldStyle(String str){
+        for (int i = 0; i < LINUX_WEIGHT_NAMES.length;i++){
+            if (str.equalsIgnoreCase(LINUX_WEIGHT_NAMES[i])){
+                return (i < 3) ? Font.BOLD : Font.PLAIN;
+            }
+        }
+        return Font.PLAIN;
+    }
+    
+    /**
+     * Returns style according to the xlfd slant string.
+     * If slant string is incorrect returned value is Font.PLAIN
+     * 
+     * @param str slant name String
+     */
+    private int getItalicStyle(String str){
+        for (int i = 0; i < LINUX_SLANT_NAMES.length;i++){
+            if (str.equalsIgnoreCase(LINUX_SLANT_NAMES[i])){
+                return (i < 2) ? Font.ITALIC : Font.PLAIN;
+            }
+        }
+        return Font.PLAIN;
+    }
+
+    /**
+     * Parse xlfd string and returns array of Strings with separate xlfd 
+     * elements.<p>
+     * 
+     * xlfd format:
+     *      -Foundry-Family-Weight-Slant-Width-Style-PixelSize-PointSize-ResX-ResY-Spacing-AvgWidth-Registry-Encoding
+     * @param xlfd String parameter in xlfd format
+     */
+    public static String[] parseXLFD(String xlfd){
+        int fieldsCount = 14;
+        String fieldsDelim = "-"; //$NON-NLS-1$
+        String[] res = new String[fieldsCount];
+        if (!xlfd.startsWith(fieldsDelim)){
+            return null;
+        }
+
+        xlfd = xlfd.substring(1);
+        int i=0;
+        int pos;
+        for (i=0; i < fieldsCount-1; i++){
+            pos = xlfd.indexOf(fieldsDelim);
+            if (pos != -1){
+                res[i] = xlfd.substring(0, pos);
+                xlfd = xlfd.substring(pos + 1);
+            } else {
+                return null;
+            }
+        }
+        pos = xlfd.indexOf(fieldsDelim);
+
+        // check if no fields left
+        if(pos != -1){
+            return null;
+        }
+        res[fieldsCount-1] = xlfd;
+
+        return res;
+    }
+
+    public int getFaceIndex(String faceName){
+    	
+        for (int i = 0; i < faces.length; i++) {
+            if(faces[i].equals(faceName)){
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    public String[] getAllFamilies(){
+        if (allFamilies == null){
+        	allFamilies = new String[]{"sans-serif", "serif", "monospace"};
+        }
+        return allFamilies;
+    }
+
+    public Font[] getAllFonts(){
+        Font[] fonts = new Font[faces.length];
+        for (int i =0; i < fonts.length;i++){
+            fonts[i] = new Font(faces[i], Font.PLAIN, 1);
+        }
+        return fonts;
+    }
+
+    public FontPeer createPhysicalFontPeer(String name, int style, int size) {
+        AndroidFont peer;
+        int familyIndex = getFamilyIndex(name);
+        if (familyIndex != -1){
+            // !! we use family names from the list with cached families because 
+            // they are differ from the family names in xlfd structure, in xlfd 
+            // family names mostly in lower case.
+            peer = new AndroidFont(getFamily(familyIndex), style, size);
+            peer.setFamily(getFamily(familyIndex));
+            return peer;
+        }
+        int faceIndex = getFaceIndex(name); 
+        if (faceIndex != -1){
+
+            peer = new AndroidFont(name, style, size);
+            return peer;
+        }
+        
+        return null;
+    }
+
+    public FontPeer createDefaultFont(int style, int size) {
+    	Log.i("DEFAULT FONT", Integer.toString(style));
+        return new AndroidFont(DEFAULT_NAME, style, size);
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidFontProperty.java b/awt/org/apache/harmony/awt/gl/font/AndroidFontProperty.java
new file mode 100644
index 0000000..0cfdc43
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidFontProperty.java
@@ -0,0 +1,81 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ *
+ */
+package org.apache.harmony.awt.gl.font;
+
+/**
+ * Android FontProperty implementation, applicable for Linux formats of 
+ * font property files. 
+ */
+public class AndroidFontProperty extends FontProperty {
+    
+    /** xlfd string that is applicable for Linux font.properties */ 
+    String xlfd;
+
+    /** logical name of the font corresponding to this FontProperty */ 
+    String logicalName;
+    
+    /** style name of the font corresponding to this FontProperty */
+    String styleName;
+
+    public AndroidFontProperty(String _logicalName, String _styleName, String _fileName, String _name, String _xlfd, int _style, int[] exclusionRange, String _encoding){
+        this.logicalName = _logicalName;
+        this.styleName = _styleName;
+        this.name = _name;
+        this.encoding = _encoding;
+        this.exclRange = exclusionRange;
+        this.fileName = _fileName;
+        this.xlfd = _xlfd;
+        this.style = _style;
+    }
+    
+    /**
+     * Returns logical name of the font corresponding to this FontProperty. 
+     */
+    public String getLogicalName(){
+        return logicalName;
+    }
+    
+    /**
+     * Returns style name of the font corresponding to this FontProperty. 
+     */
+    public String getStyleName(){
+        return styleName;
+    }
+    
+    /**
+     * Returns xlfd string of this FontProperty. 
+     */
+    public String getXLFD(){
+        return xlfd;
+    }
+
+    public String toString(){
+        return new String(this.getClass().getName() +
+                "[name=" + name + //$NON-NLS-1$
+                ",fileName="+ fileName + //$NON-NLS-1$
+                ",Charset=" + encoding + //$NON-NLS-1$
+                ",exclRange=" + exclRange + //$NON-NLS-1$
+                ",xlfd=" + xlfd + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java b/awt/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java
new file mode 100644
index 0000000..4ce5aed
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java
@@ -0,0 +1,219 @@
+package org.apache.harmony.awt.gl.font;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.Font;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import android.util.Log;
+import android.graphics.Path;
+
+public class AndroidGlyphVector extends GlyphVector {
+
+    // array of chars defined in constructor
+    public char[] charVector;
+
+    // array of Glyph objects, that describe information about glyphs
+    public Glyph[] vector;
+
+    // array of default positions of glyphs in GlyphVector
+    // without applying GlyphVector's transform
+    float[] defaultPositions;
+
+    // array of logical positions of glyphs in GlyphVector
+
+    float[] logicalPositions;
+
+    // array of visual (real) positions of glyphs in GlyphVector
+    public float[] visualPositions;
+
+    // FontRenderContext for this vector.
+    protected FontRenderContext vectorFRC;
+
+    // layout flags mask
+    protected int layoutFlags = 0;
+
+    // array of cached glyph outlines 
+    protected Shape[] gvShapes;
+
+    FontPeerImpl peer;
+
+    // font corresponding to the GlyphVector 
+    Font font;
+
+    // ascent of the font
+    float ascent;
+
+    // height of the font
+    float height;
+    
+    // leading of the font
+    float leading;
+    
+    // descent of the font
+    float descent;
+
+    // transform of the GlyphVector
+    AffineTransform transform;
+
+    @SuppressWarnings("deprecation")
+    public AndroidGlyphVector(char[] chars, FontRenderContext frc, Font fnt,
+            int flags) {
+        int len = chars.length;
+        this.font = fnt;
+        LineMetricsImpl lmImpl = (LineMetricsImpl)fnt.getLineMetrics(String.valueOf(chars), frc);     	
+        this.ascent = lmImpl.getAscent();
+        this.height = lmImpl.getHeight();
+        this.leading = lmImpl.getLeading();
+        this.descent = lmImpl.getDescent();
+        this.charVector = chars;
+        this.vectorFRC = frc;
+    }
+
+    public AndroidGlyphVector(char[] chars, FontRenderContext frc, Font fnt) {
+        this(chars, frc, fnt, 0);
+    }
+
+    public AndroidGlyphVector(String str, FontRenderContext frc, Font fnt) {
+        this(str.toCharArray(), frc, fnt, 0);
+    }
+
+    public AndroidGlyphVector(String str, FontRenderContext frc, Font fnt, int flags) {
+        this(str.toCharArray(), frc, fnt, flags);
+    }
+
+	@Override
+	public boolean equals(GlyphVector glyphVector) {
+		return false;
+	}
+
+	public char[] getGlyphs() {
+		return this.charVector;
+	}
+	
+	@Override
+	public Font getFont() {
+		return this.font;
+	}
+
+	@Override
+	public FontRenderContext getFontRenderContext() {
+		return this.vectorFRC;
+	}
+
+	@Override
+	public int getGlyphCode(int glyphIndex) {
+		return charVector[glyphIndex];
+	}
+
+	@Override
+	public int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
+			int[] codeReturn) {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public Shape getGlyphLogicalBounds(int glyphIndex) {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public GlyphMetrics getGlyphMetrics(int glyphIndex) {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	public Path getAndroidGlyphOutline(int glyphIndex) {
+		AndroidGraphics2D g = AndroidGraphics2D.getInstance();
+        Path path = new Path();
+        char tmp[] = new char[1];
+        tmp[0] = charVector[glyphIndex];
+        ((AndroidGraphics2D)g).getAndroidPaint().getTextPath(new String(tmp), 0, 1, 0, 0, path);
+        return path;
+	}
+	
+	@Override
+	public Shape getGlyphOutline(int glyphIndex) {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public Point2D getGlyphPosition(int glyphIndex) {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
+			float[] positionReturn) {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public AffineTransform getGlyphTransform(int glyphIndex) {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public Shape getGlyphVisualBounds(int glyphIndex) {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public Rectangle2D getLogicalBounds() {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public int getNumGlyphs() {
+		return charVector.length;
+	}
+
+	@Override
+	public Shape getOutline(float x, float y) {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public Shape getOutline() {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	public Path getAndroidOutline() {
+		AndroidGraphics2D g = AndroidGraphics2D.getInstance();
+        Path path = new Path();
+        ((AndroidGraphics2D)g).getAndroidPaint().getTextPath(new String(charVector), 0, charVector.length, 0, 0, path);
+        return path;
+	}
+
+	@Override
+	public Rectangle2D getVisualBounds() {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public void performDefaultLayout() {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public void setGlyphPosition(int glyphIndex, Point2D newPos) {
+		throw new RuntimeException("Not implemented!");
+	}
+
+	@Override
+	public void setGlyphTransform(int glyphIndex, AffineTransform trans) {
+		throw new RuntimeException("Not implemented!");
+	}
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java b/awt/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java
new file mode 100644
index 0000000..f37be6d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java
@@ -0,0 +1,120 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.FontRenderContext;
+import org.apache.harmony.awt.gl.font.LineMetricsImpl;
+
+
+/**
+ *
+ * Linux implementation of LineMetrics class
+ */
+public class AndroidLineMetrics extends LineMetricsImpl {
+    
+    /**
+     * Constructor
+     */
+    public AndroidLineMetrics(    AndroidFont fnt,
+                                FontRenderContext frc,
+                                String str){
+        numChars = str.length();
+        baseLineIndex = 0;
+
+        ascent = fnt.ascent;    // Ascent of the font
+        descent = -fnt.descent;  // Descent of the font
+        leading = fnt.leading;  // External leading
+
+        height = ascent + descent + leading;    // Height of the font ( == (ascent + descent + leading))
+        underlineThickness = 0.0f;
+        underlineOffset = 0.0f;
+        strikethroughThickness = 0.0f;
+        strikethroughOffset = 0.0f;
+        maxCharWidth = 0.0f;
+
+        //    TODO: Find out pixel metrics
+        /*
+         * positive metrics rounded to the smallest int that is bigger than value
+         * negative metrics rounded to the smallest int that is lesser than value
+         * thicknesses rounded to int ((int)round(value + 0.5))
+         *
+         */
+
+        lAscent = (int)Math.ceil(fnt.ascent);//   // Ascent of the font
+        lDescent = -(int)Math.ceil(fnt.descent);// Descent of the font
+        lLeading = (int)Math.ceil(leading);  // External leading
+
+        lHeight = lAscent + lDescent + lLeading;    // Height of the font ( == (ascent + descent + leading))
+
+        lUnderlineThickness = Math.round(underlineThickness);//(int)metrics[11];
+
+        if (underlineOffset >= 0){
+            lUnderlineOffset = (int)Math.ceil(underlineOffset);
+        } else {
+            lUnderlineOffset = (int)Math.floor(underlineOffset);
+        }
+
+        lStrikethroughThickness = Math.round(strikethroughThickness); //(int)metrics[13];
+
+        if (strikethroughOffset >= 0){
+            lStrikethroughOffset = (int)Math.ceil(strikethroughOffset);
+        } else {
+            lStrikethroughOffset = (int)Math.floor(strikethroughOffset);
+        }
+
+        lMaxCharWidth = (int)Math.ceil(maxCharWidth); //(int)metrics[15];
+        units_per_EM = 0;
+
+    }
+
+    public float[] getBaselineOffsets() {
+        // TODO: implement baseline offsets for TrueType fonts
+        if (baselineOffsets == null){
+            float[] baselineData = null;
+
+            // Temporary workaround:
+            // Commented out native data initialization, since it can 
+            // cause failures with opening files in multithreaded applications.
+            //
+            // TODO: support work with truetype data in multithreaded
+            // applications.
+
+            // If font TrueType data is taken from BASE table
+//            if ((this.font.getFontHandle() != 0) && (font.getFontType() == FontManager.FONT_TYPE_TT)){
+//                baselineData = LinuxNativeFont.getBaselineOffsetsNative(font.getFontHandle(), font.getSize(), ascent, descent, units_per_EM);
+//            }
+//
+                baseLineIndex = 0;
+                baselineOffsets = new float[]{0, (-ascent+descent)/2, -ascent};
+        }
+
+        return baselineOffsets;
+    }
+
+    public int getBaselineIndex() {
+        if (baselineOffsets == null){
+            // get offsets and set correct index
+            getBaselineOffsets();
+        }
+        return baseLineIndex;
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/BasicMetrics.java b/awt/org/apache/harmony/awt/gl/font/BasicMetrics.java
new file mode 100644
index 0000000..c0fb390
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/BasicMetrics.java
@@ -0,0 +1,134 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.LineMetrics;
+import java.awt.font.GraphicAttribute;
+import java.awt.*;
+
+/**
+ * Date: May 14, 2005
+ * Time: 7:44:13 PM
+ *
+ * This class incapsulates text metrics specific for the text layout or
+ * for the separate text segment. Text segment is a text run with the constant direction
+ * and attributes like font, decorations, etc. BasicMetrics is also used to store
+ * calculated text metrics like advance, ascent or descent. this class is very similar to
+ * LineMetrics, but provides some additional info, constructors and is more transparent.
+ */
+public class BasicMetrics {
+    int baseLineIndex;
+
+    float ascent;   // Ascent of the font
+    float descent;  // Descent of the font
+    float leading;  // External leading
+    float advance;
+
+    float italicAngle;
+    float superScriptOffset;
+
+    float underlineOffset;
+    float underlineThickness;
+
+    float strikethroughOffset;
+    float strikethroughThickness;
+
+    /**
+     * Constructs BasicMetrics from LineMetrics and font
+     * @param lm
+     * @param font
+     */
+    BasicMetrics(LineMetrics lm, Font font) {
+        ascent = lm.getAscent();
+        descent = lm.getDescent();
+        leading = lm.getLeading();
+
+        underlineOffset = lm.getUnderlineOffset();
+        underlineThickness = lm.getUnderlineThickness();
+
+        strikethroughOffset = lm.getStrikethroughOffset();
+        strikethroughThickness = lm.getStrikethroughThickness();
+
+        baseLineIndex = lm.getBaselineIndex();
+
+        italicAngle = font.getItalicAngle();
+        superScriptOffset = (float) font.getTransform().getTranslateY();
+    }
+
+    /**
+     * Constructs BasicMetrics from GraphicAttribute.
+     * It gets ascent and descent from the graphic attribute and
+     * computes reasonable defaults for other metrics.
+     * @param ga - graphic attribute
+     */
+    BasicMetrics(GraphicAttribute ga) {
+        ascent = ga.getAscent();
+        descent = ga.getDescent();
+        leading = 2;
+
+        baseLineIndex = ga.getAlignment();
+
+        italicAngle = 0;
+        superScriptOffset = 0;
+
+        underlineOffset = Math.max(descent/2, 1);
+
+        // Just suggested, should be cap_stem_width or something like that
+        underlineThickness = Math.max(ascent/13, 1);
+
+        strikethroughOffset = -ascent/2; // Something like middle of the line
+        strikethroughThickness = underlineThickness;
+    }
+
+    /**
+     * Copies metrics from the TextMetricsCalculator object.
+     * @param tmc - TextMetricsCalculator object
+     */
+    BasicMetrics(TextMetricsCalculator tmc) {
+        ascent = tmc.ascent;
+        descent = tmc.descent;
+        leading = tmc.leading;
+        advance = tmc.advance;
+        baseLineIndex = tmc.baselineIndex;
+    }
+
+    public float getAscent() {
+        return ascent;
+    }
+
+    public float getDescent() {
+        return descent;
+    }
+
+    public float getLeading() {
+        return leading;
+    }
+
+    public float getAdvance() {
+        return advance;
+    }
+
+    public int getBaseLineIndex() {
+        return baseLineIndex;
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/CaretManager.java b/awt/org/apache/harmony/awt/gl/font/CaretManager.java
new file mode 100644
index 0000000..b18bdd5
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/CaretManager.java
@@ -0,0 +1,530 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Jun 14, 2005
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.TextHitInfo;
+import java.awt.font.TextLayout;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
+import java.awt.*;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class provides functionality for creating caret and highlight shapes
+ * (bidirectional text is also supported, but, unfortunately, not tested yet).
+ */
+public class CaretManager {
+    private TextRunBreaker breaker;
+
+    public CaretManager(TextRunBreaker breaker) {
+        this.breaker = breaker;
+    }
+
+    /**
+     * Checks if TextHitInfo is not out of the text range and throws the
+     * IllegalArgumentException if it is.
+     * @param info - text hit info
+     */
+    private void checkHit(TextHitInfo info) {
+        int idx = info.getInsertionIndex();
+
+        if (idx < 0 || idx > breaker.getCharCount()) {
+            // awt.42=TextHitInfo out of range
+            throw new IllegalArgumentException(Messages.getString("awt.42")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Calculates and returns visual position from the text hit info.
+     * @param hitInfo - text hit info
+     * @return visual index
+     */
+    private int getVisualFromHitInfo(TextHitInfo hitInfo) {
+        final int idx = hitInfo.getCharIndex();
+
+        if (idx >= 0 && idx < breaker.getCharCount()) {
+            int visual = breaker.getVisualFromLogical(idx);
+            // We take next character for (LTR char + TRAILING info) and (RTL + LEADING)
+            if (hitInfo.isLeadingEdge() ^ ((breaker.getLevel(idx) & 0x1) == 0x0)) {
+                visual++;
+            }
+            return visual;
+        } else if (idx < 0) {
+            return breaker.isLTR() ? 0: breaker.getCharCount();
+        } else {
+            return breaker.isLTR() ? breaker.getCharCount() : 0;
+        }
+    }
+
+    /**
+     * Calculates text hit info from the visual position
+     * @param visual - visual position
+     * @return text hit info
+     */
+    private TextHitInfo getHitInfoFromVisual(int visual) {
+        final boolean first = visual == 0;
+
+        if (!(first || visual == breaker.getCharCount())) {
+            int logical = breaker.getLogicalFromVisual(visual);
+            return (breaker.getLevel(logical) & 0x1) == 0x0 ?
+                    TextHitInfo.leading(logical) : // LTR
+                    TextHitInfo.trailing(logical); // RTL
+        } else if (first) {
+            return breaker.isLTR() ?
+                    TextHitInfo.trailing(-1) :
+                    TextHitInfo.leading(breaker.getCharCount());
+        } else { // Last
+            return breaker.isLTR() ?
+                    TextHitInfo.leading(breaker.getCharCount()) :
+                    TextHitInfo.trailing(-1);
+        }
+    }
+
+    /**
+     * Creates caret info. Required for the getCaretInfo
+     * methods of the TextLayout
+     * @param hitInfo - specifies caret position
+     * @return caret info, see TextLayout.getCaretInfo documentation
+     */
+    public float[] getCaretInfo(TextHitInfo hitInfo) {
+        checkHit(hitInfo);
+        float res[] = new float[2];
+
+        int visual = getVisualFromHitInfo(hitInfo);
+        float advance, angle;
+        TextRunSegment seg;
+
+        if (visual < breaker.getCharCount()) {
+            int logIdx = breaker.getLogicalFromVisual(visual);
+            int segmentIdx = breaker.logical2segment[logIdx];
+            seg = breaker.runSegments.get(segmentIdx);
+            advance = seg.x + seg.getAdvanceDelta(seg.getStart(), logIdx);
+            angle = seg.metrics.italicAngle;
+
+        } else { // Last character
+            int logIdx = breaker.getLogicalFromVisual(visual-1);
+            int segmentIdx = breaker.logical2segment[logIdx];
+            seg = breaker.runSegments.get(segmentIdx);
+            advance = seg.x + seg.getAdvanceDelta(seg.getStart(), logIdx+1);
+        }
+
+        angle = seg.metrics.italicAngle;
+
+        res[0] = advance;
+        res[1] = angle;
+
+        return res;
+    }
+
+    /**
+     * Returns the next position to the right from the current caret position
+     * @param hitInfo - current position
+     * @return next position to the right
+     */
+    public TextHitInfo getNextRightHit(TextHitInfo hitInfo) {
+        checkHit(hitInfo);
+        int visual = getVisualFromHitInfo(hitInfo);
+
+        if (visual == breaker.getCharCount()) {
+            return null;
+        }
+
+        TextHitInfo newInfo;
+
+        while(visual <= breaker.getCharCount()) {
+            visual++;
+            newInfo = getHitInfoFromVisual(visual);
+
+            if (newInfo.getCharIndex() >= breaker.logical2segment.length) {
+                return newInfo;
+            }
+
+            if (hitInfo.getCharIndex() >= 0) { // Don't check for leftmost info
+                if (
+                        breaker.logical2segment[newInfo.getCharIndex()] !=
+                        breaker.logical2segment[hitInfo.getCharIndex()]
+                ) {
+                    return newInfo; // We crossed segment boundary
+                }
+            }
+
+            TextRunSegment seg = breaker.runSegments.get(breaker.logical2segment[newInfo
+                    .getCharIndex()]);
+            if (!seg.charHasZeroAdvance(newInfo.getCharIndex())) {
+                return newInfo;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the next position to the left from the current caret position
+     * @param hitInfo - current position
+     * @return next position to the left
+     */
+    public TextHitInfo getNextLeftHit(TextHitInfo hitInfo) {
+        checkHit(hitInfo);
+        int visual = getVisualFromHitInfo(hitInfo);
+
+        if (visual == 0) {
+            return null;
+        }
+
+        TextHitInfo newInfo;
+
+        while(visual >= 0) {
+            visual--;
+            newInfo = getHitInfoFromVisual(visual);
+
+            if (newInfo.getCharIndex() < 0) {
+                return newInfo;
+            }
+
+            // Don't check for rightmost info
+            if (hitInfo.getCharIndex() < breaker.logical2segment.length) {
+                if (
+                        breaker.logical2segment[newInfo.getCharIndex()] !=
+                        breaker.logical2segment[hitInfo.getCharIndex()]
+                ) {
+                    return newInfo; // We crossed segment boundary
+                }
+            }
+
+            TextRunSegment seg = breaker.runSegments.get(breaker.logical2segment[newInfo
+                    .getCharIndex()]);
+            if (!seg.charHasZeroAdvance(newInfo.getCharIndex())) {
+                return newInfo;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * For each visual caret position there are two hits. For the simple LTR text one is
+     * a trailing of the previous char and another is the leading of the next char. This
+     * method returns the opposite hit for the given hit.
+     * @param hitInfo - given hit
+     * @return opposite hit
+     */
+    public TextHitInfo getVisualOtherHit(TextHitInfo hitInfo) {
+        checkHit(hitInfo);
+
+        int idx = hitInfo.getCharIndex();
+
+        int resIdx;
+        boolean resIsLeading;
+
+        if (idx >= 0 && idx < breaker.getCharCount()) { // Hit info in the middle
+            int visual = breaker.getVisualFromLogical(idx);
+
+            // Char is LTR + LEADING info
+            if (((breaker.getLevel(idx) & 0x1) == 0x0) ^ hitInfo.isLeadingEdge()) {
+                visual++;
+                if (visual == breaker.getCharCount()) {
+                    if (breaker.isLTR()) {
+                        resIdx = breaker.getCharCount();
+                        resIsLeading = true;
+                    } else {
+                        resIdx = -1;
+                        resIsLeading = false;
+                    }
+                } else {
+                    resIdx = breaker.getLogicalFromVisual(visual);
+                    if ((breaker.getLevel(resIdx) & 0x1) == 0x0) {
+                        resIsLeading = true;
+                    } else {
+                        resIsLeading = false;
+                    }
+                }
+            } else {
+                visual--;
+                if (visual == -1) {
+                    if (breaker.isLTR()) {
+                        resIdx = -1;
+                        resIsLeading = false;
+                    } else {
+                        resIdx = breaker.getCharCount();
+                        resIsLeading = true;
+                    }
+                } else {
+                    resIdx = breaker.getLogicalFromVisual(visual);
+                    if ((breaker.getLevel(resIdx) & 0x1) == 0x0) {
+                        resIsLeading = false;
+                    } else {
+                        resIsLeading = true;
+                    }
+                }
+            }
+        } else if (idx < 0) { // before "start"
+            if (breaker.isLTR()) {
+                resIdx = breaker.getLogicalFromVisual(0);
+                resIsLeading = (breaker.getLevel(resIdx) & 0x1) == 0x0; // LTR char?
+            } else {
+                resIdx = breaker.getLogicalFromVisual(breaker.getCharCount() - 1);
+                resIsLeading = (breaker.getLevel(resIdx) & 0x1) != 0x0; // RTL char?
+            }
+        } else { // idx == breaker.getCharCount()
+            if (breaker.isLTR()) {
+                resIdx = breaker.getLogicalFromVisual(breaker.getCharCount() - 1);
+                resIsLeading = (breaker.getLevel(resIdx) & 0x1) != 0x0; // LTR char?
+            } else {
+                resIdx = breaker.getLogicalFromVisual(0);
+                resIsLeading = (breaker.getLevel(resIdx) & 0x1) == 0x0; // RTL char?
+            }
+        }
+
+        return resIsLeading ? TextHitInfo.leading(resIdx) : TextHitInfo.trailing(resIdx);
+    }
+
+    public Line2D getCaretShape(TextHitInfo hitInfo, TextLayout layout) {
+        return getCaretShape(hitInfo, layout, true, false, null);
+    }
+
+    /**
+     * Creates a caret shape.
+     * @param hitInfo - hit where to place a caret
+     * @param layout - text layout
+     * @param useItalic - unused for now, was used to create
+     * slanted carets for italic text
+     * @param useBounds - true if the cared should fit into the provided bounds
+     * @param bounds - bounds for the caret
+     * @return caret shape
+     */
+    public Line2D getCaretShape(
+            TextHitInfo hitInfo, TextLayout layout,
+            boolean useItalic, boolean useBounds, Rectangle2D bounds
+    ) {
+        checkHit(hitInfo);
+
+        float x1, x2, y1, y2;
+
+        int charIdx = hitInfo.getCharIndex();
+
+        if (charIdx >= 0 && charIdx < breaker.getCharCount()) {
+            TextRunSegment segment = breaker.runSegments.get(breaker.logical2segment[charIdx]);
+            y1 = segment.metrics.descent;
+            y2 = - segment.metrics.ascent - segment.metrics.leading;
+
+            x1 = x2 = segment.getCharPosition(charIdx) + (hitInfo.isLeadingEdge() ?
+                    0 : segment.getCharAdvance(charIdx));
+            // Decided that straight cursor looks better even for italic fonts,
+            // especially combined with highlighting
+            /*
+            // Not graphics, need to check italic angle and baseline
+            if (layout.getBaseline() >= 0) {
+                if (segment.metrics.italicAngle != 0 && useItalic) {
+                    x1 -= segment.metrics.italicAngle * segment.metrics.descent;
+                    x2 += segment.metrics.italicAngle *
+                        (segment.metrics.ascent + segment.metrics.leading);
+
+                    float baselineOffset =
+                        layout.getBaselineOffsets()[layout.getBaseline()];
+                    y1 += baselineOffset;
+                    y2 += baselineOffset;
+                }
+            }
+            */
+        } else {
+            y1 = layout.getDescent();
+            y2 = - layout.getAscent() - layout.getLeading();
+            x1 = x2 = ((breaker.getBaseLevel() & 0x1) == 0 ^ charIdx < 0) ?
+                    layout.getAdvance() : 0;
+        }
+
+        if (useBounds) {
+            y1 = (float) bounds.getMaxY();
+            y2 = (float) bounds.getMinY();
+
+            if (x2 > bounds.getMaxX()) {
+                x1 = x2 = (float) bounds.getMaxX();
+            }
+            if (x1 < bounds.getMinX()) {
+                x1 = x2 = (float) bounds.getMinX();
+            }
+        }
+
+        return new Line2D.Float(x1, y1, x2, y2);
+    }
+
+    /**
+     * Creates caret shapes for the specified offset. On the boundaries where
+     * the text is changing its direction this method may return two shapes
+     * for the strong and the weak carets, in other cases it would return one.
+     * @param offset - offset in the text.
+     * @param bounds - bounds to fit the carets into
+     * @param policy - caret policy
+     * @param layout - text layout
+     * @return one or two caret shapes
+     */
+    public Shape[] getCaretShapes(
+            int offset, Rectangle2D bounds,
+            TextLayout.CaretPolicy policy, TextLayout layout
+    ) {
+        TextHitInfo hit1 = TextHitInfo.afterOffset(offset);
+        TextHitInfo hit2 = getVisualOtherHit(hit1);
+
+        Shape caret1 = getCaretShape(hit1, layout);
+
+        if (getVisualFromHitInfo(hit1) == getVisualFromHitInfo(hit2)) {
+            return new Shape[] {caret1, null};
+        }
+        Shape caret2 = getCaretShape(hit2, layout);
+
+        TextHitInfo strongHit = policy.getStrongCaret(hit1, hit2, layout);
+        return strongHit.equals(hit1) ?
+                new Shape[] {caret1, caret2} :
+                new Shape[] {caret2, caret1};
+    }
+
+    /**
+     * Connects two carets to produce a highlight shape.
+     * @param caret1 - 1st caret
+     * @param caret2 - 2nd caret
+     * @return highlight shape
+     */
+    GeneralPath connectCarets(Line2D caret1, Line2D caret2) {
+        GeneralPath path = new GeneralPath(GeneralPath.WIND_NON_ZERO);
+        path.moveTo((float) caret1.getX1(), (float) caret1.getY1());
+        path.lineTo((float) caret2.getX1(), (float) caret2.getY1());
+        path.lineTo((float) caret2.getX2(), (float) caret2.getY2());
+        path.lineTo((float) caret1.getX2(), (float) caret1.getY2());
+
+        path.closePath();
+
+        return path;
+    }
+
+    /**
+     * Creates a highlight shape from given two hits. This shape
+     * will always be visually contiguous
+     * @param hit1 - 1st hit
+     * @param hit2 - 2nd hit
+     * @param bounds - bounds to fit the shape into
+     * @param layout - text layout
+     * @return highlight shape
+     */
+    public Shape getVisualHighlightShape(
+            TextHitInfo hit1, TextHitInfo hit2,
+            Rectangle2D bounds, TextLayout layout
+    ) {
+        checkHit(hit1);
+        checkHit(hit2);
+
+        Line2D caret1 = getCaretShape(hit1, layout, false, true, bounds);
+        Line2D caret2 = getCaretShape(hit2, layout, false, true, bounds);
+
+        return connectCarets(caret1, caret2);
+    }
+
+    /**
+     * Suppose that the user visually selected a block of text which has
+     * several different levels (mixed RTL and LTR), so, in the logical
+     * representation of the text this selection may be not contigous.
+     * This methods returns a set of logical ranges for the arbitrary
+     * visual selection represented by two hits.
+     * @param hit1 - 1st hit
+     * @param hit2 - 2nd hit
+     * @return logical ranges for the selection
+     */
+    public int[] getLogicalRangesForVisualSelection(TextHitInfo hit1, TextHitInfo hit2) {
+        checkHit(hit1);
+        checkHit(hit2);
+
+        int visual1 = getVisualFromHitInfo(hit1);
+        int visual2 = getVisualFromHitInfo(hit2);
+
+        if (visual1 > visual2) {
+            int tmp = visual2;
+            visual2 = visual1;
+            visual1 = tmp;
+        }
+
+        // Max level is 255, so we don't need more than 512 entries
+        int results[] = new int[512];
+
+        int prevLogical, logical, runStart, numRuns = 0;
+
+        logical = runStart = prevLogical = breaker.getLogicalFromVisual(visual1);
+
+        // Get all the runs. We use the fact that direction is constant in all runs.
+        for (int i=visual1+1; i<=visual2; i++) {
+            logical = breaker.getLogicalFromVisual(i);
+            int diff = logical-prevLogical;
+
+            // Start of the next run encountered
+            if (diff > 1 || diff < -1) {
+                results[(numRuns)*2] = Math.min(runStart, prevLogical);
+                results[(numRuns)*2 + 1] = Math.max(runStart, prevLogical);
+                numRuns++;
+                runStart = logical;
+            }
+
+            prevLogical = logical;
+        }
+
+        // The last unsaved run
+        results[(numRuns)*2] = Math.min(runStart, logical);
+        results[(numRuns)*2 + 1] = Math.max(runStart, logical);
+        numRuns++;
+
+        int retval[] = new int[numRuns*2];
+        System.arraycopy(results, 0, retval, 0, numRuns*2);
+        return retval;
+    }
+
+    /**
+     * Creates a highlight shape from given two endpoints in the logical
+     * representation. This shape is not always visually contiguous
+     * @param firstEndpoint - 1st logical endpoint
+     * @param secondEndpoint - 2nd logical endpoint
+     * @param bounds - bounds to fit the shape into
+     * @param layout - text layout
+     * @return highlight shape
+     */
+    public Shape getLogicalHighlightShape(
+            int firstEndpoint, int secondEndpoint,
+            Rectangle2D bounds, TextLayout layout
+    ) {
+        GeneralPath res = new GeneralPath();
+
+        for (int i=firstEndpoint; i<=secondEndpoint; i++) {
+            int endRun = breaker.getLevelRunLimit(i, secondEndpoint);
+            TextHitInfo hit1 = TextHitInfo.leading(i);
+            TextHitInfo hit2 = TextHitInfo.trailing(endRun-1);
+
+            Line2D caret1 = getCaretShape(hit1, layout, false, true, bounds);
+            Line2D caret2 = getCaretShape(hit2, layout, false, true, bounds);
+
+            res.append(connectCarets(caret1, caret2), false);
+
+            i = endRun;
+        }
+
+        return res;
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/CommonGlyphVector.java b/awt/org/apache/harmony/awt/gl/font/CommonGlyphVector.java
new file mode 100644
index 0000000..4040a60
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/CommonGlyphVector.java
@@ -0,0 +1,954 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * GlyphVector implementation
+ */
+public class CommonGlyphVector extends GlyphVector {
+
+    // array of transforms of glyphs in GlyphVector
+    protected AffineTransform[] glsTransforms;
+
+    // array of chars defined in constructor
+    public char[] charVector;
+
+    // array of Glyph objects, that describe information about glyphs
+    public Glyph[] vector;
+
+    // array of default positions of glyphs in GlyphVector
+    // without applying GlyphVector's transform
+    float[] defaultPositions;
+
+    // array of logical positions of glyphs in GlyphVector
+
+    float[] logicalPositions;
+
+    // array of visual (real) positions of glyphs in GlyphVector
+    public float[] visualPositions;
+
+    // FontRenderContext for this vector.
+    protected FontRenderContext vectorFRC;
+
+    // layout flags mask
+    protected int layoutFlags = 0;
+
+    // array of cached glyph outlines 
+    protected Shape[] gvShapes;
+
+    FontPeerImpl peer;
+
+    // font corresponding to the GlyphVector 
+    Font font;
+
+    // ascent of the font
+    float ascent;
+
+    // height of the font
+    float height;
+    
+    // leading of the font
+    float leading;
+    
+    // descent of the font
+    float descent;
+
+    // transform of the GlyphVector
+    AffineTransform transform;
+
+    /**
+     * Creates new CommonGlyphVector object from the specified parameters.
+     * 
+     * @param chars an array of chars
+     * @param frc FontRenderContext object
+     * @param fnt Font object
+     * @param flags layout flags
+     */
+    @SuppressWarnings("deprecation")
+    public CommonGlyphVector(char[] chars, FontRenderContext frc, Font fnt,
+            int flags) {
+        int len = chars.length;
+
+        this.font = fnt;
+        this.transform = fnt.getTransform();
+        this.peer = (FontPeerImpl) fnt.getPeer();
+
+        gvShapes = new Shape[len];
+
+        // !! As pointed in API documentation for the 
+        // getGlyphPosisitions(int index,int numEntries, float[] positionReturn) 
+        // and getGlyphPosition(int index) methods, if the index is equals to 
+        // the number of glyphs the position after the last glyph must be 
+        // returned, thus there are n+1 positions and last (n+1) position 
+        // points to the end of GlyphVector.
+
+        logicalPositions = new float[(len+1)<<1];
+        visualPositions = new float[(len+1)<<1];
+        defaultPositions = new float[(len+1)<<1];
+
+        glsTransforms = new AffineTransform[len];
+
+        this.charVector = chars;
+        this.vectorFRC = frc;
+        //LineMetricsImpl lmImpl = (LineMetricsImpl)peer.getLineMetrics();
+
+        LineMetricsImpl lmImpl = (LineMetricsImpl)fnt.getLineMetrics(String.valueOf(chars), frc);
+
+        this.ascent = lmImpl.getAscent();
+        this.height = lmImpl.getHeight();
+        this.leading = lmImpl.getLeading();
+        this.descent = lmImpl.getDescent();
+        this.layoutFlags = flags;
+
+        if ((flags & Font.LAYOUT_RIGHT_TO_LEFT) != 0){
+            char vector[] = new char[len];
+            for(int i=0; i < len; i++){
+                vector[i] = chars[len-i-1];
+            }
+            this.vector = peer.getGlyphs(vector);
+
+        } else {
+            this.vector = peer.getGlyphs(chars);
+        }
+
+        this.glsTransforms = new AffineTransform[len];
+
+        setDefaultPositions();
+        performDefaultLayout();
+    }
+
+    /**
+     * Creates new CommonGlyphVector object from the specified parameters. 
+     * Layout flags set to default.
+     * 
+     * @param chars an array of chars
+     * @param frc FontRenderContext object
+     * @param fnt Font object
+     */
+    public CommonGlyphVector(char[] chars, FontRenderContext frc, Font fnt) {
+        this(chars, frc, fnt, 0);
+    }
+
+    /**
+     * Creates new CommonGlyphVector object from the specified parameters. 
+     * Layout flags set to default.
+     * 
+     * @param str specified string
+     * @param frc FontRenderContext object
+     * @param fnt Font object
+     */
+    public CommonGlyphVector(String str, FontRenderContext frc, Font fnt) {
+        this(str.toCharArray(), frc, fnt, 0);
+    }
+
+    /**
+     * Creates new CommonGlyphVector object from the specified parameters.
+     * 
+     * @param str specified string
+     * @param frc FontRenderContext object
+     * @param fnt Font object
+     * @param flags layout flags
+     */
+    public CommonGlyphVector(String str, FontRenderContext frc, Font fnt, int flags) {
+        this(str.toCharArray(), frc, fnt, flags);
+    }
+
+    /**
+     * Set array of logical positions of the glyphs to
+     * default with their default advances and height.
+     */
+    void setDefaultPositions(){
+        int len = getNumGlyphs();
+
+        // First [x,y] is set into [0,0] position
+        // for this reason start index is 1
+        for (int i=1; i <= len; i++ ){
+                int idx = i << 1;
+                float advanceX = vector[i-1].getGlyphPointMetrics().getAdvanceX();
+                float advanceY = vector[i-1].getGlyphPointMetrics().getAdvanceY();
+
+                defaultPositions[idx] = defaultPositions[idx-2] + advanceX;
+                defaultPositions[idx+1] = defaultPositions[idx-1] + advanceY;
+
+        }
+        transform.transform(defaultPositions, 0, logicalPositions, 0, getNumGlyphs()+1);
+
+    }
+
+    /**
+     * Returnes the pixel bounds of this GlyphVector rendered at the 
+     * specified x,y location with the given FontRenderContext.
+     *  
+     * @param frc a FontRenderContext that is used
+     * @param x specified x coordinate value
+     * @param y specified y coordinate value
+     * @return a Rectangle that bounds pixels of this GlyphVector
+     */
+    @Override
+    public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) {
+
+        double xM, yM, xm, ym;
+
+        double minX = 0;
+        double minY = 0;
+        double maxX = 0;
+        double maxY = 0;
+
+        for (int i = 0; i < this.getNumGlyphs(); i++) {
+            Rectangle glyphBounds = this.getGlyphPixelBounds(i, frc, 0, 0);
+            xm = glyphBounds.getMinX();
+            ym = glyphBounds.getMinY();
+            xM = glyphBounds.getMaxX();
+            yM = glyphBounds.getMaxY();
+
+            if (i == 0) {
+                minX = xm;
+                minY = ym;
+                maxX = xM;
+                maxY = yM;
+            }
+
+            if (minX > xm) {
+                minX = xm;
+            }
+            if (minY > ym) {
+                minY = ym;
+            }
+            if (maxX < xM) {
+                maxX = xM;
+            }
+            if (maxY < yM) {
+                maxY = yM;
+            }
+        }
+        return new Rectangle((int)(minX + x), (int)(minY + y), (int)(maxX - minX), (int)(maxY - minY));
+
+    }
+
+    /**
+     * Returns the visual bounds of this GlyphVector.
+     * The visual bounds is the bounds of the total outline of 
+     * this GlyphVector.
+     * @return a Rectangle2D that id the visual bounds of this GlyphVector
+     */
+    @Override
+    public Rectangle2D getVisualBounds() {
+        float xM, yM, xm, ym;
+        float minX = 0;
+        float minY = 0;
+        float maxX = 0;
+        float maxY = 0;
+        boolean firstIteration = true;
+
+        for (int i = 0; i < this.getNumGlyphs(); i++) {
+            Rectangle2D bounds = this.getGlyphVisualBounds(i).getBounds2D();
+            if (bounds.getWidth() == 0){
+                continue;
+            }
+            xm = (float)bounds.getX();
+            ym = (float)bounds.getY();
+
+            xM = (float)(xm + bounds.getWidth());
+
+            yM = ym + (float) bounds.getHeight();
+
+            if (firstIteration) {
+                minX = xm;
+                minY = ym;
+                maxX = xM;
+                maxY = yM;
+                firstIteration = false;
+            } else {
+                if (minX > xm) {
+                    minX = xm;
+                }
+                if (minY > ym) {
+                    minY = ym;
+                }
+                if (maxX < xM) {
+                    maxX = xM;
+                }
+                if (maxY < yM) {
+                    maxY = yM;
+                }
+
+            }
+        }
+
+        return (this.getNumGlyphs() != 0) ? new Rectangle2D.Float(minX, minY,
+                (maxX - minX), (maxY - minY)) : null;
+    }
+
+    /**
+     * Sets new position to the specified glyph.
+     */
+    @Override
+    public void setGlyphPosition(int glyphIndex, Point2D newPos) {
+        if ((glyphIndex > vector.length) || (glyphIndex < 0)) {
+            // awt.43=glyphIndex is out of vector's limits
+            throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+        }
+        float x = (float)newPos.getX();
+        float y = (float)newPos.getY();
+        int index = glyphIndex << 1;
+
+        if ((x != visualPositions[index]) || (y != visualPositions[index + 1])){
+            visualPositions[index] = x;
+            visualPositions[index+1] = y;
+            layoutFlags = layoutFlags | FLAG_HAS_POSITION_ADJUSTMENTS;
+        }
+
+    }
+
+    /**
+     * Returns the position of the specified glyph relative to the origin of
+     * this GlyphVector
+     * @return a Point2D that the origin of the glyph with specified index
+     */
+    @Override
+    public Point2D getGlyphPosition(int glyphIndex) {
+        if ((glyphIndex > vector.length) || (glyphIndex < 0)) {
+            // awt.43=glyphIndex is out of vector's limits
+            throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+        }
+        int index = glyphIndex << 1;
+        Point2D pos = new Point2D.Float(visualPositions[index], visualPositions[index+1]);
+
+        // For last position we don't have to transform !!
+        if(glyphIndex==vector.length){
+            return pos;
+        }
+
+        AffineTransform at = getGlyphTransform(glyphIndex);
+        if ((at == null) || (at.isIdentity())){
+            return pos;
+        }
+
+        pos.setLocation(pos.getX() + at.getTranslateX(), pos.getY() + at.getTranslateY());
+
+        return pos;
+    }
+
+    /**
+     * Sets new transform to the specified glyph.
+     * 
+     * @param glyphIndex specified index of the glyph
+     * @param trans AffineTransform of the glyph with specified index
+     */
+    @Override
+    public void setGlyphTransform(int glyphIndex, AffineTransform trans) {
+        if ((glyphIndex >= vector.length) || (glyphIndex < 0)) {
+            // awt.43=glyphIndex is out of vector's limits
+            throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+        }
+
+        if ((trans == null) || (trans.isIdentity())) {
+            glsTransforms[glyphIndex] = null;
+        } else {
+            glsTransforms[glyphIndex] = new AffineTransform(trans);
+            layoutFlags = layoutFlags | FLAG_HAS_TRANSFORMS;
+        }
+    }
+
+    /**
+     * Returns the affine transform of the specified glyph.
+     * 
+     * @param glyphIndex specified index of the glyph
+     * @return an AffineTransform of the glyph with specified index
+     */
+    @Override
+    public AffineTransform getGlyphTransform(int glyphIndex) {
+        if ((glyphIndex >= this.vector.length) || (glyphIndex < 0)) {
+            // awt.43=glyphIndex is out of vector's limits
+            throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+        }
+        return this.glsTransforms[glyphIndex];
+    }
+
+    /**
+     * Returns the metrics of the specified glyph.
+     * 
+     * @param glyphIndex specified index of the glyph
+     */
+    @Override
+    public GlyphMetrics getGlyphMetrics(int glyphIndex) {
+
+        if ((glyphIndex < 0) || ((glyphIndex) >= this.getNumGlyphs())) {
+            // awt.43=glyphIndex is out of vector's limits
+            throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+        }
+        // TODO: is there a sence in GlyphMetrics
+        // if certain glyph or Font has a transform??
+        return this.vector[glyphIndex].getGlyphMetrics();
+    }
+
+    /**
+     * Returns a justification information for the glyph with specified glyph 
+     * index.
+     * @param glyphIndex index of a glyph which GlyphJustificationInfo is to be 
+     * received   
+     * @return a GlyphJustificationInfo object that contains glyph justification 
+     * properties of the specified glyph
+     */
+    @Override
+    public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) {
+        // TODO : Find out the source of Justification info
+        if (true) {
+            throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+        }
+        return null;
+    }
+
+    /**
+     * Returns the FontRenderContext parameter of this GlyphVector.
+     */
+    @Override
+    public FontRenderContext getFontRenderContext() {
+        return this.vectorFRC;
+    }
+
+    /**
+     * Returns the visual bounds of the specified glyph.
+     * 
+     * @param glyphIndex specified index of the glyph
+     */
+    @Override
+    public Shape getGlyphVisualBounds(int glyphIndex) {
+        if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+            // awt.43=glyphIndex is out of vector's limits
+            throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+        }
+
+        int idx  = glyphIndex << 1;
+
+        AffineTransform fontTransform = this.transform;
+        double xOffs = fontTransform.getTranslateX();
+        double yOffs = fontTransform.getTranslateY();
+
+        if (vector[glyphIndex].getWidth() == 0){
+            return new Rectangle2D.Float((float)xOffs, (float)yOffs, 0, 0);
+        }
+
+        AffineTransform at = AffineTransform.getTranslateInstance(xOffs, yOffs);
+        AffineTransform glyphTransform = getGlyphTransform(glyphIndex);
+
+        if (transform.isIdentity() && ((glyphTransform == null) || glyphTransform.isIdentity())){
+            Rectangle2D blackBox = vector[glyphIndex].getGlyphMetrics().getBounds2D();
+            at.translate(visualPositions[idx], visualPositions[idx+1]);
+            return(at.createTransformedShape(blackBox));
+        }
+
+        GeneralPath shape = (GeneralPath)this.getGlyphOutline(glyphIndex);
+        shape.transform(at);
+        return shape.getBounds2D();
+    }
+
+    /**
+     * Returnes the pixel bounds of the specified glyph within GlyphVector 
+     * rendered at the specified x,y location.
+     *  
+     * @param glyphIndex index of the glyph
+     * @param frc a FontRenderContext that is used
+     * @param x specified x coordinate value
+     * @param y specified y coordinate value
+     * @return a Rectangle that bounds pixels of the specified glyph
+     */
+    @Override
+    public Rectangle getGlyphPixelBounds(int glyphIndex, FontRenderContext frc,
+            float x, float y) {
+        // TODO : need to be implemented with FontRenderContext
+        if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+            // awt.43=glyphIndex is out of vector's limits
+            throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+        }
+
+        int idx  = glyphIndex << 1;
+
+        if (vector[glyphIndex].getWidth() == 0){
+            AffineTransform fontTransform = this.transform;
+            double xOffs = x + visualPositions[idx] + fontTransform.getTranslateX();
+            double yOffs = y + visualPositions[idx+1] + fontTransform.getTranslateY();
+            return new Rectangle((int)xOffs, (int)yOffs, 0, 0);
+        }
+
+        GeneralPath shape = (GeneralPath)this.getGlyphOutline(glyphIndex);
+
+        AffineTransform at = AffineTransform.getTranslateInstance(x, y);
+
+        if (frc != null){
+            at.concatenate(frc.getTransform());
+        }
+
+        shape.transform(at);
+
+        Rectangle bounds = shape.getBounds();
+        return new Rectangle((int)bounds.getX(), (int)bounds.getY(),
+                            (int)bounds.getWidth()-1, (int)bounds.getHeight()-1);
+        }
+
+    /**
+     * Returns a Shape that encloses specified glyph.
+     * 
+     * @param glyphIndex specified index of the glyph
+     */
+    @Override
+    public Shape getGlyphOutline(int glyphIndex) {
+        if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+            // awt.43=glyphIndex is out of vector's limits
+            throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+        }
+
+        if (gvShapes[glyphIndex] == null) {
+            gvShapes[glyphIndex] = vector[glyphIndex].getShape();
+        }
+
+        GeneralPath gp = (GeneralPath)((GeneralPath)gvShapes[glyphIndex]).clone();
+
+        /* Applying GlyphVector font transform */
+        AffineTransform at = (AffineTransform)this.transform.clone();
+
+        /* Applying Glyph transform */
+        AffineTransform glyphAT = getGlyphTransform(glyphIndex);
+        if (glyphAT != null){
+            at.preConcatenate(glyphAT);
+        }
+
+        int idx  = glyphIndex << 1;
+
+        gp.transform(at);
+        gp.transform(AffineTransform.getTranslateInstance(visualPositions[idx], visualPositions[idx+1]));
+        return gp;
+    }
+
+
+    /**
+     * Returns a Shape that is the outline representation of this GlyphVector 
+     * rendered at the specified x,y coordinates.
+     * 
+     * @param x specified x coordinate value
+     * @param y specified y coordinate value
+     * @return a Shape object that is the outline of this GlyphVector
+     * at the specified coordinates.
+     */
+    @Override
+    public Shape getOutline(float x, float y) {
+        GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
+        for (int i = 0; i < this.vector.length; i++) {
+            GeneralPath outline = (GeneralPath)getGlyphOutline(i);
+
+            /* Applying translation to actual visual bounds */
+            outline.transform(AffineTransform.getTranslateInstance(x, y));
+            gp.append(outline, false);
+        }
+
+        return gp;
+    }
+
+    /**
+     * Returns a Shape that is the outline representation of this GlyphVector.
+     * 
+     * @return a Shape object that is the outline of this GlyphVector
+     */
+    @Override
+    public Shape getOutline() {
+        return this.getOutline(0, 0);
+    }
+
+    /**
+     * Returns an array of glyphcodes for the specified glyphs.
+     * 
+     * @param beginGlyphIndex the start index
+     * @param numEntries the number of glyph codes to get
+     * @param codeReturn the array that receives glyph codes' values
+     * @return an array that receives glyph codes' values
+     */
+    @Override
+    public int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
+            int[] codeReturn) {
+
+        if ((beginGlyphIndex < 0) || ((numEntries + beginGlyphIndex) > this.getNumGlyphs())) {
+            // awt.44=beginGlyphIndex is out of vector's range
+            throw new IndexOutOfBoundsException(Messages.getString("awt.44")); //$NON-NLS-1$
+        }
+
+        if (numEntries < 0) {
+            // awt.45=numEntries is out of vector's range
+            throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$
+        }
+
+        if (codeReturn == null) {
+            codeReturn = new int[numEntries];
+        }
+
+        for (int i = beginGlyphIndex; i < beginGlyphIndex + numEntries; i++) {
+            codeReturn[i-beginGlyphIndex] = this.vector[i].getGlyphCode();
+        }
+
+        return codeReturn;
+    }
+
+    /**
+     * Returns an array of numEntries character indices for the specified glyphs.
+     * 
+     * @param beginGlyphIndex the start index
+     * @param numEntries the number of glyph codes to get
+     * @param codeReturn the array that receives glyph codes' values
+     * @return an array that receives glyph char indices
+     */
+    @Override
+    public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries,
+            int[] codeReturn) {
+        if ((beginGlyphIndex < 0) || (beginGlyphIndex >= this.getNumGlyphs())) {
+            // awt.44=beginGlyphIndex is out of vector's range
+            throw new IllegalArgumentException(Messages.getString("awt.44")); //$NON-NLS-1$
+        }
+
+        if ((numEntries < 0)
+                || ((numEntries + beginGlyphIndex) > this.getNumGlyphs())) {
+            // awt.45=numEntries is out of vector's range
+            throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$
+        }
+
+        if (codeReturn == null) {
+            codeReturn = new int[numEntries];
+        }
+
+        for (int i = 0; i < numEntries; i++) {
+            codeReturn[i] = this.getGlyphCharIndex(i + beginGlyphIndex);
+        }
+        return codeReturn;
+    }
+
+    /**
+     * Returns an array of numEntries glyphs positions from beginGlyphIndex
+     * glyph in Glyph Vector.
+     * 
+     * @param beginGlyphIndex the start index
+     * @param numEntries the number of glyph codes to get
+     * @param positionReturn the array that receives glyphs' positions
+     * @return an array of floats that receives glyph char indices
+     */
+    @Override
+    public float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
+            float[] positionReturn) {
+
+        int len = (this.getNumGlyphs()+1) << 1;
+        beginGlyphIndex *= 2;
+        numEntries *= 2;
+
+        if ((beginGlyphIndex < 0) || ((numEntries + beginGlyphIndex) > len)) {
+            // awt.44=beginGlyphIndex is out of vector's range
+            throw new IndexOutOfBoundsException(Messages.getString("awt.44")); //$NON-NLS-1$
+        }
+
+        if (numEntries < 0) {
+            // awt.45=numEntries is out of vector's range
+            throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$
+        }
+
+        if (positionReturn == null) {
+            positionReturn = new float[numEntries];
+        }
+
+        System.arraycopy(visualPositions, beginGlyphIndex, positionReturn, 0, numEntries);
+
+        return positionReturn;
+    }
+
+    /**
+     * Set numEntries elements of the visualPositions array from beginGlyphIndex
+     * of numEntries glyphs positions from beginGlyphIndex glyph in Glyph Vector.
+     * 
+     * @param beginGlyphIndex the start index
+     * @param numEntries the number of glyph codes to get
+     * @param setPositions the array of positions to set
+     */
+    public void setGlyphPositions(int beginGlyphIndex, int numEntries,
+            float[] setPositions) {
+
+        int len = (this.getNumGlyphs()+1) << 1;
+        beginGlyphIndex *= 2;
+        numEntries *= 2;
+
+        if ((beginGlyphIndex < 0) || ((numEntries + beginGlyphIndex) > len)) {
+            // awt.44=beginGlyphIndex is out of vector's range
+            throw new IndexOutOfBoundsException(Messages.getString("awt.44")); //$NON-NLS-1$
+        }
+
+        if (numEntries < 0) {
+            // awt.45=numEntries is out of vector's range
+            throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$
+        }
+
+        System.arraycopy(setPositions, 0, visualPositions, beginGlyphIndex, numEntries);
+        layoutFlags = layoutFlags & FLAG_HAS_POSITION_ADJUSTMENTS;
+
+    }
+
+    /**
+     * Set elements of the visualPositions array.
+     * 
+     * @param setPositions the array of positions to set
+     */
+    public void setGlyphPositions(float[] setPositions) {
+
+        int len = (this.getNumGlyphs()+1) << 1;
+        if (len != setPositions.length){
+            // awt.46=length of setPositions array differs from the length of positions array
+            throw new IllegalArgumentException(Messages.getString("awt.46")); //$NON-NLS-1$
+        }
+
+        System.arraycopy(setPositions, 0, visualPositions, 0, len);
+        layoutFlags = layoutFlags & FLAG_HAS_POSITION_ADJUSTMENTS;
+
+    }
+
+
+    /**
+     * Returns glyph code of the specified glyph.
+     * 
+     * @param glyphIndex specified index of the glyph
+     */
+    @Override
+    public int getGlyphCode(int glyphIndex) {
+        if (glyphIndex >= this.vector.length || glyphIndex < 0) {
+            // awt.43=glyphIndex is out of vector's limits
+            throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+        }
+        return this.vector[glyphIndex].getGlyphCode();
+    }
+
+    /**
+     * Returns character index of the specified glyph.
+     * 
+     * @param glyphIndex specified index of the glyph
+     */
+    @Override
+    public int getGlyphCharIndex(int glyphIndex) {
+
+        if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+            // awt.43=glyphIndex is out of vector's limits
+            throw new IllegalArgumentException(Messages.getString("awt.43")); //$NON-NLS-1$
+        }
+
+        if ((this.layoutFlags & Font.LAYOUT_RIGHT_TO_LEFT) != 0) {
+            return this.charVector.length - glyphIndex - 1;
+        }
+
+        return glyphIndex;
+    }
+
+    /**
+     * Returns a character value of the specified glyph.
+     * 
+     * @param glyphIndex specified index of the glyph
+     */
+    public char getGlyphChar(int glyphIndex) {
+
+        if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+            // awt.43=glyphIndex is out of vector's limits
+            throw new IllegalArgumentException(Messages.getString("awt.43")); //$NON-NLS-1$
+        }
+        return this.charVector[glyphIndex];
+    }
+
+    /**
+     * Assigns default positions to each glyph in this GlyphVector.
+     */
+    @Override
+    public void performDefaultLayout() {
+
+        System.arraycopy(logicalPositions, 0, visualPositions, 0, logicalPositions.length);
+
+        // Set position changes flag to zero
+        clearLayoutFlags(GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS);
+    }
+
+    /**
+     * Returns the number of glyphs in this Glyph Vector
+     */
+    @Override
+    public int getNumGlyphs() {
+        return vector.length;
+    }
+
+    /**
+     * Returns the logical bounds of this GlyphVector
+     */
+    @Override
+    public Rectangle2D getLogicalBounds(){
+        // XXX: for transforms where an angle between basis vectors is not 90 degrees
+        // Rectanlge2D class doesn't fit as Logical bounds. For this reason we use
+        // only non-transformed bounds!!
+
+        float x = visualPositions[0];
+        float width = visualPositions[visualPositions.length-2];
+
+        double scaleY =  transform.getScaleY();
+
+        Rectangle2D bounds = new Rectangle2D.Float(x, (float)((-this.ascent-this.leading)*scaleY), width, (float)(this.height*scaleY));
+        return bounds;
+    }
+
+
+    /**
+     * Checks whether given GlyphVector equals to this GlyphVector.
+     * @param glyphVector GlyphVector object to compare
+     */
+    @Override
+    public boolean equals(GlyphVector glyphVector){
+        if (glyphVector == this){
+            return true;
+        }
+
+        if (glyphVector != null) {
+
+            if (!(glyphVector.getFontRenderContext().equals(this.vectorFRC) &&
+                      glyphVector.getFont().equals(this.font))){
+                return false;
+            }
+
+            try {
+                boolean eq = true;
+                for (int i = 0; i < getNumGlyphs(); i++) {
+
+                    int idx = i*2;
+                    eq = (((CommonGlyphVector)glyphVector).visualPositions[idx] == this.visualPositions[idx]) &&
+                        (((CommonGlyphVector)glyphVector).visualPositions[idx+1] == this.visualPositions[idx+1]) &&
+                        (glyphVector.getGlyphCharIndex(i) == this.getGlyphCharIndex(i));
+
+                    if (eq){
+                        AffineTransform trans = glyphVector.getGlyphTransform(i);
+                        if (trans == null){
+                            eq = (this.glsTransforms[i] == null);
+                        }else{
+                            eq = this.glsTransforms[i].equals(trans);
+                        }
+                    }
+
+                    if (!eq){
+                        return false;
+                    }
+                }
+
+                return  eq;
+            } catch (ClassCastException e) {
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Returns flags describing the state of the GlyphVector.
+     */
+    @Override
+    public int getLayoutFlags() {
+        return layoutFlags;
+    }
+
+    /**
+     * Returns char with the specified index.
+     * 
+     * @param index specified index of the char
+     * 
+     */
+    public char getChar(int index) {
+        return this.charVector[index];
+
+    }
+
+    /**
+     * Clear desired flags in layout flags describing the state. 
+     * 
+     * @param clearFlags flags mask to clear 
+     */
+    
+    private void clearLayoutFlags(int clearFlags){
+        layoutFlags &= ~clearFlags;
+    }
+
+    /**
+     * Returns the logical bounds of the specified glyph within this CommonGlyphVector.
+     * 
+     * @param glyphIndex index of the glyph to get it's logical bounds
+     * @return logical bounds of the specified glyph
+     */
+    @Override
+    public Shape getGlyphLogicalBounds(int glyphIndex){
+        if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())){
+            // awt.43=glyphIndex is out of vector's limits
+            throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+        }
+        Glyph glyph = this.vector[glyphIndex];
+
+        float x0 = visualPositions[glyphIndex*2];
+        float y0 = visualPositions[glyphIndex*2+1];
+        float advanceX = glyph.getGlyphPointMetrics().getAdvanceX();
+
+        GeneralPath gp = new GeneralPath();
+        gp.moveTo(0, -ascent - leading);
+        gp.lineTo(advanceX ,-ascent - leading);
+        gp.lineTo(advanceX, descent);
+        gp.lineTo(0, descent);
+        gp.lineTo(0, -ascent - leading);
+        gp.closePath();
+
+        /* Applying GlyphVector font transform */
+        AffineTransform at = (AffineTransform)this.transform.clone();
+
+        /* Applying Glyph transform */
+        AffineTransform glyphTransform = getGlyphTransform(glyphIndex);
+        if (glyphTransform != null){
+            at.concatenate(glyphTransform);
+        }
+
+        /* Applying translation to actual visual bounds */
+        at.preConcatenate(AffineTransform.getTranslateInstance(x0, y0));
+        gp.transform(at);
+        return gp;
+    }
+
+    /**
+     * Returns the Font parameter of this GlyphVector
+     */
+    @Override
+    public Font getFont(){
+        return this.font;
+    }
+
+
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/font/CompositeFont.java b/awt/org/apache/harmony/awt/gl/font/CompositeFont.java
new file mode 100644
index 0000000..70cb334
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/CompositeFont.java
@@ -0,0 +1,486 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.awt.gl.font.FontPeerImpl;
+import org.apache.harmony.awt.gl.font.FontProperty;
+
+/**
+ * CompositeFont class is the implementation of logical font classes. 
+ * Every logical font consists of several physical fonts that described 
+ * in font.properties file according to the face name of this logical font.
+ */
+public class CompositeFont extends FontPeerImpl{
+    
+    // a number of physical fonts that CompositeFont consist of 
+    int numFonts;
+
+    // font family name
+    String family;
+
+    // font face name
+    String face;
+
+    String[] fontNames;
+    
+    // an array of font properties applicable to this CompositeFont
+    FontProperty[] fontProperties;
+    
+    // an array of font peers applicable to this CompositeFont
+    public FontPeerImpl[] fPhysicalFonts;
+    
+    // missing glyph code field
+    int missingGlyphCode = -1;
+    
+    // line metrics of this font
+    LineMetricsImpl nlm = null;
+    
+    // cached num glyphs parameter of this font that is the sum of num glyphs of 
+    // font peers composing this font
+    int cachedNumGlyphs = -1;
+    /**
+     * Creates CompositeFont object that is corresponding to the specified logical 
+     * family name.
+     * 
+     * @param familyName logical family name CompositeFont is to be created from
+     * @param faceName logical face name CompositeFont is to be created from
+     * @param _style style of the CompositeFont to be created
+     * @param _size size of the CompositeFont to be created 
+     * @param fProperties an array of FontProperties describing physical fonts - 
+     * parts of logical font
+     * @param physFonts an array of physical font peers related to the CompositeFont
+     * to be created
+     */
+    public CompositeFont(String familyName, String faceName, int _style, int _size, FontProperty[] fProperties, FontPeerImpl[] physFonts){
+        this.size = _size;
+        this.name = faceName;
+        this.family = familyName;
+        this.style = _style;
+        this.face = faceName;
+        this.psName = faceName;
+        this.fontProperties = fProperties;// !! Supposed that fProperties parameter != null
+        fPhysicalFonts = physFonts;
+        numFonts = fPhysicalFonts.length; 
+        setDefaultLineMetrics("", null); //$NON-NLS-1$
+        this.uniformLM = false;
+    }
+
+    /**
+     * Returns the index of the FontPeer in array of physical fonts that is applicable 
+     * for the given character. This font has to have the highest priority among fonts
+     * that can display this character and don't have exclusion range covering 
+     * specified character. If there is no desired fonts -1 is returned.
+     * 
+     * @param chr specified character
+     * @return index of the font from the array of physical fonts that will be used 
+     * during processing of the specified character. 
+     */
+    public int getCharFontIndex(char chr){
+        for (int i = 0; i < numFonts; i++){
+            if (fontProperties[i].isCharExcluded(chr)){
+                continue;
+            }
+            if (fPhysicalFonts[i].canDisplay(chr)){
+                return i;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Returns the index of the FontPeer in array of physical fonts that is applicable 
+     * for the given character. This font has to have the highest priority among fonts
+     * that can display this character and don't have exclusion range covering 
+     * specified character. If there is no desired fonts default value is returned.
+     * 
+     * @param chr specified character
+     * @param defaultValue default index that is returned if the necessary font couldn't be found.
+     * @return index of the font from the array of physical fonts that will be used 
+     * during processing of the specified character. 
+     */
+     public int getCharFontIndex(char chr, int defaultValue){
+        for (int i = 0; i < numFonts; i++){
+            if (fontProperties[i].isCharExcluded(chr)){
+                continue;
+            }
+            if (fPhysicalFonts[i].canDisplay(chr)){
+                return i;
+            }
+        }
+
+        return defaultValue;
+    }
+
+    /**
+     * Returns true if one of the physical fonts composing this font CompositeFont 
+     * can display specified character.
+     *   
+     * @param chr specified character
+     */
+    @Override
+    public boolean canDisplay(char chr){
+        return (getCharFontIndex(chr) != -1);
+    }
+
+    /**
+     * Returns logical ascent (in pixels)
+     */
+    @Override
+    public int getAscent(){
+        return nlm.getLogicalAscent();
+    }
+
+    /**
+     * Returns LineMetrics instance scaled according to the specified transform.  
+     * 
+     * @param str specified String 
+     * @param frc specified FontRenderContext 
+     * @param at specified AffineTransform
+     */
+     @Override
+    public LineMetrics getLineMetrics(String str, FontRenderContext frc , AffineTransform at){
+        LineMetricsImpl lm = (LineMetricsImpl)(this.nlm.clone());
+        lm.setNumChars(str.length());
+
+        if ((at != null) && (!at.isIdentity())){
+            lm.scale((float)at.getScaleX(), (float)at.getScaleY());
+        }
+
+        return lm;
+    }
+
+    /**
+     * Returns cached LineMetrics instance for the null string or creates it if
+     * it wasn't cached yet.
+     */
+    @Override
+    public LineMetrics getLineMetrics(){
+        if (nlm == null){
+            setDefaultLineMetrics("", null); //$NON-NLS-1$
+        }
+
+        return this.nlm;
+    }
+
+    /**
+     * Creates LineMetrics instance and set cached LineMetrics field to it.
+     * Created LineMetrics has maximum values of the idividual metrics of all
+     * composing physical fonts. If there is only one physical font - it's 
+     * LineMetrics object is returned.
+     * 
+     * @param str specified String 
+     * @param frc specified FontRenderContext 
+     */
+    private void setDefaultLineMetrics(String str, FontRenderContext frc){
+        LineMetrics lm = fPhysicalFonts[0].getLineMetrics(str, frc, null);
+        float maxCharWidth = (float)fPhysicalFonts[0].getMaxCharBounds(frc).getWidth();
+
+        if (numFonts == 1) {
+            this.nlm = (LineMetricsImpl)lm;
+            return;
+        }
+
+        float[] baselineOffsets = lm.getBaselineOffsets();
+        int numChars = str.length();
+
+        // XXX: default value - common for all Fonts
+        int baseLineIndex = lm.getBaselineIndex();
+
+        float maxUnderlineThickness = lm.getUnderlineThickness();
+        float maxUnderlineOffset = lm.getUnderlineOffset();
+        float maxStrikethroughThickness = lm.getStrikethroughThickness();
+        float minStrikethroughOffset = lm.getStrikethroughOffset();
+        float maxLeading = lm.getLeading();  // External leading
+        float maxHeight = lm.getHeight();   // Height of the font ( == (ascent + descent + leading))
+        float maxAscent = lm.getAscent();   // Ascent of the font
+        float maxDescent = lm.getDescent(); // Descent of the font
+
+        for (int i = 1; i < numFonts; i++){
+            lm = fPhysicalFonts[i].getLineMetrics(str, frc, null);
+            if (maxUnderlineThickness < lm.getUnderlineThickness()){
+                maxUnderlineThickness = lm.getUnderlineThickness();
+            }
+
+            if (maxUnderlineOffset < lm.getUnderlineOffset()){
+                maxUnderlineOffset = lm.getUnderlineOffset();
+            }
+
+            if (maxStrikethroughThickness < lm.getStrikethroughThickness()){
+                maxStrikethroughThickness = lm.getStrikethroughThickness();
+            }
+
+            if (minStrikethroughOffset > lm.getStrikethroughOffset()){
+                minStrikethroughOffset = lm.getStrikethroughOffset();
+            }
+
+            if (maxLeading < lm.getLeading()){
+                maxLeading = lm.getLeading();
+            }
+
+            if (maxAscent < lm.getAscent()){
+                maxAscent = lm.getAscent();
+            }
+
+            if (maxDescent < lm.getDescent()){
+                maxDescent = lm.getDescent();
+            }
+
+            float width = (float)fPhysicalFonts[i].getMaxCharBounds(frc).getWidth();
+            if(maxCharWidth < width){
+                maxCharWidth = width;
+            }
+            for (int j =0; j < baselineOffsets.length; j++){
+                float[] offsets = lm.getBaselineOffsets();
+                if (baselineOffsets[j] > offsets[j]){
+                    baselineOffsets[j] = offsets[j];
+                }
+            }
+
+        }
+        maxHeight = maxAscent + maxDescent + maxLeading;
+
+        this.nlm =  new LineMetricsImpl(
+                numChars,
+                baseLineIndex,
+                baselineOffsets,
+                maxUnderlineThickness,
+                maxUnderlineOffset,
+                maxStrikethroughThickness,
+                minStrikethroughOffset,
+                maxLeading,
+                maxHeight,
+                maxAscent,
+                maxDescent,
+                maxCharWidth);
+
+    }
+
+    /**
+     * Returns the number of glyphs in this CompositeFont object.
+     */
+    @Override
+    public int getNumGlyphs(){
+        if (this.cachedNumGlyphs == -1){
+
+            this.cachedNumGlyphs = 0;
+
+            for (int i = 0; i < numFonts; i++){
+                this.cachedNumGlyphs += fPhysicalFonts[i].getNumGlyphs();
+            }
+        }
+
+        return this.cachedNumGlyphs;
+    }
+
+    /**
+     * Returns the italic angle of this object.
+     */
+    @Override
+    public float getItalicAngle(){
+        // !! only first physical font used to get this value
+        return fPhysicalFonts[0].getItalicAngle();
+    }
+
+    /**
+     * Returns rectangle that bounds the specified string in terms of composite line metrics.
+     * 
+     * @param chars an array of chars
+     * @param start the initial offset in array of chars
+     * @param end the end offset in array of chars
+     * @param frc specified FontRenderContext
+     */
+    public Rectangle2D getStringBounds(char[] chars, int start, int end, FontRenderContext frc){
+
+        LineMetrics lm = getLineMetrics();
+        float minY = -lm.getAscent();
+        float minX = 0;
+        float height = lm.getHeight();
+        float width = 0;
+
+        for (int i = start; i < end; i++){
+            width += charWidth(chars[i]);
+        }
+
+        Rectangle2D rect2D = new Rectangle2D.Float(minX, minY, width, height);
+        return rect2D;
+
+    }
+
+    /**
+     * Returns maximum rectangle that encloses all maximum char bounds of 
+     * physical fonts composing this CompositeFont.
+     *  
+     * @param frc specified FontRenderContext
+     */
+    @Override
+    public Rectangle2D getMaxCharBounds(FontRenderContext frc){
+
+        Rectangle2D rect2D = fPhysicalFonts[0].getMaxCharBounds(frc);
+        float minY = (float)rect2D.getY();
+        float maxWidth = (float)rect2D.getWidth();
+        float maxHeight = (float)rect2D.getHeight();
+        if (numFonts == 1){
+            return rect2D;
+        }
+
+        for (int i = 1; i < numFonts; i++){
+            if (fPhysicalFonts[i] != null){
+                rect2D = fPhysicalFonts[i].getMaxCharBounds(frc);
+                float y = (float)rect2D.getY();
+                float mWidth = (float)rect2D.getWidth();
+                float mHeight = (float)rect2D.getHeight();
+                if (y < minY){
+                    minY = y;
+                }
+                if (mWidth > maxWidth){
+                    maxHeight = mWidth;
+                }
+                
+                if (mHeight > maxHeight){
+                    maxHeight = mHeight;
+                }
+            }
+        }
+
+        rect2D = new Rectangle2D.Float(0, minY, maxWidth, maxHeight);
+
+        return rect2D;
+    }
+
+    /**
+     * Returns font name.
+     */
+    @Override
+    public String getFontName(){
+        return face;
+    }
+
+    /**
+     * Returns font postscript name.
+     */
+    @Override
+    public String getPSName(){
+        return psName;
+    }
+
+    /**
+     * Returns font family name.
+     */
+    @Override
+    public String getFamily(){
+        return family;
+    }
+
+    /**
+     * Returns the code of the missing glyph.
+     */
+    @Override
+    public int getMissingGlyphCode(){
+        // !! only first physical font used to get this value
+        return fPhysicalFonts[0].getMissingGlyphCode();
+    }
+
+    /**
+     * Returns Glyph object corresponding to the specified character.
+     * 
+     * @param ch specified char
+     */
+    @Override
+    public Glyph getGlyph(char ch){
+        for (int i = 0; i < numFonts; i++){
+            if (fontProperties[i].isCharExcluded(ch)){
+                    continue;
+            }
+            
+            /* Control symbols considered to be supported by the font peer */
+            if ((ch < 0x20) || fPhysicalFonts[i].canDisplay(ch)){
+                return fPhysicalFonts[i].getGlyph(ch);
+            }
+        }
+        return getDefaultGlyph();
+    }
+
+    /**
+     * Returns width of the char with specified index.
+     * 
+     * @param ind specified index of the character 
+     */
+    @Override
+    public int charWidth(int ind){
+        return charWidth((char)ind);
+    }
+
+    /**
+     * Returns width of the specified char.
+     * 
+     * @param c specified character 
+     */
+    @Override
+    public int charWidth(char c){
+        Glyph gl = this.getGlyph(c);
+        return (int)gl.getGlyphPointMetrics().getAdvanceX();
+    }
+
+    /**
+     * Returns debug information about this class.
+     */
+    @Override
+    public String toString(){
+    return new String(this.getClass().getName() +
+            "[name=" + this.name + //$NON-NLS-1$
+            ",style="+ this.style + //$NON-NLS-1$
+            ",fps=" + this.fontProperties + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+    /**
+     * Returns Glyph object corresponding to the default glyph.
+     */
+    @Override
+    public Glyph getDefaultGlyph(){
+        // !! only first physical font used to get this value
+        return fPhysicalFonts[0].getDefaultGlyph();
+    }
+    
+    /**
+     * Returns FontExtraMetrics object with extra metrics
+     * related to this CompositeFont.
+     */
+    @Override
+    public FontExtraMetrics getExtraMetrics(){
+        // Returns FontExtraMetrics instanse of the first physical 
+        // Font from the array of fonts.
+        return fPhysicalFonts[0].getExtraMetrics();
+    }
+
+    /**
+     * Disposes CompositeFont object's resources.
+     */
+    @Override
+    public void dispose() {
+        // Nothing to dispose
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontExtraMetrics.java b/awt/org/apache/harmony/awt/gl/font/FontExtraMetrics.java
new file mode 100644
index 0000000..047ba6d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontExtraMetrics.java
@@ -0,0 +1,145 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ * 
+ */
+package org.apache.harmony.awt.gl.font;
+
+/**
+ * Extra font metrics: sub/superscripts sizes, offsets, average char width.
+ */
+public class FontExtraMetrics {
+    
+    /* !! Subscript/superscript metrics are undefined for Type1. As a possible 
+     * solution we can use values for Type1, that are proportionate to TrueType
+     * ones:
+     *  SubscriptSizeX == 0.7 * fontSize
+     *  SubscriptSizeY == 0.65 * fontSize
+     *  SubscriptOffsetX == 0;
+     *  SubscriptOffsetY == 0.15 * fontSize;
+     *  SuperscriptSizeX == 0.7 * fontSize
+     *  SuperscriptSizeY == 0.65 * fontSize
+     *  SuperscriptOffsetX == 0;
+     *  SuperscriptOffsetY == 0.45 * fontSize
+     *  
+     */
+    
+    /*
+     * The average width of characters in the font.
+     */
+    private float lAverageCharWidth;
+    
+    /*
+     * Horizontal size for subscripts.
+     */
+    private float lSubscriptSizeX;
+
+    /*
+     * Vertical size for subscripts.
+     */
+    private float lSubscriptSizeY; 
+    
+    /*
+     * Horizontal offset for subscripts, the offset from the character origin 
+     * to the origin of the subscript character.
+     */
+    private float lSubscriptOffsetX; 
+
+    /*
+     * Vertical offset for subscripts, the offset from the character origin 
+     * to the origin of the subscript character.
+     */
+    private float lSubscriptOffsetY;
+    
+    /*
+     * Horizontal size for superscripts.
+     */
+    private float lSuperscriptSizeX; 
+
+    /*
+     * Vertical size for superscripts.
+     */
+    private float lSuperscriptSizeY;
+    
+    /*
+     * Horizontal offset for superscripts, the offset from the character 
+     * base line to the base line of the superscript character.
+     */
+    private float lSuperscriptOffsetX;
+
+    /*
+     * Vertical offset for superscripts, the offset from the character 
+     * base line to the base line of the superscript character.
+     */
+    private float lSuperscriptOffsetY;
+    
+    public FontExtraMetrics(){
+        // default constructor
+    }
+
+    public FontExtraMetrics(float[] metrics){
+        lAverageCharWidth = metrics[0];
+        lSubscriptSizeX = metrics[1];
+        lSubscriptSizeY = metrics[2];
+        lSubscriptOffsetX = metrics[3];
+        lSubscriptOffsetY = metrics[4];
+        lSuperscriptSizeX = metrics[5];
+        lSuperscriptSizeY = metrics[6];
+        lSuperscriptOffsetX = metrics[7];
+        lSuperscriptOffsetY = metrics[8];
+    }
+
+    public float getAverageCharWidth(){
+        return lAverageCharWidth;
+    }
+    
+    public float getSubscriptSizeX(){
+        return lSubscriptSizeX;
+    }
+
+    public float getSubscriptSizeY(){
+        return lSubscriptSizeY;
+    }
+
+    public float getSubscriptOffsetX(){
+        return lSubscriptOffsetX;
+    }
+
+    public float getSubscriptOffsetY(){
+        return lSubscriptOffsetY;
+    }
+
+    public float getSuperscriptSizeX(){
+        return lSuperscriptSizeX;
+    }
+
+    public float getSuperscriptSizeY(){
+        return lSuperscriptSizeY;
+    }
+
+    public float getSuperscriptOffsetX(){
+        return lSuperscriptOffsetX;
+    }
+
+    public float getSuperscriptOffsetY(){
+        return lSuperscriptOffsetY;
+    }
+    
+    
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontFinder.java b/awt/org/apache/harmony/awt/gl/font/FontFinder.java
new file mode 100644
index 0000000..09bcf5c
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontFinder.java
@@ -0,0 +1,121 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Jul 12, 2005
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.GraphicsEnvironment;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class chooses the default font for the given text.
+ * If it finds the character which current font is unable to display
+ * it starts the next font run and looks for the font which is able to
+ * display the current character. It also caches the font mappings
+ * (index in the array containing all fonts) for the characters,
+ * using that fact that scripts are mainly contiguous in the UTF-16 encoding
+ * and there's a high probability that the upper byte will be the same for the
+ * next character as for the previous. This allows to save the space used for the cache.
+ */
+public class FontFinder {
+    private static final float DEFAULT_FONT_SIZE = 12;
+
+    private static final Font fonts[] =
+            GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
+
+    private static final int NUM_BLOCKS = 256;
+    private static final int BLOCK_SIZE = 256;
+    private static final int INDEX_MASK = 0xFF;
+    private static final int BLOCK_SHIFT = 8;
+
+    // Maps characters into the fonts array
+    private static final int blocks[][] = new int[NUM_BLOCKS][];
+
+    /**
+     * Finds the font which is able to display the given character
+     * and saves the font mapping for this character
+     * @param c - character
+     * @return font
+     */
+    static Font findFontForChar(char c) {
+        int blockNum = c >> BLOCK_SHIFT;
+        int index = c & INDEX_MASK;
+
+        if (blocks[blockNum] == null) {
+            blocks[blockNum] = new int[BLOCK_SIZE];
+        }
+
+        if (blocks[blockNum][index] == 0) {
+            blocks[blockNum][index] = 1;
+
+            for (int i=0; i<fonts.length; i++) {
+                if (fonts[i].canDisplay(c)) {
+                    blocks[blockNum][index] = i+1;
+                    break;
+                }
+            }
+        }
+
+        return getDefaultSizeFont(blocks[blockNum][index]-1);
+    }
+
+    /**
+     * Derives the default size font
+     * @param i - index in the array of all fonts
+     * @return derived font
+     */
+    static Font getDefaultSizeFont(int i) {
+        if (fonts[i].getSize() != DEFAULT_FONT_SIZE) {
+            fonts[i] = fonts[i].deriveFont(DEFAULT_FONT_SIZE);
+        }
+
+        return fonts[i];
+    }
+
+    /**
+     * Assigns default fonts for the given text run.
+     * First three parameters are input, last three are output.
+     * @param text - given text
+     * @param runStart - start of the text run
+     * @param runLimit - end of the text run
+     * @param runStarts - starts of the resulting font runs
+     * @param fonts - mapping of the font run starts to the fonts
+     */
+    static void findFonts(char text[], int runStart, int runLimit, List<Integer> runStarts,
+            Map<Integer, Font> fonts) {
+        Font prevFont = null;
+        Font currFont;
+        for (int i = runStart; i < runLimit; i++) {
+            currFont = findFontForChar(text[i]);
+            if (currFont != prevFont) {
+                prevFont = currFont;
+                Integer idx = new Integer(i);
+                fonts.put(idx, currFont);
+                if (i != runStart) {
+                    runStarts.add(idx);
+                }
+            }
+        }
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontManager.java b/awt/org/apache/harmony/awt/gl/font/FontManager.java
new file mode 100644
index 0000000..8354e25
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontManager.java
@@ -0,0 +1,819 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.peer.FontPeer;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.harmony.awt.gl.CommonGraphics2DFactory;
+import org.apache.harmony.luni.util.NotImplementedException;
+
+
+public abstract class FontManager {
+    
+    //???AWT
+    boolean NOT_IMP = false;
+    
+    /**
+     * array of font families names
+     */
+    public String[] allFamilies;
+
+    public static final String DEFAULT_NAME = "Default"; /* Default font name */ //$NON-NLS-1$
+    public static final String DIALOG_NAME = "Dialog";  /* Dialog font name */ //$NON-NLS-1$
+
+    /**
+     * Set of constants applicable to the TrueType 'name' table.
+     */
+    public static final byte  FAMILY_NAME_ID  = 1;      /* Family name identifier   */
+    public static final byte  FONT_NAME_ID  = 4;        /* Full font name identifier    */
+    public static final byte  POSTSCRIPT_NAME_ID = 6;   /* PostScript name identifier   */
+    public static final short ENGLISH_LANGID = 0x0409;  /* English (United States)language identifier   */
+
+    /**
+     * Set of constants describing font type.
+     */
+    public static final byte  FONT_TYPE_TT  = 4;        /* TrueType type (TRUETYPE_FONTTYPE)    */
+    public static final byte  FONT_TYPE_T1  = 2;        /* Type1 type    (DEVICE_FONTTYPE)      */
+    public static final byte  FONT_TYPE_UNDEF  = 0;     /* Undefined type                       */
+
+    // logical family types (indices in FontManager.LOGICAL_FONT_NAMES)
+    static final int DIALOG = 3;        // FF_SWISS
+    static final int SANSSERIF = 1;     // FF_SWISS
+    static final int DIALOGINPUT = 4;   // FF_MODERN
+    static final int MONOSPACED = 2;    // FF_MODERN
+    static final int SERIF = 0;         // FF_ROMAN
+
+
+    /**
+     * FontProperty related constants. 
+     */
+    public static final String PLATFORM_FONT_NAME = "PlatformFontName"; //$NON-NLS-1$
+    public static final String LOGICAL_FONT_NAME = "LogicalFontName"; //$NON-NLS-1$
+    public static final String COMPONENT_INDEX = "ComponentIndex"; //$NON-NLS-1$
+    public static final String STYLE_INDEX = "StyleIndex"; //$NON-NLS-1$
+
+    public static final String[] FONT_MAPPING_KEYS = {
+            "LogicalFontName.StyleName.ComponentIndex", "LogicalFontName.ComponentIndex" //$NON-NLS-1$ //$NON-NLS-2$
+    };
+
+    public static final String FONT_CHARACTER_ENCODING = "fontcharset.LogicalFontName.ComponentIndex"; //$NON-NLS-1$
+
+    public static final String EXCLUSION_RANGES = "exclusion.LogicalFontName.ComponentIndex"; //$NON-NLS-1$
+
+    public static final String FONT_FILE_NAME = "filename.PlatformFontName"; //$NON-NLS-1$
+
+    /**
+     * Available logical font families names.
+     */
+    public static final String[] LOGICAL_FONT_FAMILIES = {
+            "Serif", "SansSerif", "Monospaced", "Dialog", "DialogInput" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+    };
+
+    /**
+     * Available logical font names.
+     */
+    public static final String[] LOGICAL_FONT_NAMES = {
+            "serif", "serif.plain", "serif.bold", "serif.italic", "serif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+            "sansserif", "sansserif.plain", "sansserif.bold", "sansserif.italic", "sansserif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+            "monospaced", "monospaced.plain", "monospaced.bold", "monospaced.italic", "monospaced.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+            "dialog", "dialog.plain", "dialog.bold", "dialog.italic", "dialog.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+            "dialoginput", "dialoginput.plain", "dialoginput.bold", "dialoginput.italic", "dialoginput.bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+    };
+
+    /**
+     * Available logical font face names.
+     */
+    public static final String[] LOGICAL_FONT_FACES = {
+            "Serif", "Serif.plain", "Serif.bold", "Serif.italic", "Serif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+            "Sansserif", "Sansserif.plain", "Sansserif.bold", "Sansserif.italic", "Sansserif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+            "Monospaced", "Monospaced.plain", "Monospaced.bold", "Monospaced.italic", "Monospaced.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+            "Dialog", "Dialog.plain", "Dialog.bold", "Dialog.italic", "Dialog.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+            "Dialoginput", "Dialoginput.plain", "Dialoginput.bold", "Dialoginput.italic", "Dialoginput.bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+    };
+
+    /**
+     * Set of font style names.
+     * Font.getStyle() corresponds to indexes in STYLE_NAMES array.
+     */
+    public static final String[] STYLE_NAMES = {
+            "plain", "bold", "italic", "bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+    };
+
+    /**
+     * Logical font styles names table where font styles names used 
+     * as the key and the value is the index of this style name.
+     */
+    private static final Hashtable<String, Integer> style_keys = new Hashtable<String, Integer>(4);
+
+    /**
+     * Initialize font styles keys table.
+     */
+    static {
+        for (int i = 0; i < STYLE_NAMES.length; i++){
+            style_keys.put(STYLE_NAMES[i], Integer.valueOf(i));
+        }
+    }
+
+    /**
+     * Return font style from the logical style name.
+     * 
+     * @param lName style name of the logical face
+     */
+    public static int getLogicalStyle(String lName){
+        Integer value = style_keys.get(lName);
+        return value != null ? value.intValue(): -1;
+    }
+
+    /**
+     * Set of possible "os" property values.
+     */
+    public static final String[] OS_VALUES = {
+            "NT", "98", "2000", "Me", "XP", // For Windows //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+            "Redhat", "Turbo", "SuSE"       // For Linux //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    };
+
+    /**
+     * Set of possible font.property file names.
+     * Language, Country, Encoding, OS, Version should be replaced with
+     * the values from current configuration.
+     */
+    public static final String[] FP_FILE_NAMES = {
+            "/lib/font.properties.Language_Country_Encoding.OSVersion", //$NON-NLS-1$
+            "/lib/font.properties.Language_Country_Encoding.OS", //$NON-NLS-1$
+            "/lib/font.properties.Language_Country_Encoding.Version", //$NON-NLS-1$
+            "/lib/font.properties.Language_Country_Encoding", //$NON-NLS-1$
+            "/lib/font.properties.Language_Country.OSVersion", //$NON-NLS-1$
+            "/lib/font.properties.Language_Country.OS", //$NON-NLS-1$
+            "/lib/font.properties.Language_Country.Version", //$NON-NLS-1$
+            "/lib/font.properties.Language_Country", //$NON-NLS-1$
+            "/lib/font.properties.Language_Encoding.OSVersion", //$NON-NLS-1$
+            "/lib/font.properties.Language_Encoding.OS", //$NON-NLS-1$
+            "/lib/font.properties.Language_Encoding.Version", //$NON-NLS-1$
+            "/lib/font.properties.Language_Encoding", //$NON-NLS-1$
+            "/lib/font.properties.Language.OSVersion", //$NON-NLS-1$
+            "/lib/font.properties.Language.OS", //$NON-NLS-1$
+            "/lib/font.properties.Language.Version", //$NON-NLS-1$
+            "/lib/font.properties.Language", //$NON-NLS-1$
+            "/lib/font.properties.Encoding.OSVersion", //$NON-NLS-1$
+            "/lib/font.properties.Encoding.OS", //$NON-NLS-1$
+            "/lib/font.properties.Encoding.Version", //$NON-NLS-1$
+            "/lib/font.properties.Encoding", //$NON-NLS-1$
+            "/lib/font.properties.OSVersion", //$NON-NLS-1$
+            "/lib/font.properties.OS", //$NON-NLS-1$
+            "/lib/font.properties.Version", //$NON-NLS-1$
+            "/lib/font.properties" //$NON-NLS-1$
+    };
+
+    /**
+     * Table with all available font properties corresponding
+     * to the current system configuration.
+     */
+    public Hashtable<String, Vector<FontProperty>> fProperties = new Hashtable<String, Vector<FontProperty>>();
+    
+    public FontManager(){
+        allFamilies = getAllFamilies();
+        /*
+         * Creating and registering shutdown hook to free resources
+         * before object is destroyed.
+         */
+        //???AWT
+        //DisposeNativeHook shutdownHook = new DisposeNativeHook();
+        //Runtime.getRuntime().addShutdownHook(shutdownHook);
+    }
+
+    /**
+     * Maximum number of unreferenced font peers to keep.
+     */
+    public static final int EMPTY_FONTS_CAPACITY = 10;
+
+    /**
+     * Locale - Language ID hash table.
+     */
+    Hashtable<String, Short> tableLCID = new Hashtable<String, Short>();
+
+    /**
+     * Hash table that contains FontPeers instances.
+     */
+    public Hashtable<String, HashMapReference> fontsTable = new Hashtable<String, HashMapReference>();
+    
+    /**
+     * ReferenceQueue for HashMapReference objects to check
+     * if they were collected by garbage collector. 
+     */
+    public ReferenceQueue<FontPeer> queue = new ReferenceQueue<FontPeer>();
+
+    /**
+     * Singleton instance
+     */
+    public final static FontManager inst = CommonGraphics2DFactory.inst.getFontManager();
+
+    /**
+     * Gets singleton instance of FontManager
+     * 
+     * @return instance of FontManager implementation
+     */
+    public static FontManager getInstance() {
+        return inst;
+    }
+
+    /**
+     * Returns platform-dependent Font peer created from the specified 
+     * Font object from the table with cached FontPeers instances.
+     * 
+     * Note, this method checks whether FontPeer with specified parameters 
+     * exists in the table with cached FontPeers' instances. If there is no needed 
+     * instance - it is created and cached.
+     * 
+     * @param fontName name of the font 
+     * @param _fontStyle style of the font 
+     * @param size font size
+     * 
+     * @return platform dependent FontPeer implementation created from 
+     * the specified parameters
+     */
+    public FontPeer getFontPeer(String fontName, int _fontStyle, int size) {
+        updateFontsTable();
+        
+        FontPeer peer = null;
+        String key; 
+        String name;
+        int fontStyle = _fontStyle;
+        
+        int logicalIndex = getLogicalFaceIndex(fontName);
+        
+        if (logicalIndex != -1){
+            name = getLogicalFaceFromFont(fontStyle, logicalIndex);
+            fontStyle = getStyleFromLogicalFace(name);
+            key = name.concat(String.valueOf(size));
+        } else {
+            name = fontName;
+            key = name.concat(String.valueOf(fontStyle)).
+                    concat(String.valueOf(size));
+        }
+        
+        HashMapReference hmr   = fontsTable.get(key);
+        if (hmr != null) {
+            peer = hmr.get();
+        }
+
+        if (peer == null) {
+            peer = createFontPeer(name, fontStyle, size, logicalIndex);
+            if (peer == null){
+                peer = getFontPeer(DIALOG_NAME, fontStyle, size);
+            }
+            fontsTable.put(key, new HashMapReference(key, peer, queue));
+        }
+
+        return peer;
+    }
+    
+    /**
+     * Returns instance of font peer (logical or physical) according to the 
+     * specified parameters.
+     * 
+     * @param name font face name
+     * @param style style of the font
+     * @param size size of the font
+     * @param logicalIndex index of the logical face name in LOGICAL_FONT_FACES 
+     * array or -1 if desired font peer is not logical.
+     */
+    private FontPeer createFontPeer(String name, int style, int size, int logicalIndex){
+        FontPeer peer;
+        if (logicalIndex != -1){
+            peer = createLogicalFontPeer(name, style, size);
+        }else {
+            peer = createPhysicalFontPeer(name, style, size);
+        }
+        
+        return peer;
+    }
+    
+    /**
+     * Returns family name for logical face names as a parameter.
+     * 
+     * @param faceName logical font face name
+     */
+    public String getFamilyFromLogicalFace(String faceName){
+        int pos = faceName.indexOf("."); //$NON-NLS-1$
+        if (pos == -1){
+            return faceName;
+        }
+            
+        return faceName.substring(0, pos);
+    }
+            
+    /**
+     * Returns new logical font peer for the parameters specified using font 
+     * properties.
+     * 
+     * @param faceName face name of the logical font 
+     * @param style style of the font 
+     * @param size font size
+     * 
+     */
+    private FontPeer createLogicalFontPeer(String faceName, int style, int size){
+        String family = getFamilyFromLogicalFace(faceName);
+        FontProperty[] fps = getFontProperties(family.toLowerCase() + "." + style); //$NON-NLS-1$
+        if (fps != null){
+            int numFonts = fps.length;
+            FontPeerImpl[] physicalFonts = new FontPeerImpl[numFonts];
+            for (int i = 0; i < numFonts; i++){
+                FontProperty fp = fps[i];
+                
+                String name = fp.getName();
+                int fpStyle = fp.getStyle();
+                String key = name.concat(String.valueOf(fpStyle)).
+                    concat(String.valueOf(size));
+                
+                HashMapReference hmr   = fontsTable.get(key);
+                if (hmr != null) {
+                    physicalFonts[i] = (FontPeerImpl)hmr.get();
+                }
+
+                if (physicalFonts[i] == null){
+                    physicalFonts[i] = (FontPeerImpl)createPhysicalFontPeer(name, fpStyle, size);
+                    fontsTable.put(key, new HashMapReference(key, physicalFonts[i], queue));
+                }
+
+                if (physicalFonts[i] == null){
+                    physicalFonts[i] = (FontPeerImpl)getDefaultFont(style, size);
+                }
+            }
+            return new CompositeFont(family, faceName, style, size, fps, physicalFonts); 
+        }
+        
+        // if there is no property for this logical font - default font is to be
+        // created
+        FontPeerImpl peer = (FontPeerImpl)getDefaultFont(style, size);
+        
+        return peer;
+    }
+
+    /**
+     * Returns new physical font peer for the parameters specified using font properties
+     * This method must be overridden by subclasses implementations.
+     *  
+     * @param faceName face name or family name of the font 
+     * @param style style of the font 
+     * @param size font size
+     * 
+     */
+    public abstract FontPeer createPhysicalFontPeer(String name, int style, int size);
+    
+    /**
+     * Returns default font peer class with "Default" name that is usually 
+     * used when font with specified font names and style doesn't exsist 
+     * on a system. 
+     * 
+     * @param style style of the font
+     * @param size size of the font
+     */
+    public FontPeer getDefaultFont(int style, int size){
+        updateFontsTable();
+        
+        FontPeer peer = null;
+        String key = DEFAULT_NAME.concat(String.valueOf(style)).
+                    concat(String.valueOf(size));
+        
+        HashMapReference hmr   = fontsTable.get(key);
+        if (hmr != null) {
+            peer = hmr.get();
+        }
+
+        if (peer == null) {
+            peer = createDefaultFont(style, size);
+            
+            ((FontPeerImpl)peer).setFamily(DEFAULT_NAME);
+            ((FontPeerImpl)peer).setPSName(DEFAULT_NAME);
+            ((FontPeerImpl)peer).setFontName(DEFAULT_NAME);
+
+            fontsTable.put(key, new HashMapReference(key, peer, queue));
+        }
+
+        return peer;
+    }
+    
+    /**
+     * 
+     * Returns new default font peer with "Default" name for the parameters 
+     * specified. This method must be overridden by subclasses implementations.
+     *  
+     * @param style style of the font
+     * @param size size of the font
+     */
+    public abstract FontPeer createDefaultFont(int style, int size);
+    
+    /**
+     * Returns face name of the logical font, which is the result
+     * of specified font style and face style union.   
+     * 
+     * @param fontStyle specified style of the font
+     * @param logicalIndex index of the specified face from the 
+     * LOGICAL_FONT_FACES array
+     * @return resulting face name
+     */
+    public String getLogicalFaceFromFont(int fontStyle, int logicalIndex){
+        int style = 0;
+        String name = LOGICAL_FONT_FACES[logicalIndex];
+        int pos = name.indexOf("."); //$NON-NLS-1$
+        
+        if (pos == -1){
+            return createLogicalFace(name, fontStyle);
+        }
+        
+        String styleName = name.substring(pos+1);
+        name = name.substring(0, pos);
+        
+        // appending font style to the face style
+        style = fontStyle | getLogicalStyle(styleName);
+        
+        return createLogicalFace(name, style);
+    }
+    
+    /**
+     * Function returns style value from logical face name.
+     *  
+     * @param name face name
+     * @return font style
+     */
+    public int getStyleFromLogicalFace(String name){
+        int style;
+        int pos = name.indexOf("."); //$NON-NLS-1$
+        
+        if (pos == -1){
+            return Font.PLAIN;
+        }
+        
+        String styleName = name.substring(pos+1);
+        
+        style = getLogicalStyle(styleName);
+        
+        return style;
+    }
+
+    /**
+     * Returns logical face name corresponding to the logical
+     * family name and style of the font.
+     * 
+     * @param family font family
+     * @param styleIndex index of the style name from the STYLE_NAMES array 
+     */
+    public String createLogicalFace(String family, int styleIndex){
+        return family + "." + STYLE_NAMES[styleIndex]; //$NON-NLS-1$
+    }
+    
+    /**
+     * Return language Id from LCID hash corresponding to the specified locale
+     * 
+     * @param l specified locale
+     */
+    public Short getLCID(Locale l){
+        if (this.tableLCID.size() == 0){
+            initLCIDTable();
+        }
+
+        return tableLCID.get(l.toString());
+    }
+
+    /**
+     * Platform-dependent LCID table init.
+     */
+    public abstract void initLCIDTable();
+
+    /**
+     * Freeing native resources. This hook is used to avoid 
+     * sudden application exit and to free resources created in native code.
+     */
+    private class DisposeNativeHook extends Thread {
+
+        @Override
+        public void run() {
+            try{
+                /* Disposing native font peer's resources */
+                Enumeration<String> kEnum = fontsTable.keys();
+
+                while(kEnum.hasMoreElements()){
+                    Object key = kEnum.nextElement();
+                    HashMapReference hmr = fontsTable.remove(key);
+                    FontPeerImpl delPeer = (FontPeerImpl)hmr.get();
+                    
+                    if ((delPeer != null) && (delPeer.getClass() != CompositeFont.class)){
+                        // there's nothing to dispose in CompositeFont objects
+                        delPeer.dispose();
+                    }
+                }
+            } catch (Throwable t){
+                throw new RuntimeException(t);
+            }
+        }
+      }
+
+    /**
+     * Returns File object, created in a directory
+     * according to the System, where JVM is being ran.
+     *
+     * In Linux case we use ".fonts" directory (for fontconfig purpose),
+     * where font file from the stream will be stored, hence in LinuxFontManager this
+     * method is overridden.
+     * In Windows case we use Windows temp directory (default implementation)
+     *
+     */
+    public File getTempFontFile()throws IOException{
+        //???AWT
+        /*
+        File fontFile = File.createTempFile("jFont", ".ttf"); //$NON-NLS-1$ //$NON-NLS-2$
+        fontFile.deleteOnExit();
+
+        return fontFile;
+         */
+        if(NOT_IMP)
+            throw new NotImplementedException("getTempFontFile not Implemented");
+        return null;
+    }
+
+    /**
+     * Returns File object with font properties. It's name obtained using current 
+     * system configuration properties and locale settings. If no appropriate 
+     * file is found method returns null. 
+     */
+    public static File getFontPropertyFile(){
+        File file = null;
+
+        String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
+        Locale l = Locale.getDefault();
+        String language = l.getLanguage();
+        String country = l.getCountry();
+        String fileEncoding = System.getProperty("file.encoding"); //$NON-NLS-1$
+
+        String os = System.getProperty("os.name"); //$NON-NLS-1$
+
+        int i = 0;
+
+        // OS names from system properties don't match
+        // OS identifiers used in font.property files
+        for (; i < OS_VALUES.length; i++){
+            if (os.endsWith(OS_VALUES[i])){
+                os = OS_VALUES[i];
+                break;
+            }
+        }
+
+        if (i == OS_VALUES.length){
+            os = null;
+        }
+
+        String version = System.getProperty("os.version"); //$NON-NLS-1$
+        String pathname;
+
+        for (i = 0; i < FP_FILE_NAMES.length; i++){
+            pathname = FP_FILE_NAMES[i];
+            if (os != null){
+                pathname = pathname.replaceFirst("OS", os); //$NON-NLS-1$
+            }
+
+            pathname = javaHome + pathname;
+
+            pathname = pathname.replaceAll("Language", language). //$NON-NLS-1$
+                                replaceAll("Country", country). //$NON-NLS-1$
+                                replaceAll("Encoding", fileEncoding). //$NON-NLS-1$
+                                replaceAll("Version", version); //$NON-NLS-1$
+
+            file = new File(pathname);
+
+            if (file.exists()){
+                break;
+            }
+        }
+
+        return file.exists() ? file : null;
+    }
+
+    /**
+     * Returns an array of integer range values
+     * if the parameter exclusionString has format:
+     *          Range
+     *          Range [, exclusionString]
+     *
+     *          Range:
+     *              Char-Char
+     *
+     *          Char:
+     *              HexDigit HexDigit HexDigit HexDigit
+     * 
+     * Method returns null if the specified string is null.
+     *  
+     * @param exclusionString string parameter in specified format
+     */
+    public static int[] parseIntervals(String exclusionString){
+        int[] results = null;
+
+        if (exclusionString == null){
+            return null;
+        }
+
+        String[] intervals = exclusionString.split(","); //$NON-NLS-1$
+
+        if (intervals != null){
+            int num = intervals.length;
+            if (num > 0){
+                results = new int[intervals.length << 1];
+                for (int i = 0; i < intervals.length; i++){
+                    String ranges[] = intervals[i].split("-"); //$NON-NLS-1$
+                    results[i*2] = Integer.parseInt(ranges[0], 16);
+                    results[i*2+1] = Integer.parseInt(ranges[1], 16);
+
+                }
+            }
+        }
+        return results;
+    }
+
+    /**
+     * Returns Properties from the properties file or null if 
+     * there is an error with FileInputStream processing.
+     * 
+     * @param file File object containing properties
+     */
+    public static Properties getProperties(File file){
+        Properties props = null;
+        FileInputStream fis = null;
+        try{
+            fis = new FileInputStream(file);
+            props = new Properties();
+            props.load(fis);
+        } catch (Exception e){
+            System.out.println(e);
+        }
+        return props;
+    }
+
+    /**
+     * Returns an array of FontProperties from the properties file
+     * with the specified property name "logical face.style". E.g. 
+     * "dialog.2" corresponds to the font family Dialog with bold style. 
+     *
+     * @param fpName key of the font properties in the properties set
+     */
+    public FontProperty[] getFontProperties(String fpName){
+        Vector<FontProperty> props = fProperties.get(fpName);
+        
+        if (props == null){
+            return null;
+        }
+
+        int size =  props.size();
+        
+        if (size == 0){
+            return null;
+        }
+
+        FontProperty[] fps = new FontProperty[size];
+        for (int i=0; i < fps.length; i++){
+            fps[i] = props.elementAt(i);
+        }
+        return fps;
+    }
+
+    /**
+     * Returns index of the font name in array of font names or -1 if 
+     * this font is not logical.
+     * 
+     * @param fontName specified font name
+     */
+    public static int getLogicalFaceIndex(String fontName){
+        for (int i=0; i<LOGICAL_FONT_NAMES.length; i++ ){
+            if (LOGICAL_FONT_NAMES[i].equalsIgnoreCase(fontName)){
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns true if specified family name is available in this 
+     * GraphicsEnvironment. 
+     * 
+     * @param familyName the specified font family name
+     */
+    public boolean isFamilyExist(String familyName){
+        return (getFamilyIndex(familyName) != -1);
+    }
+
+    /**
+     * Returns index of family name from the array of family names available in 
+     * this GraphicsEnvironment or -1 if no family name was found.
+     * 
+     * @param familyName specified font family name 
+     */
+    public int getFamilyIndex(String familyName){
+        for (int i=0; i<allFamilies.length; i++ ){
+            if (familyName.equalsIgnoreCase(allFamilies[i])){
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns family with index specified from the array of family names available in 
+     * this GraphicsEnvironment.
+     * 
+     * @param index index of the family in families names array 
+     */
+    public String getFamily(int index){
+        return allFamilies[index];
+    }
+    /**
+     * Returns index of face name from the array of face names available in 
+     * this GraphicsEnvironment or -1 if no face name was found. Default return 
+     * value is -1, method must be overridden by FontManager implementation.
+     * 
+     * @param faceName font face name which index is to be searched
+     */
+    public int getFaceIndex(String faceName){
+        return -1;
+    }
+
+    public abstract String[] getAllFamilies();
+
+    public abstract Font[] getAllFonts();
+    
+    /**
+     * Class contains SoftReference instance that can be stored in the 
+     * Hashtable by means of key field corresponding to it.
+     */
+    private class HashMapReference extends SoftReference<FontPeer> {
+        
+        /**
+         * The key for Hashtable.
+         */
+        private final String key;
+
+        /**
+         * Creates a new soft reference with the key specified and 
+         * adding this reference in the reference queue specified.
+         *
+         * @param key the key in Hashtable
+         * @param value object that corresponds to the key
+         * @param queue reference queue where reference is to be added 
+         */
+        public HashMapReference(final String key, final FontPeer value,
+                              final ReferenceQueue<FontPeer> queue) {
+            super(value, queue);
+            this.key = key;
+        }
+
+        /**
+         * Returns the key that corresponds to the SoftReference instance 
+         *
+         * @return the key in Hashtable with cached references
+         */
+        public Object getKey() {
+            return key;
+        }
+    }
+
+    /**
+     * Removes keys from the Hashtable with font peers which corresponding 
+     * HashMapReference objects were garbage collected.
+     */
+    private void updateFontsTable() {
+        HashMapReference r;
+        //???AWT
+        //while ((r = (HashMapReference)queue.poll()) != null) {
+        //    fontsTable.remove(r.getKey());
+        //}
+    }
+
+}
+
+
diff --git a/awt/org/apache/harmony/awt/gl/font/FontMetricsImpl.java b/awt/org/apache/harmony/awt/gl/font/FontMetricsImpl.java
new file mode 100644
index 0000000..7783317
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontMetricsImpl.java
@@ -0,0 +1,282 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+//import java.awt.Paint;
+import java.awt.geom.AffineTransform;
+
+import android.graphics.Paint;
+
+/**
+ * FontMetrics implementation
+ */
+
+public class FontMetricsImpl extends FontMetrics {
+
+	private static final long serialVersionUID = 844695615201925138L;
+
+	// ascent of the font
+	private int ascent;
+
+	// descent of the font
+	private int descent;
+
+	// leading of the font
+	private int leading;
+
+	// maximum ascent of the font
+	private int maxAscent;
+
+	// maximum descent of the font
+	private int maxDescent;
+
+	// maximum advance of the font
+	private int maxAdvance;
+
+	// array of char advance widths
+	private int[] widths = new int[256];
+
+	// font peer corresponding to this FontPeerImpl
+	private transient FontPeerImpl peer;
+
+	// X scale parameter of the font transform
+	private float scaleX = 1;
+
+	public AndroidGraphics2D mSg;
+
+	private Font mFn;
+
+	// Y scale parameter of the font transform
+	private float scaleY = 1;
+
+	/**
+	 * Creates new FontMericsImpl object described by the specified Font.
+	 * 
+	 * @param fnt
+	 *            the specified Font object
+	 */
+	public FontMetricsImpl(Font fnt) {
+		super(fnt);
+		this.mFn = fnt;
+		
+		mSg = AndroidGraphics2D.getInstance();
+		Paint p = mSg.getAndroidPaint();
+		
+		this.ascent = (int)-p.ascent();
+		this.descent = (int)p.descent();
+		this.leading = p.getFontMetricsInt().leading;
+		
+		AffineTransform at = fnt.getTransform();
+		if (!at.isIdentity()) {
+			scaleX = (float) at.getScaleX();
+			scaleY = (float) at.getScaleY();
+		}
+				
+	    /*
+	     * metrics[5] - strikethrough thickness<p>
+	     * -metrics[6] - strikethrough offset<p>
+	     * metrics[7] - maximum char width<p>
+	     * metrics[8] - ascent in pixels<p>
+	     * metrics[9] - descent in pixles<p>
+	     * metrics[10] - external leading in pixels<p>
+	     * metrics[11] - underline thickness in pixels<p>
+	     * -metrics[12] - underline offset in pixels<p>
+	     * metrics[13] - strikethrough thickness in pixels<p>
+	     * -metrics[14] - strikethrough offset in pixels<p>
+	     * metrics[15] - maximum char width in pixels<p>
+
+	     * @param _baselineData an array of 3 elements with baseline offsets metrics<p>
+	     * _baselineData[0] - roman baseline offset<p> 
+	     * _baselineData[1] - center baseline offset<p>
+	     * _baselineData[2] - hanging baseline offset<p>
+	     */
+	}
+
+
+	/**
+	 * Initialize the array of the first 256 chars' advance widths of the Font
+	 * describing this FontMetricsImpl object.
+	 */
+	private void initWidths() {
+
+		this.widths = new int[256];
+		for (int chr = 0; chr < 256; chr++) {
+			widths[chr] = (int) (getFontPeer().charWidth((char) chr) * scaleX);
+		}
+
+	}
+
+	/**
+	 * Returns the ascent of the Font describing this FontMetricsImpl object.
+	 */
+	@Override
+	public int getAscent() {
+		return this.ascent;
+	}
+
+	/**
+	 * Returns the descent of the Font describing this FontMetricsImpl object.
+	 */
+	@Override
+	public int getDescent() {
+		return this.descent;
+	}
+
+	/**
+	 * Returns the leading of the Font describing this FontMetricsImpl object.
+	 */
+	@Override
+	public int getLeading() {
+		return this.leading;
+	}
+
+	/**
+	 * Returns the advance width of the specified char of the Font describing
+	 * this FontMetricsImpl object.
+	 * 
+	 * @param ch
+	 *            the char which width is to be returned
+	 * @return the advance width of the specified char of the Font describing
+	 *         this FontMetricsImpl object
+	 */
+	@Override
+	public int charWidth(int ch) {
+		if (ch < 256) {
+			return widths[ch];
+		}
+
+		return getFontPeer().charWidth((char) ch);
+	}
+
+	/**
+	 * Returns the advance width of the specified char of the Font describing
+	 * this FontMetricsImpl object.
+	 * 
+	 * @param ch
+	 *            the char which width is to be returned
+	 * @return the advance width of the specified char of the Font describing
+	 *         this FontMetricsImpl object
+	 */
+	@Override
+	public int charWidth(char ch) {
+		if (ch < 256) {
+			return widths[ch];
+		}
+		return (int) (getFontPeer().charWidth(ch) * scaleX);
+	}
+
+	/**
+	 * Returns the maximum advance of the Font describing this FontMetricsImpl
+	 * object.
+	 */
+	@Override
+	public int getMaxAdvance() {
+		return this.maxAdvance;
+	}
+
+	/**
+	 * Returns the maximum ascent of the Font describing this FontMetricsImpl
+	 * object.
+	 */
+	@Override
+	public int getMaxAscent() {
+		return this.maxAscent;
+	}
+
+	/**
+	 * Returns the maximum descent of the Font describing this FontMetricsImpl
+	 * object.
+	 */
+	@SuppressWarnings("deprecation")
+	@Deprecated
+	@Override
+	public int getMaxDecent() {
+		return this.maxDescent;
+	}
+
+	/**
+	 * Returns the maximum descent of the Font describing this FontMetricsImpl
+	 * object.
+	 */
+	@Override
+	public int getMaxDescent() {
+		return this.maxDescent;
+	}
+
+	/**
+	 * Returns the advance widths of the first 256 characters in the Font
+	 * describing this FontMetricsImpl object.
+	 */
+	@Override
+	public int[] getWidths() {
+		return this.widths;
+	}
+
+	/**
+	 * Returns the total advance width of the specified string in the metrics of
+	 * the Font describing this FontMetricsImpl object.
+	 * 
+	 * @param str
+	 *            the String which width is to be measured
+	 * @return the total advance width of the specified string in the metrics of
+	 *         the Font describing this FontMetricsImpl object
+	 */
+	@Override
+	public int stringWidth(String str) {
+
+		int width = 0;
+		char chr;
+
+		for (int i = 0; i < str.length(); i++) {
+			chr = str.charAt(i);
+			width += charWidth(chr);
+		}
+		return width;
+
+		/*
+		 * float res = 0; int ln = str.length(); char[] c = new char[ln]; float[] f =
+		 * new float[ln]; str.getChars(0, ln, c, 0); mSg.getPaint().getTextWidths(c, 0,
+		 * ln, f);
+		 * 
+		 * for(int i = 0; i < f.length; i++) { res += f[i]; } return (int)res;
+		 */
+	}
+
+	/**
+	 * Returns FontPeer implementation of the Font describing this
+	 * FontMetricsImpl object.
+	 * 
+	 * @return a FontPeer object, that is the platform dependent FontPeer
+	 *         implementation for the Font describing this FontMetricsImpl
+	 *         object.
+	 */
+	@SuppressWarnings("deprecation")
+	public FontPeerImpl getFontPeer() {
+		if (peer == null) {
+			peer = (FontPeerImpl) font.getPeer();
+		}
+		return peer;
+	}
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontPeerImpl.java b/awt/org/apache/harmony/awt/gl/font/FontPeerImpl.java
new file mode 100644
index 0000000..14ff997
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontPeerImpl.java
@@ -0,0 +1,499 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+
+import com.android.internal.awt.AndroidGraphics2D;
+import com.android.internal.awt.AndroidGraphicsFactory;
+
+import java.awt.Graphics2D;
+import java.awt.Toolkit;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.peer.FontPeer;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+import android.graphics.Paint;
+
+/**
+ * Abstract class for platform dependent peer implementation of the Font class.
+ */
+public abstract class FontPeerImpl implements FontPeer{
+
+    // ascent of this font peer (in pixels)
+    int ascent;
+
+    // descent of this font peer (in pixels)
+    int descent;
+
+    // leading of this font peer (in pixels) 
+    int leading;
+
+    // logical maximum advance of this font peer (in pixels)
+    int maxAdvance;
+
+    // the height of this font peer
+    float height;
+
+    // the style of this font peer
+    int style;
+
+    // the point size of this font peer (in pixels)
+    int size;
+
+    // the logical hight of this font peer (in pixels)
+    int logicalHeight;
+
+    // the name of this font peer
+    String name;
+
+    // family name of this font peer
+    String fontFamilyName;
+
+    // the Face name of this font peer
+    String faceName;
+
+    // bounds rectanlge of the largest character in this font peer
+    Rectangle2D maxCharBounds;
+
+    // italic angle value of this font peer
+    float italicAngle = 0.0f;
+
+    // the number of glyphs supported by this font peer
+    int numGlyphs = 0;
+
+    // native font handle
+    long pFont;
+
+    // cached line metrics object
+    LineMetricsImpl nlm;
+
+    // the postscript name of this font peer
+    String psName = null;
+
+    /**
+     * Default glyph index, that is used, when the desired glyph
+     * is unsupported in this Font.
+     */
+    public char defaultChar = (char)0xFFFF;
+
+    /**
+     * Uniform LineMetrics flag, that is false for CompositeFont.  
+     * Default value is true.
+     */
+    boolean uniformLM = true;
+
+    /**
+     * Flag of the type of this Font that is indicate is the Font
+     * has TrueType or Type1 type. Default value is FONT_TYPE_UNDEF. 
+     */
+    int fontType = FontManager.FONT_TYPE_UNDEF;
+
+    /**
+     * Flag if this Font was created from stream, 
+     * this parameter used in finilize method.
+     */ 
+    private boolean createdFromStream = false;  
+    
+    // temorary Font file name, if this FontPeerImpl was created from InputStream 
+    private String tempFontFileName = null;     
+    
+    // cached FontExtraMetrics object related to this font peer
+    FontExtraMetrics extraMetrix = null;
+
+    public abstract FontExtraMetrics getExtraMetrics();
+    
+    /**
+     * Returns LineMetrics object with specified parameters
+     * @param str specified String
+     * @param frc specified render context
+     * @param at specified affine transform
+     * @return
+     */
+    public abstract LineMetrics getLineMetrics(String str, FontRenderContext frc, AffineTransform at);
+
+    /**
+     * Returns postscript name of the font.  
+     */
+    public abstract String getPSName();
+    
+	//private Graphics2D g = ((AndroidGraphicsFactory)Toolkit.getDefaultToolkit().getGraphicsFactory()).getGraphics2D();
+    //private Graphics2D g = AndroidGraphics2D.getInstance();
+
+    /**
+     * Set postscript name of the font to the specified parameter.  
+     */
+    public void setPSName(String name){
+        this.psName = name;
+    }
+    
+    /**
+     * Returns code of the missing glyph. 
+     */
+    public abstract int getMissingGlyphCode();
+
+    /**
+     * Returns Glyph representation of the given char.
+     * @param ch specified char
+     */
+    public abstract Glyph getGlyph(char ch);
+
+    /**
+     * Disposes nesessary resources.
+     */
+    public abstract void dispose();
+
+    /**
+     * Returns Glyph represeting missing char. 
+     */
+    public abstract Glyph getDefaultGlyph();
+
+    /**
+     * Returns true if this FontPeerImpl can display the specified char
+     */
+    public abstract boolean canDisplay(char c);
+
+    /**
+     * Returns family name of the font in specified locale settings.
+     * @param l specified Locale
+     */
+    public String getFamily(Locale l){
+        return this.getFamily();
+    }
+
+    /**
+     * Sets family name of the font in specified locale settings.
+     */
+    public void setFamily(String familyName){
+        this.fontFamilyName = familyName;
+    }
+
+    /**
+     * Returns face name of the font in specified locale settings.
+     * @param l specified Locale
+     */
+    public String getFontName(Locale l){
+        return this.getFontName();
+    }
+
+    /**
+     * Sets font name of the font in specified locale settings.
+     */
+    public void setFontName(String fontName){
+        this.faceName = fontName;
+    }
+
+    /**
+     * Returns true, if this font peer was created from InputStream, false otherwise.
+     * In case of creating fonts from InputStream some font peer implementations 
+     * may need to free temporary resources.
+     */
+    public boolean isCreatedFromStream(){
+        return this.createdFromStream;
+    }
+
+    /**
+     * Sets createdFromStream flag to the specified parameter.
+     * If parameter is true it means font peer was created from InputStream.
+     * 
+     * @param value true, if font peer was created from InputStream 
+     */
+    public void setCreatedFromStream(boolean value){
+        this.createdFromStream = value;
+    }
+
+    /**
+     * Returns font file name of this font.
+     */
+    public String getTempFontFileName(){
+        return this.tempFontFileName;
+    }
+
+    /**
+     * Sets font file name of this font to the specified one.
+     * @param value String representing font file name
+     */
+    public void setFontFileName(String value){
+        this.tempFontFileName = value;
+    }
+
+    /**
+     * Returns the advance width of the specified char of this FontPeerImpl.
+     * Note, if glyph is absent in the font's glyphset - returned value 
+     * is the advance of the deafualt glyph. For escape-chars returned 
+     * width value is 0.
+     * 
+     * @param ch the char which width is to be returned
+     * @return the advance width of the specified char of this FontPeerImpl
+     */
+    public int charWidth(char ch) {
+    	Paint p;
+    	AndroidGraphics2D g = AndroidGraphics2D.getInstance();
+    	if(g == null) {
+    		throw new RuntimeException("AndroidGraphics2D not instantiated!");
+    	}
+   		p = ((AndroidGraphics2D)g).getAndroidPaint();
+   		char[] ca = {ch};
+   		float[] fa = new float[1];
+   		p.getTextWidths(ca, 0, 1, fa);
+   		return (int)fa[0];
+    }
+
+    /**
+     * Returns the advance width of the specified char of this FontPeerImpl.
+     * 
+     * @param ind the char which width is to be returned
+     * @return the advance width of the specified char of this FontPeerImpl
+     */
+    public int charWidth(int ind) {
+        return charWidth((char)ind);
+    }
+
+    /**
+     * Returns an array of Glyphs that represent characters from the specified 
+     * Unicode range.
+     * 
+     * @param uFirst start position in Unicode range
+     * @param uLast end position in Unicode range
+     * @return
+     */
+    public Glyph[] getGlyphs(char uFirst, char uLast) {
+
+        char i = uFirst;
+        int len = uLast - uFirst;
+        ArrayList<Glyph> lst = new ArrayList<Glyph>(len);
+
+        if (size < 0) {
+            // awt.09=min range bound value is greater than max range bound
+            throw new IllegalArgumentException(Messages.getString("awt.09")); //$NON-NLS-1$
+        }
+
+        while (i < uLast) {
+            lst.add(this.getGlyph(i));
+        }
+
+        return (Glyph[]) lst.toArray();
+    }
+
+    /**
+     * Returns an array of Glyphs representing given array of chars.
+     * 
+     * @param chars specified array of chars
+     */
+    public Glyph[] getGlyphs(char[] chars) {
+        if (chars == null){
+            return null;
+        }
+
+        Glyph[] result = new Glyph[chars.length];
+
+        for (int i = 0; i < chars.length; i++) {
+            result[i] = this.getGlyph(chars[i]);
+        }
+        return result;
+    }
+
+    /**
+     * Returns an array of Glyphs representing given string.
+     * 
+     * @param str specified string
+     */
+    public Glyph[] getGlyphs(String str) {
+        char[] chars = str.toCharArray();
+        return this.getGlyphs(chars);
+    }
+
+    /**
+     * Returns family name of this FontPeerImpl.
+     */
+    public String getFamily() {
+        return fontFamilyName;
+    }
+
+    /**
+     * Returns face name of this FontPeerImpl.
+     */
+    public String getFontName() {
+        if (this.fontType == FontManager.FONT_TYPE_T1){
+            return this.fontFamilyName;
+        }
+
+        return faceName;
+    }
+
+    /**
+     * Returns height of this font peer in pixels. 
+     */
+    public int getLogicalHeight() {
+        return logicalHeight;
+    }
+
+    /**
+     * Sets height of this font peer in pixels to the given value.
+     * 
+     * @param newHeight new height in pixels value
+     */
+    public void setLogicalHeight(int newHeight) {
+        logicalHeight = newHeight;
+    }
+
+    /**
+     * Returns font size. 
+     */
+    public int getSize() {
+        return size;
+    }
+
+    /**
+     * Returns font style. 
+     */
+    public int getStyle() {
+        return style;
+    }
+
+    /**
+     * Returns font name. 
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the bounds of the largest char in this FontPeerImpl in 
+     * specified render context.
+     * 
+     * @param frc specified FontRenderContext
+     */
+    public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
+        return maxCharBounds;
+    }
+
+    /**
+     * Returns the number of glyphs in this FontPeerImpl.
+     */
+    public int getNumGlyphs() {
+        return  numGlyphs;
+    }
+
+    /**
+     * Returns tangens of the italic angle of this FontPeerImpl.
+     * If the FontPeerImpl has TrueType font type, italic angle value can be 
+     * calculated as (CharSlopeRun / CharSlopeRise) in terms of GDI.
+     */
+    public float getItalicAngle() {
+        return italicAngle;
+    }
+
+    /**
+     * Returns height of this font peer. 
+     */
+    public float getHeight(){
+        return height;
+    }
+
+    /**
+     * Returns cached LineMetrics object of this font peer. 
+     */
+    public LineMetrics getLineMetrics(){
+        return nlm;
+    }
+
+    /**
+     * Returns native font handle of this font peer. 
+     */
+    public long getFontHandle(){
+        return pFont;
+    }
+
+    /**
+     * Returns ascent of this font peer. 
+     */
+    public int getAscent(){
+    	Paint p;
+    	AndroidGraphics2D g = AndroidGraphics2D.getInstance();
+    	if(g == null) {
+    		throw new RuntimeException("AndroidGraphics2D not instantiated!");
+    	}
+   		p = ((AndroidGraphics2D)g).getAndroidPaint();
+   		return (int)p.ascent();
+        //return ascent;
+    }
+
+    /**
+     * Returns descent of this font peer. 
+     */
+    public int getDescent(){
+        return descent;
+    }
+
+    /**
+     * Returns leading of this font peer. 
+     */
+    public int getLeading(){
+        return leading;
+    }
+
+    /**
+     * Returns true if this font peer has uniform line metrics. 
+     */
+    public boolean hasUniformLineMetrics(){
+        return uniformLM;
+    }
+
+    /**
+     * Returns type of this font.
+     *  
+     * @return one of constant font type values. 
+     */    
+    public int getFontType(){
+        return fontType;
+    }
+
+    /**
+     * Sets new font type to the font object.
+     * 
+     * @param newType new type value
+     */
+    public void setFontType(int newType){
+        if (newType == FontManager.FONT_TYPE_T1 || newType == FontManager.FONT_TYPE_TT){
+            fontType = newType;
+        }
+    }
+
+    /**
+     * Sets new font type to the font object.
+     * 
+     * @param newType new type value
+     */
+    @Override
+    protected void finalize() throws Throwable {
+      super.finalize();
+      
+      dispose();
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontProperty.java b/awt/org/apache/harmony/awt/gl/font/FontProperty.java
new file mode 100644
index 0000000..4eb7cbb
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontProperty.java
@@ -0,0 +1,106 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+
+/**
+ * Class containing font property information. This information can be found 
+ * in font.property files. See API documentation, logical fonts description part. 
+ *
+ */
+public class FontProperty {
+
+    // font file name 
+    String fileName = null;
+    
+    // name of the encoding to be used 
+    String encoding = null;
+    
+    // array of exclusion ranges (pairs of low and high unicode exclusion bounds)
+    int[] exclRange = null;
+    
+    // font face name
+    String name = null;
+    
+    // font style
+    int style = -1;
+
+    /**
+     * Returns font style of this font property. 
+     */
+    public int getStyle(){
+        return this.style;
+    }
+
+    /**
+     * Returns font name of this font property. 
+     */
+    public String getName(){
+        return this.name;
+    }
+
+    /**
+     * Returns encoding used in this font property. 
+     */
+    public String getEncoding(){
+        return this.encoding;
+    }
+    
+    /**
+     * Returns an array of exclusion ranges. This array contain pairs of 
+     * low and high bounds of the intervals of characters to ignore in 
+     * total Unicode characters range.   
+     */
+    public int[] getExclusionRange(){
+        return this.exclRange;
+    }
+
+    /**
+     * Returns file name of the font that is described by this font property. 
+     */
+    public String getFileName(){
+        return this.fileName;
+    }
+
+    /**
+     * Returns true if specified character covered by exclusion ranges of this 
+     * font property, false otherwise.
+     * 
+     * @param ch specified char to check
+     */
+    public boolean isCharExcluded(char ch){
+        if (exclRange == null ){
+            return false;
+        }
+
+        for (int i = 0; i < exclRange.length;){
+            int lb = exclRange[i++];
+            int hb = exclRange[i++];
+
+            if (ch >= lb && ch <= hb){
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/Glyph.java b/awt/org/apache/harmony/awt/gl/font/Glyph.java
new file mode 100644
index 0000000..44b8809
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/Glyph.java
@@ -0,0 +1,236 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Shape;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+import java.awt.image.BufferedImage;
+
+public abstract class Glyph{
+
+    // character of the glyph
+    char glChar;
+    
+    // precise glyph metrics
+    GlyphMetrics glMetrics;
+    
+    // glyph metrics in pixels
+    GlyphMetrics glPointMetrics;
+    
+    //  glyph code of this Glyph
+    int glCode;
+    
+    // justification info of this glyph
+    GlyphJustificationInfo glJustInfo;
+    
+    // native font handle of the font corresponding to this glyph
+    long pFont;
+    
+    // size of the font corresponding to this glyph
+    int fontSize;
+    
+    // bitmap representation of the glyph
+    byte[] bitmap = null;
+    
+    // Buffered image representation of the glyph
+    BufferedImage image;
+    
+    // shape that representing the outline of this glyph
+    Shape glOutline = null;
+
+    /**
+     * image bitmap parameters
+     */
+    
+    //  top side bearing
+    public int bmp_top = 0;
+    
+    // left side bearing
+    public int bmp_left = 0;
+
+    // number of bytes in row
+    public int bmp_pitch;
+    
+    // number of rows
+    public int bmp_rows;
+    
+    // width of the row
+    public int bmp_width;
+
+    /**
+     *  Retruns handle to Native Font object
+     */
+    public long getPFont(){
+        return this.pFont;
+    }
+
+    /**
+     *  Retruns char value of this glyph object
+     */
+    public char getChar(){
+        return glChar;
+    }
+
+    /**
+     *  Retruns precise width of this glyph object
+     */
+    public int getWidth(){
+        return Math.round((float)glMetrics.getBounds2D().getWidth());
+    }
+
+    /**
+     *  Retruns precise height of this glyph object
+     */
+    public int getHeight(){
+        return Math.round((float)glMetrics.getBounds2D().getHeight());
+    }
+
+    /**
+     *  Retruns glyph code of this glyph object
+     */
+    public int getGlyphCode(){
+        return glCode;
+    }
+
+    /**
+     *  Retruns GlyphMetrics of this glyph object with precise metrics.
+     */
+    public GlyphMetrics getGlyphMetrics(){
+        return glMetrics;
+    }
+
+    /**
+     *  Retruns GlyphMetrics of this glyph object in pixels.
+     */
+    public GlyphMetrics getGlyphPointMetrics(){
+        return glPointMetrics;
+    }
+
+    /**
+     *  Retruns GlyphJustificationInfo of this glyph object
+     */
+    public GlyphJustificationInfo getGlyphJustificationInfo(){
+        return glJustInfo;
+    }
+
+    /**
+     *  Sets JustificationInfo of this glyph object
+     * 
+     * @param newJustInfo GlyphJustificationInfo object to set to the Glyph object 
+     */
+    public void setGlyphJustificationInfo(GlyphJustificationInfo newJustInfo){
+        this.glJustInfo = newJustInfo;
+    }
+
+    /**
+     * Returns an int array of 3 elements, so-called ABC structure that contains 
+     * the width of the character:
+     * 1st element = left side bearing of the glyph
+     * 2nd element = width of the glyph
+     * 3d element = right side bearing of the glyph 
+     */
+    public int[] getABC(){
+        int[] abc = new int[3];
+        abc[0] = (int)glMetrics.getLSB();
+        abc[1] = (int)glMetrics.getBounds2D().getWidth();
+        abc[2] = (int)glMetrics.getRSB();
+
+        return abc;
+    }
+
+    /**
+     * Sets BufferedImage representation of this glyph to the specified parameter.
+     * 
+     * @param newImage new BufferedImage object to be set as BufferedImage 
+     * representation.
+     */
+    public void setImage(BufferedImage newImage){
+        this.image = newImage;
+    }
+
+    /**
+     * Returns true if this Glyph and specified object are equal.
+     */
+    @Override
+    public boolean equals(Object obj){
+         if (obj == this) {
+            return true;
+        }
+
+        if (obj != null) {
+          try {
+            Glyph gl = (Glyph)obj;
+
+            return  ((this.getChar() == gl.getChar())
+              && (this.getGlyphMetrics().equals(gl.getGlyphMetrics()))
+              && (this.getGlyphCode() == gl.getGlyphCode()));
+          } catch (ClassCastException e) {
+          }
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns height of the glyph in points. 
+     */
+    public int getPointHeight(){
+        return (int)glPointMetrics.getBounds2D().getHeight();
+    }
+
+    /**
+     * Returns width of the glyph in points. 
+     */
+    public int getPointWidth(){
+        return (int)glPointMetrics.getBounds2D().getWidth();
+    }
+
+    public Shape getShape(){
+        if (glOutline == null){
+            glOutline = initOutline(this.glChar);
+        }
+        return glOutline;
+    }
+
+    /**
+     * Sets BufferedImage representation of this glyph.
+     */
+    public BufferedImage getImage(){
+        //!! Implementation classes must override this method
+        return null;
+    }
+
+    /**
+     *  Returns array of bytes, representing image of this glyph
+     */
+    public abstract byte[] getBitmap();
+
+    /**
+     * Returns shape that represents outline of the specified character. 
+     * 
+     * @param c specified character
+     */
+    public abstract Shape initOutline(char c);
+
+}
+
+
diff --git a/awt/org/apache/harmony/awt/gl/font/LineMetricsImpl.java b/awt/org/apache/harmony/awt/gl/font/LineMetricsImpl.java
new file mode 100644
index 0000000..370146d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/LineMetricsImpl.java
@@ -0,0 +1,412 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.LineMetrics;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ *
+ * LineMetrics implementation class.
+ */
+
+public class LineMetricsImpl extends LineMetrics implements Cloneable{
+
+    // array of baseline offsets
+    float[] baselineOffsets;
+
+    // the number of characters to measure
+    int numChars;
+
+    // baseline index of the font corresponding to this line metrics
+    int baseLineIndex;
+
+    // underline thickness
+    float underlineThickness;
+
+    // underline offset
+    float underlineOffset;
+
+    // strikethrough thickness
+    float strikethroughThickness;
+
+    // strikethrough offset
+    float strikethroughOffset;
+
+    // External leading
+    float leading;
+
+    // Height of the font ( == (ascent+descent+leading))
+    float height;
+
+    // Ascent of the font
+    float ascent;
+
+    // Descent of the font
+    float descent;
+
+    // Width of the widest char in the font
+    float maxCharWidth;
+
+    // underline thickness (in pixels)
+    int lUnderlineThickness;
+
+    // underline offset (in pixels)
+    int lUnderlineOffset;
+
+    // strikethrough thickness (in pixels)
+    int lStrikethroughThickness;
+
+    // strikethrough offset (in pixels)
+    int lStrikethroughOffset;
+
+    // External leading (in pixels)
+    int lLeading;
+
+    // Height of the font ( == (ascent+descent+leading)) (in pixels)
+    int lHeight;
+
+    // Ascent of the font (in pixels)
+    int lAscent;
+    
+    // Descent of the font (in pixels)
+    int lDescent;
+
+    //  Width of the widest char in the font (in pixels)
+    int lMaxCharWidth;
+
+    // units per EM square in font value
+    int units_per_EM = 0;
+
+    /**
+     * Creates LineMetricsImpl object from specified parameters. If baseline data parameter
+     * is null than {0, (-ascent+descent)/2, -ascent} values are used for baseline offsets.
+     *  
+     * @param len a number of characters 
+     * @param metrics an array of 16 elements with metrics values that can be 
+     * initialized in native code.<p>
+     * metrics[0] - ascent<p>
+     * metrics[1] - descent<p>
+     * metrics[2] - external leading<p>
+     * metrics[3] - underline thickness<p>
+     * -metrics[4] - underline offset<p>
+     * metrics[5] - strikethrough thickness<p>
+     * -metrics[6] - strikethrough offset<p>
+     * metrics[7] - maximum char width<p>
+     * metrics[8] - ascent in pixels<p>
+     * metrics[9] - descent in pixles<p>
+     * metrics[10] - external leading in pixels<p>
+     * metrics[11] - underline thickness in pixels<p>
+     * -metrics[12] - underline offset in pixels<p>
+     * metrics[13] - strikethrough thickness in pixels<p>
+     * -metrics[14] - strikethrough offset in pixels<p>
+     * metrics[15] - maximum char width in pixels<p>
+
+     * @param _baselineData an array of 3 elements with baseline offsets metrics<p>
+     * _baselineData[0] - roman baseline offset<p> 
+     * _baselineData[1] - center baseline offset<p>
+     * _baselineData[2] - hanging baseline offset<p>
+     */
+    public LineMetricsImpl(int len, float[] metrics, float[] _baselineData){
+        numChars = len;
+
+        ascent = metrics[0];    // Ascent of the font
+        descent = metrics[1];   // Descent of the font
+        leading = metrics[2];  // External leading
+        height = metrics[0] + metrics[1] + metrics[2];  // Height of the font ( == (ascent + descent + leading))
+    }
+
+    /**
+     * Creates LineMetricsImpl object from specified parameters. If baseline data parameter
+     * is null than {0, (-ascent+descent)/2, -ascent} values are used for baseline offsets.
+     *  
+     * @param _numChars number of chars 
+     * @param _baseLineIndex index of the baseline offset
+     * @param _baselineOffsets an array of baseline offsets
+     * @param _underlineThickness underline thickness
+     * @param _underlineOffset underline offset
+     * @param _strikethroughThickness strikethrough thickness
+     * @param _strikethroughOffset strinkethrough offset
+     * @param _leading leading of the font
+     * @param _height font height
+     * @param _ascent ascent of the font
+     * @param _descent descent of the font
+     * @param _maxCharWidth max char width
+     */
+    public LineMetricsImpl(int _numChars, int _baseLineIndex,
+            float[] _baselineOffsets, float _underlineThickness,
+            float _underlineOffset, float _strikethroughThickness,
+            float _strikethroughOffset, float _leading, float _height,
+            float _ascent, float _descent, float _maxCharWidth) {
+
+        numChars = _numChars;
+        baseLineIndex = _baseLineIndex;
+        underlineThickness = _underlineThickness;
+        underlineOffset = _underlineOffset;
+        strikethroughThickness = _strikethroughThickness;
+        strikethroughOffset = _strikethroughOffset;
+        leading = _leading;
+        height = _height;
+        ascent = _ascent;
+        descent = _descent;
+        baselineOffsets = _baselineOffsets;
+        lUnderlineThickness = (int) underlineThickness;
+        lUnderlineOffset = (int) underlineOffset;
+        lStrikethroughThickness = (int) strikethroughThickness;
+        lStrikethroughOffset = (int) strikethroughOffset;
+        lLeading = (int) leading;
+        lHeight = (int) height;
+        lAscent = (int) ascent;
+        lDescent = (int) descent;
+        maxCharWidth = _maxCharWidth;
+    }
+
+    public LineMetricsImpl(){
+
+    }
+
+    /**
+     * All metrics are scaled according to scaleX and scaleY values. 
+     * This function helps to recompute metrics according to the scale factors
+     * of desired AffineTransform.
+     * 
+     * @param scaleX scale X factor
+     * @param scaleY scale Y factor
+     */
+    public void scale(float scaleX, float scaleY){
+        float absScaleX = Math.abs(scaleX);
+        float absScaleY = Math.abs(scaleY);
+
+        underlineThickness *= absScaleY;
+        underlineOffset *= scaleY;
+        strikethroughThickness *= absScaleY;
+        strikethroughOffset *= scaleY;
+        leading *= absScaleY;
+        height *= absScaleY;
+        ascent *= absScaleY;
+        descent *= absScaleY;
+
+        if(baselineOffsets == null) {
+            getBaselineOffsets();
+        }
+
+        for (int i=0; i< baselineOffsets.length; i++){
+            baselineOffsets[i] *= scaleY;
+        }
+
+        lUnderlineThickness *= absScaleY;
+        lUnderlineOffset *= scaleY;
+        lStrikethroughThickness *= absScaleY;
+        lStrikethroughOffset *= scaleY;
+        lLeading  *= absScaleY;
+        lHeight *= absScaleY;
+        lAscent *= absScaleY;
+        lDescent *= absScaleY;
+        maxCharWidth *= absScaleX;
+
+    }
+
+
+    /**
+     * Returns offset of the baseline.
+     */
+    @Override
+    public float[] getBaselineOffsets() {
+        // XXX: at the moment there only horizontal metrics are taken into
+        // account. If there is no baseline information in TrueType font
+        // file default values used: {0, -ascent, (-ascent+descent)/2}
+
+        return baselineOffsets;
+    }
+
+    /**
+     * Returns a number of chars in specified text
+     */
+    @Override
+    public int getNumChars() {
+        return numChars;
+    }
+
+    /**
+     * Returns index of the baseline, one of predefined constants.
+     */
+    @Override
+    public int getBaselineIndex() {
+        // Baseline index is the deafult baseline index value
+        // taken from the TrueType table "BASE".
+        return baseLineIndex;
+    }
+
+    /**
+     * Returns thickness of the Underline.
+     */
+    @Override
+    public float getUnderlineThickness() {
+        return underlineThickness;
+    }
+
+    /**
+     * Returns offset of the Underline.
+     */
+    @Override
+    public float getUnderlineOffset() {
+        return underlineOffset;
+    }
+
+    /**
+     * Returns thickness of the Strikethrough line.
+     */
+    @Override
+    public float getStrikethroughThickness() {
+        return strikethroughThickness;
+    }
+
+    /**
+     * Returns offset of the Strikethrough line.
+     */
+    @Override
+    public float getStrikethroughOffset() {
+        return strikethroughOffset;
+    }
+
+    /**
+     * Returns the leading.
+     */
+    @Override
+    public float getLeading() {
+        return leading;
+    }
+
+    /**
+     * Returns the height of the font.
+     */
+    @Override
+    public float getHeight() {
+        //return height; // equals to (ascent + descent + leading);
+    	return ascent + descent + leading;
+    }
+
+    /**
+     * Returns the descent.
+     */
+    @Override
+    public float getDescent() {
+        return descent;
+    }
+
+    /**
+     * Returns the ascent.
+     */
+    @Override
+    public float getAscent() {
+        return ascent;
+    }
+
+    /**
+     * Returns logical thickness of the Underline.
+     */
+    public int getLogicalUnderlineThickness() {
+        return lUnderlineThickness;
+    }
+
+    /**
+     * Returns logical offset of the Underline.
+     */
+    public int getLogicalUnderlineOffset() {
+        return lUnderlineOffset;
+    }
+
+    /**
+     * Returns logical thickness of the Strikethrough line.
+     */
+    public int getLogicalStrikethroughThickness() {
+        return lStrikethroughThickness;
+    }
+
+    /**
+     * Returns logical offset of the Strikethrough line.
+     */
+    public int getLogicalStrikethroughOffset() {
+        return lStrikethroughOffset;
+    }
+
+    /**
+     * Returns the logical leading.
+     */
+    public int getLogicalLeading() {
+        return lLeading;
+    }
+
+    /**
+     * Returns the logical height of the font.
+     */
+    public int getLogicalHeight() {
+        return lHeight; // equals to (ascent + descent + leading);
+    }
+
+    /**
+     * Returns the logical descent.
+     */
+    public int getLogicalDescent() {
+        return lDescent;
+    }
+
+    /**
+     * Returns the logical ascent.
+     */
+    public int getLogicalAscent() {
+        return lAscent;
+    }
+
+    /**
+     * Returns the logical size of the widest char.
+     */
+    public int getLogicalMaxCharWidth() {
+        return lMaxCharWidth;
+    }
+
+    /**
+     * Returns the size of the widest char.
+     */
+    public float getMaxCharWidth() {
+        return maxCharWidth;
+    }
+
+    /**
+     * Set num chars to the desired value.
+     * 
+     * @param num specified number of chars
+     */
+    public void setNumChars(int num){
+        numChars = num;
+    }
+
+    @Override
+    public Object clone(){
+        try{
+            return super.clone();
+        }catch (CloneNotSupportedException e){
+            return null;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/font/TextDecorator.java b/awt/org/apache/harmony/awt/gl/font/TextDecorator.java
new file mode 100644
index 0000000..81905fd
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextDecorator.java
@@ -0,0 +1,433 @@
+/*
+ *  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.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.font.TextAttribute;
+import java.awt.geom.Area;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.Map;
+
+/**
+ * This class is responsible for rendering text decorations like
+ * underline, strikethrough, text with background, etc.
+ */
+public class TextDecorator {
+    private static final TextDecorator inst = new TextDecorator();
+    private TextDecorator() {}
+    static TextDecorator getInstance() {
+        return inst;
+    }
+
+    /**
+     * This class encapsulates a set of decoration attributes for a single text run.
+     */
+    static class Decoration {
+        private static final BasicStroke UNDERLINE_LOW_ONE_PIXEL_STROKE =
+                new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10);
+
+        private static final BasicStroke UNDERLINE_LOW_TWO_PIXEL_STROKE =
+                new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10);
+
+        private static final BasicStroke UNDERLINE_LOW_DOTTED_STROKE =
+                new BasicStroke(
+                        1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,
+                        new float[] { 1, 1 }, 0
+                );
+
+        private static final BasicStroke UNDERLINE_LOW_DOTTED_STROKE2 =
+                new BasicStroke(
+                        1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,
+                        new float[] { 1, 1 }, 1
+                );
+
+        private static final BasicStroke UNDERLINE_LOW_DASHED_STROKE =
+                new BasicStroke(
+                        1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,
+                        new float[] { 4, 4 }, 0
+                );
+
+        boolean ulOn = false; // Have standard underline?
+        BasicStroke ulStroke;
+
+        BasicStroke imUlStroke;  // Stroke for INPUT_METHOD_UNDERLINE
+        BasicStroke imUlStroke2; // Specially for UNDERLINE_LOW_GRAY
+
+        boolean strikeThrough;
+        BasicStroke strikeThroughStroke;
+
+        boolean haveStrokes = false; // Strokes already created?
+
+        boolean swapBfFg;
+        Paint bg; // background color
+        Paint fg; // foreground color
+
+        Paint graphicsPaint; // Slot for saving current paint
+
+        Decoration(
+                Integer imUl,
+                boolean swap,
+                boolean sth,
+                Paint bg, Paint fg,
+                boolean ulOn) {
+
+            if (imUl != null) {
+                // Determine which stroke to use
+                if (imUl == TextAttribute.UNDERLINE_LOW_ONE_PIXEL) {
+                    this.imUlStroke = Decoration.UNDERLINE_LOW_ONE_PIXEL_STROKE;
+                } else if (imUl == TextAttribute.UNDERLINE_LOW_TWO_PIXEL) {
+                    this.imUlStroke = Decoration.UNDERLINE_LOW_TWO_PIXEL_STROKE;
+                } else if (imUl == TextAttribute.UNDERLINE_LOW_DOTTED) {
+                    this.imUlStroke = Decoration.UNDERLINE_LOW_DOTTED_STROKE;
+                } else if (imUl == TextAttribute.UNDERLINE_LOW_GRAY) {
+                    this.imUlStroke = Decoration.UNDERLINE_LOW_DOTTED_STROKE;
+                    this.imUlStroke2 = Decoration.UNDERLINE_LOW_DOTTED_STROKE2;
+                } else if (imUl == TextAttribute.UNDERLINE_LOW_DASHED) {
+                    this.imUlStroke = Decoration.UNDERLINE_LOW_DASHED_STROKE;
+                }
+            }
+
+            this.ulOn = ulOn; // Has underline
+            this.swapBfFg = swap;
+            this.strikeThrough = sth;
+            this.bg = bg;
+            this.fg = fg;
+        }
+
+        /**
+         * Creates strokes of proper width according to the info
+         * stored in the BasicMetrics
+         * @param metrics - basic metrics
+         */
+        private void getStrokes(BasicMetrics metrics) {
+            if (!haveStrokes) {
+                if (strikeThrough) {
+                    strikeThroughStroke =
+                            new BasicStroke(
+                                    metrics.strikethroughThickness,
+                                    BasicStroke.CAP_BUTT,
+                                    BasicStroke.JOIN_MITER,
+                                    10
+                            );
+                }
+
+                if (ulOn) {
+                    ulStroke =
+                            new BasicStroke(
+                                    metrics.underlineThickness,
+                                    BasicStroke.CAP_BUTT,
+                                    BasicStroke.JOIN_MITER,
+                                    10
+                            );
+                }
+
+                haveStrokes = true;
+            }
+        }
+    }
+
+    /**
+     * Creates Decoration object from the set of text attributes
+     * @param attributes - text attributes
+     * @return Decoration object
+     */
+    static Decoration getDecoration(Map<? extends Attribute, ?> attributes) {
+        if (attributes == null) {
+            return null; // It is for plain text
+        }
+
+        Object underline = attributes.get(TextAttribute.UNDERLINE);
+        boolean hasStandardUnderline = underline == TextAttribute.UNDERLINE_ON;
+
+        Object imUnderline = attributes.get(TextAttribute.INPUT_METHOD_UNDERLINE);
+        Integer imUl = (Integer) imUnderline;
+
+        boolean swapBgFg =
+                TextAttribute.SWAP_COLORS_ON.equals(
+                        attributes.get(TextAttribute.SWAP_COLORS)
+                );
+
+        boolean strikeThrough =
+                TextAttribute.STRIKETHROUGH_ON.equals(
+                        attributes.get(TextAttribute.STRIKETHROUGH)
+                );
+
+        Paint fg = (Paint) attributes.get(TextAttribute.FOREGROUND);
+        Paint bg = (Paint) attributes.get(TextAttribute.BACKGROUND);
+
+        if (
+                !hasStandardUnderline &&
+                imUnderline == null &&
+                fg == null &&
+                bg == null &&
+                !swapBgFg &&
+                !strikeThrough
+        ) {
+            return null;
+        }
+        return new Decoration(imUl, swapBgFg, strikeThrough, bg, fg, hasStandardUnderline);
+    }
+
+    /**
+     * Fills the background before drawing if needed.
+     * 
+     * @param trs - text segment
+     * @param g2d - graphics to draw to
+     * @param xOffset - offset in X direction to the upper left corner of the
+     *        layout from the origin of the graphics
+     * @param yOffset - offset in Y direction to the upper left corner of the
+     *        layout from the origin of the graphics
+     */
+    static void prepareGraphics(
+            TextRunSegment trs, Graphics2D g2d,
+            float xOffset, float yOffset
+    ) {
+        Decoration d = trs.decoration;
+
+        if (d.fg == null && d.bg == null && d.swapBfFg == false) {
+            return; // Nothing to do
+        }
+
+        d.graphicsPaint = g2d.getPaint();
+
+        if (d.fg == null) {
+            d.fg = d.graphicsPaint;
+        }
+
+        if (d.swapBfFg) {
+            // Fill background area
+            g2d.setPaint(d.fg);
+            Rectangle2D bgArea = trs.getLogicalBounds();
+            Rectangle2D toFill =
+                    new Rectangle2D.Double(
+                            bgArea.getX() + xOffset,
+                            bgArea.getY() + yOffset,
+                            bgArea.getWidth(),
+                            bgArea.getHeight()
+                    );
+            g2d.fill(toFill);
+
+            // Set foreground color
+            g2d.setPaint(d.bg == null ? Color.WHITE : d.bg);
+        } else {
+            if (d.bg != null) { // Fill background area
+                g2d.setPaint(d.bg);
+                Rectangle2D bgArea = trs.getLogicalBounds();
+                Rectangle2D toFill =
+                        new Rectangle2D.Double(
+                                bgArea.getX() + xOffset,
+                                bgArea.getY() + yOffset,
+                                bgArea.getWidth(),
+                                bgArea.getHeight()
+                        );
+                g2d.fill(toFill);
+            }
+
+            // Set foreground color
+            g2d.setPaint(d.fg);
+        }
+    }
+
+    /**
+     * Restores the original state of the graphics if needed
+     * @param d - decoration
+     * @param g2d - graphics
+     */
+    static void restoreGraphics(Decoration d, Graphics2D g2d) {
+        if (d.fg == null && d.bg == null && d.swapBfFg == false) {
+            return; // Nothing to do
+        }
+
+        g2d.setPaint(d.graphicsPaint);
+    }
+
+    /**
+     * Renders the text decorations
+     * @param trs - text run segment
+     * @param g2d - graphics to render to
+     * @param xOffset - offset in X direction to the upper left corner
+     * of the layout from the origin of the graphics
+     * @param yOffset - offset in Y direction to the upper left corner
+     * of the layout from the origin of the graphics
+     */
+    static void drawTextDecorations(
+            TextRunSegment trs, Graphics2D g2d,
+            float xOffset, float yOffset
+    ) {
+        Decoration d = trs.decoration;
+
+        if (!d.ulOn && d.imUlStroke == null && !d.strikeThrough) {
+            return; // Nothing to do
+        }
+
+        float left = xOffset + (float) trs.getLogicalBounds().getMinX();
+        float right = xOffset + (float) trs.getLogicalBounds().getMaxX();
+
+        Stroke savedStroke = g2d.getStroke();
+
+        d.getStrokes(trs.metrics);
+
+        if (d.strikeThrough) {
+            float y = trs.y + yOffset + trs.metrics.strikethroughOffset;
+            g2d.setStroke(d.strikeThroughStroke);
+            g2d.draw(new Line2D.Float(left, y, right, y));
+        }
+
+        if (d.ulOn) {
+            float y = trs.y + yOffset + trs.metrics.underlineOffset;
+            g2d.setStroke(d.ulStroke);
+            g2d.draw(new Line2D.Float(left, y, right, y));
+        }
+
+        if (d.imUlStroke != null) {
+            float y = trs.y + yOffset + trs.metrics.underlineOffset;
+            g2d.setStroke(d.imUlStroke);
+            g2d.draw(new Line2D.Float(left, y, right, y));
+            if (d.imUlStroke2 != null) {
+                y++;
+                g2d.setStroke(d.imUlStroke2);
+                g2d.draw(new Line2D.Float(left, y, right, y));
+            }
+        }
+
+        g2d.setStroke(savedStroke);
+    }
+
+    /**
+     * Extends the visual bounds of the text run segment to
+     * include text decorations.
+     * @param trs - text segment
+     * @param segmentBounds - bounds of the undecorated text
+     * @param d - decoration
+     * @return extended bounds
+     */
+    static Rectangle2D extendVisualBounds(
+            TextRunSegment trs,
+            Rectangle2D segmentBounds,
+            Decoration d
+    ) {
+        if (d == null) {
+            return segmentBounds;
+        }
+        double minx = segmentBounds.getMinX();
+        double miny = segmentBounds.getMinY();
+        double maxx = segmentBounds.getMaxX();
+        double maxy = segmentBounds.getMaxY();
+
+        Rectangle2D lb = trs.getLogicalBounds();
+
+        if (d.swapBfFg || d.bg != null) {
+            minx = Math.min(lb.getMinX() - trs.x, minx);
+            miny = Math.min(lb.getMinY() - trs.y, miny);
+            maxx = Math.max(lb.getMaxX() - trs.x, maxx);
+            maxy = Math.max(lb.getMaxY() - trs.y, maxy);
+        }
+
+        if (d.ulOn || d.imUlStroke != null || d.strikeThrough) {
+            minx = Math.min(lb.getMinX() - trs.x, minx);
+            maxx = Math.max(lb.getMaxX() - trs.x, maxx);
+
+            d.getStrokes(trs.metrics);
+
+            if (d.ulStroke != null) {
+                maxy = Math.max(
+                        maxy,
+                        trs.metrics.underlineOffset +
+                        d.ulStroke.getLineWidth()
+                );
+            }
+
+            if (d.imUlStroke != null) {
+                maxy = Math.max(
+                        maxy,
+                        trs.metrics.underlineOffset +
+                        d.imUlStroke.getLineWidth() +
+                        (d.imUlStroke2 == null ? 0 : d.imUlStroke2.getLineWidth())
+                );
+            }
+        }
+
+        return new Rectangle2D.Double(minx, miny, maxx-minx, maxy-miny);
+    }
+
+    /**
+     * Extends the outline of the text run segment to
+     * include text decorations.
+     * @param trs - text segment
+     * @param segmentOutline - outline of the undecorated text
+     * @param d - decoration
+     * @return extended outline
+     */
+    static Shape extendOutline(
+            TextRunSegment trs,
+            Shape segmentOutline,
+            Decoration d
+    ) {
+        if (d == null || !d.ulOn && d.imUlStroke == null && !d.strikeThrough) {
+            return segmentOutline; // Nothing to do
+        }
+
+        Area res = new Area(segmentOutline);
+
+        float left = (float) trs.getLogicalBounds().getMinX() - trs.x;
+        float right = (float) trs.getLogicalBounds().getMaxX() - trs.x;
+
+        d.getStrokes(trs.metrics);
+
+        if (d.strikeThrough) {
+            float y = trs.metrics.strikethroughOffset;
+            res.add(new Area(d.strikeThroughStroke.createStrokedShape(
+                    new Line2D.Float(left, y, right, y)
+            )));
+        }
+
+        if (d.ulOn) {
+            float y = trs.metrics.underlineOffset;
+            res.add(new Area(d.ulStroke.createStrokedShape(
+                    new Line2D.Float(left, y, right, y)
+            )));
+        }
+
+        if (d.imUlStroke != null) {
+            float y = trs.metrics.underlineOffset;
+            res.add(new Area(d.imUlStroke.createStrokedShape(
+                    new Line2D.Float(left, y, right, y)
+            )));
+
+            if (d.imUlStroke2 != null) {
+                y++;
+                res.add(new Area(d.imUlStroke2.createStrokedShape(
+                        new Line2D.Float(left, y, right, y)
+                )));
+            }
+        }
+
+        return res;
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java b/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java
new file mode 100644
index 0000000..be5762a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java
@@ -0,0 +1,209 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.LineMetrics;
+import java.awt.font.GraphicAttribute;
+import java.awt.Font;
+import java.util.HashMap;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class operates with an arbitrary text string which can include
+ * any number of style, font and direction runs. It is responsible for computation
+ * of the text metrics, such as ascent, descent, leading and advance. Actually,
+ * each text run segment contains logic which allows it to compute its own metrics and
+ * responsibility of this class is to combine metrics for all segments included in the text,
+ * managed by the associated TextRunBreaker object.
+ */
+public class TextMetricsCalculator {
+    TextRunBreaker breaker; // Associated run breaker
+
+    // Metrics
+    float ascent = 0;
+    float descent = 0;
+    float leading = 0;
+    float advance = 0;
+
+    private float baselineOffsets[];
+    int baselineIndex;
+
+    public TextMetricsCalculator(TextRunBreaker breaker) {
+        this.breaker = breaker;
+        checkBaselines();
+    }
+
+    /**
+     * Returns either values cached by checkBaselines method or reasonable
+     * values for the TOP and BOTTOM alignments.
+     * @param baselineIndex - baseline index
+     * @return baseline offset
+     */
+    float getBaselineOffset(int baselineIndex) {
+        if (baselineIndex >= 0) {
+            return baselineOffsets[baselineIndex];
+        } else if (baselineIndex == GraphicAttribute.BOTTOM_ALIGNMENT) {
+            return descent;
+        } else if (baselineIndex == GraphicAttribute.TOP_ALIGNMENT) {
+            return -ascent;
+        } else {
+            // awt.3F=Invalid baseline index
+            throw new IllegalArgumentException(Messages.getString("awt.3F")); //$NON-NLS-1$
+        }
+    }
+
+    public float[] getBaselineOffsets() {
+        float ret[] = new float[baselineOffsets.length];
+        System.arraycopy(baselineOffsets, 0, ret, 0, baselineOffsets.length);
+        return ret;
+    }
+
+    /**
+     * Take baseline offsets from the first font or graphic attribute
+     * and normalizes them, than caches the results.
+     */
+    public void checkBaselines() {
+        // Take baseline offsets of the first font and normalize them
+        HashMap<Integer, Font> fonts = breaker.fonts;
+
+        Object val = fonts.get(new Integer(0));
+
+        if (val instanceof Font) {
+            Font firstFont = (Font) val;
+            LineMetrics lm = firstFont.getLineMetrics(breaker.text, 0, 1, breaker.frc);
+            baselineOffsets = lm.getBaselineOffsets();
+            baselineIndex = lm.getBaselineIndex();
+        } else if (val instanceof GraphicAttribute) {
+            // Get first graphic attribute and use it
+            GraphicAttribute ga = (GraphicAttribute) val;
+
+            int align = ga.getAlignment();
+
+            if (
+                    align == GraphicAttribute.TOP_ALIGNMENT ||
+                    align == GraphicAttribute.BOTTOM_ALIGNMENT
+            ) {
+                baselineIndex = GraphicAttribute.ROMAN_BASELINE;
+            } else {
+                baselineIndex = align;
+            }
+
+            baselineOffsets = new float[3];
+            baselineOffsets[0] = 0;
+            baselineOffsets[1] = (ga.getDescent() - ga.getAscent()) / 2.f;
+            baselineOffsets[2] = -ga.getAscent();
+        } else { // Use defaults - Roman baseline and zero offsets
+            baselineIndex = GraphicAttribute.ROMAN_BASELINE;
+            baselineOffsets = new float[3];
+        }
+
+        // Normalize offsets if needed
+        if (baselineOffsets[baselineIndex] != 0) {
+            float baseOffset = baselineOffsets[baselineIndex];
+            for (int i = 0; i < baselineOffsets.length; i++) {
+                baselineOffsets[i] -= baseOffset;
+            }
+        }
+    }
+
+    /**
+     * Computes metrics for the text managed by the associated TextRunBreaker
+     */
+    void computeMetrics() {
+
+        ArrayList<TextRunSegment> segments = breaker.runSegments;
+
+        float maxHeight = 0;
+        float maxHeightLeading = 0;
+
+        for (int i = 0; i < segments.size(); i++) {
+            TextRunSegment segment = segments.get(i);
+            BasicMetrics metrics = segment.metrics;
+            int baseline = metrics.baseLineIndex;
+
+            if (baseline >= 0) {
+                float baselineOffset = baselineOffsets[metrics.baseLineIndex];
+                float fixedDescent = metrics.descent + baselineOffset;
+
+                ascent = Math.max(ascent, metrics.ascent - baselineOffset);
+                descent = Math.max(descent, fixedDescent);
+                leading = Math.max(leading, fixedDescent + metrics.leading);
+            } else { // Position is not fixed by the baseline, need sum of ascent and descent
+                float height = metrics.ascent + metrics.descent;
+
+                maxHeight = Math.max(maxHeight, height);
+                maxHeightLeading = Math.max(maxHeightLeading, height + metrics.leading);
+            }
+        }
+
+        // Need to increase sizes for graphics?
+        if (maxHeightLeading != 0) {
+            descent = Math.max(descent, maxHeight - ascent);
+            leading = Math.max(leading, maxHeightLeading - ascent);
+        }
+
+        // Normalize leading
+        leading -= descent;
+
+        BasicMetrics currMetrics;
+        float currAdvance = 0;
+
+        for (int i = 0; i < segments.size(); i++) {
+            TextRunSegment segment = segments.get(breaker.getSegmentFromVisualOrder(i));
+            currMetrics = segment.metrics;
+
+            segment.y = getBaselineOffset(currMetrics.baseLineIndex)
+                    + currMetrics.superScriptOffset;
+            segment.x = currAdvance;
+
+            currAdvance += segment.getAdvance();
+        }
+
+        advance = currAdvance;
+    }
+
+    /**
+     * Computes metrics and creates BasicMetrics object from them
+     * @return basic metrics
+     */
+    public BasicMetrics createMetrics() {
+        computeMetrics();
+        return new BasicMetrics(this);
+    }
+
+    /**
+     * Corrects advance after justification. Gets BasicMetrics object
+     * and updates advance stored into it.
+     * @param metrics - metrics with outdated advance which should be corrected 
+     */
+    public void correctAdvance(BasicMetrics metrics) {
+        ArrayList<TextRunSegment> segments = breaker.runSegments;
+        TextRunSegment segment = segments.get(breaker
+                .getSegmentFromVisualOrder(segments.size() - 1));
+
+        advance = segment.x + segment.getAdvance();
+        metrics.advance = advance;
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/TextRunBreaker.java b/awt/org/apache/harmony/awt/gl/font/TextRunBreaker.java
new file mode 100644
index 0000000..be606f7
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextRunBreaker.java
@@ -0,0 +1,861 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Rectangle2D;
+import java.awt.im.InputMethodHighlight;
+import java.awt.font.*;
+import java.awt.*;
+import java.text.AttributedCharacterIterator;
+import java.text.Annotation;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.*;
+
+import org.apache.harmony.awt.gl.font.TextDecorator.Decoration;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+// TODO - bidi not implemented yet
+
+/**
+ * This class is responsible for breaking the text into the run segments
+ * with constant font, style, other text attributes and direction.
+ * It also stores the created text run segments and covers functionality
+ * related to the operations on the set of segments, like calculating metrics,
+ * rendering, justification, hit testing, etc.
+ */
+public class TextRunBreaker implements Cloneable {
+    AttributedCharacterIterator aci;
+    FontRenderContext frc;
+
+    char[] text;
+
+    byte[] levels;
+
+    HashMap<Integer, Font> fonts;
+    HashMap<Integer, Decoration> decorations;
+
+    // Related to default font substitution
+    int forcedFontRunStarts[];
+
+    ArrayList<TextRunSegment> runSegments = new ArrayList<TextRunSegment>();
+
+    // For fast retrieving of the segment containing
+    // character with known logical index
+    int logical2segment[];
+    int segment2visual[]; // Visual order of segments TODO - implement
+    int visual2segment[];
+    int logical2visual[];
+    int visual2logical[];
+
+    SegmentsInfo storedSegments;
+    private boolean haveAllSegments = false;
+    int segmentsStart, segmentsEnd;
+
+    float justification = 1.0f;
+
+    public TextRunBreaker(AttributedCharacterIterator aci, FontRenderContext frc) {
+        this.aci = aci;
+        this.frc = frc;
+
+        segmentsStart = aci.getBeginIndex();
+        segmentsEnd = aci.getEndIndex();
+
+        int len = segmentsEnd - segmentsStart;
+        text = new char[len];
+        aci.setIndex(segmentsEnd);
+        while (len-- != 0) { // Going in backward direction is faster? Simplier checks here?
+            text[len] = aci.previous();
+        }
+
+        createStyleRuns();
+    }
+
+    /**
+     * Visual order of text segments may differ from the logical order.
+     * This method calculates visual position of the segment from its logical position.
+     * @param segmentNum - logical position of the segment
+     * @return visual position of the segment
+     */
+    int getVisualFromSegmentOrder(int segmentNum) {
+        return (segment2visual == null) ? segmentNum : segment2visual[segmentNum];
+    }
+
+    /**
+     * Visual order of text segments may differ from the logical order.
+     * This method calculates logical position of the segment from its visual position.
+     * @param visual - visual position of the segment
+     * @return logical position of the segment
+     */
+    int getSegmentFromVisualOrder(int visual) {
+        return (visual2segment == null) ? visual : visual2segment[visual];
+    }
+
+    /**
+     * Visual order of the characters may differ from the logical order.
+     * This method calculates visual position of the character from its logical position.
+     * @param logical - logical position of the character
+     * @return visual position
+     */
+    int getVisualFromLogical(int logical) {
+        return (logical2visual == null) ? logical : logical2visual[logical];
+    }
+
+    /**
+     * Visual order of the characters may differ from the logical order.
+     * This method calculates logical position of the character from its visual position.
+     * @param visual - visual position
+     * @return logical position
+     */
+    int getLogicalFromVisual(int visual) {
+        return (visual2logical == null) ? visual : visual2logical[visual];
+    }
+
+    /**
+     * Calculates the end index of the level run, limited by the given text run.
+     * @param runStart - run start
+     * @param runEnd - run end
+     * @return end index of the level run
+     */
+    int getLevelRunLimit(int runStart, int runEnd) {
+        if (levels == null) {
+            return runEnd;
+        }
+        int endLevelRun = runStart + 1;
+        byte level = levels[runStart];
+
+        while (endLevelRun <= runEnd && levels[endLevelRun] == level) {
+            endLevelRun++;
+        }
+
+        return endLevelRun;
+    }
+
+    /**
+     * Adds InputMethodHighlight to the attributes
+     * @param attrs - text attributes
+     * @return patched text attributes
+     */
+    Map<? extends Attribute, ?> unpackAttributes(Map<? extends Attribute, ?> attrs) {
+        if (attrs.containsKey(TextAttribute.INPUT_METHOD_HIGHLIGHT)) {
+            Map<TextAttribute, ?> styles = null;
+
+            Object val = attrs.get(TextAttribute.INPUT_METHOD_HIGHLIGHT);
+
+            if (val instanceof Annotation) {
+                val = ((Annotation) val).getValue();
+            }
+
+            if (val instanceof InputMethodHighlight) {
+                InputMethodHighlight ihl = ((InputMethodHighlight) val);
+                styles = ihl.getStyle();
+
+                if (styles == null) {
+                    Toolkit tk = Toolkit.getDefaultToolkit();
+                    styles = tk.mapInputMethodHighlight(ihl);
+                }
+            }
+
+            if (styles != null) {
+                HashMap<Attribute, Object> newAttrs = new HashMap<Attribute, Object>();
+                newAttrs.putAll(attrs);
+                newAttrs.putAll(styles);
+                return newAttrs;
+            }
+        }
+
+        return attrs;
+    }
+
+    /**
+     * Breaks the text into separate style runs.
+     */
+    void createStyleRuns() {
+        // TODO - implement fast and simple case
+        fonts = new HashMap<Integer, Font>();
+        decorations = new HashMap<Integer, Decoration>();
+        ////
+
+        ArrayList<Integer> forcedFontRunStartsList = null;
+
+        Map<? extends Attribute, ?> attributes = null;
+
+        // Check justification attribute
+        Object val = aci.getAttribute(TextAttribute.JUSTIFICATION);
+        if (val != null) {
+            justification = ((Float) val).floatValue();
+        }
+
+        for (
+            int index = segmentsStart, nextRunStart = segmentsStart;
+            index < segmentsEnd;
+            index = nextRunStart, aci.setIndex(index)
+           )  {
+            nextRunStart = aci.getRunLimit();
+            attributes = unpackAttributes(aci.getAttributes());
+
+            TextDecorator.Decoration d = TextDecorator.getDecoration(attributes);
+            decorations.put(new Integer(index), d);
+
+            // Find appropriate font or place GraphicAttribute there
+
+            // 1. Try to pick up CHAR_REPLACEMENT (compatibility)
+            Font value = (Font)attributes.get(TextAttribute.CHAR_REPLACEMENT);
+
+            if (value == null) {
+                // 2. Try to Get FONT
+                value = (Font)attributes.get(TextAttribute.FONT);
+
+                if (value == null) {
+                    // 3. Try to create font from FAMILY
+                    if (attributes.get(TextAttribute.FAMILY) != null) {
+                        value = Font.getFont(attributes);
+                    }
+
+                    if (value == null) {
+                        // 4. No attributes found, using default.
+                        if (forcedFontRunStartsList == null) {
+                            forcedFontRunStartsList = new ArrayList<Integer>();
+                        }
+                        FontFinder.findFonts(
+                                text,
+                                index,
+                                nextRunStart,
+                                forcedFontRunStartsList,
+                                fonts
+                        );
+                        value = fonts.get(new Integer(index));
+                    }
+                }
+            }
+
+            fonts.put(new Integer(index), value);
+        }
+
+        // We have added some default fonts, so we have some extra runs in text
+        if (forcedFontRunStartsList != null) {
+            forcedFontRunStarts = new int[forcedFontRunStartsList.size()];
+            for (int i=0; i<forcedFontRunStartsList.size(); i++) {
+                forcedFontRunStarts[i] =
+                        forcedFontRunStartsList.get(i).intValue();
+            }
+        }
+    }
+
+    /**
+     * Starting from the current position looks for the end of the text run with
+     * constant text attributes.
+     * @param runStart - start position
+     * @param maxPos - position where to stop if no run limit found
+     * @return style run limit
+     */
+    int getStyleRunLimit(int runStart, int maxPos) {
+        try {
+            aci.setIndex(runStart);
+        } catch(IllegalArgumentException e) { // Index out of bounds
+            if (runStart < segmentsStart) {
+                aci.first();
+            } else {
+                aci.last();
+            }
+        }
+
+        // If we have some extra runs we need to check for their limits
+        if (forcedFontRunStarts != null) {
+            for (int element : forcedFontRunStarts) {
+                if (element > runStart) {
+                    maxPos = Math.min(element, maxPos);
+                    break;
+                }
+            }
+        }
+
+        return Math.min(aci.getRunLimit(), maxPos);
+    }
+
+    /**
+     * Creates segments for the text run with
+     * constant decoration, font and bidi level
+     * @param runStart - run start
+     * @param runEnd - run end
+     */
+    public void createSegments(int runStart, int runEnd) {
+        int endStyleRun, endLevelRun;
+
+        // TODO - update levels
+
+        int pos = runStart, levelPos;
+
+        aci.setIndex(pos);
+        final int firstRunStart = aci.getRunStart();
+        Object tdd = decorations.get(new Integer(firstRunStart));
+        Object fontOrGAttr = fonts.get(new Integer(firstRunStart));
+
+        logical2segment = new int[runEnd - runStart];
+
+        do {
+            endStyleRun = getStyleRunLimit(pos, runEnd);
+
+            // runStart can be non-zero, but all arrays will be indexed from 0
+            int ajustedPos = pos - runStart;
+            int ajustedEndStyleRun = endStyleRun - runStart;
+            levelPos = ajustedPos;
+            do {
+                endLevelRun = getLevelRunLimit(levelPos, ajustedEndStyleRun);
+
+                if (fontOrGAttr instanceof GraphicAttribute) {
+                    runSegments.add(
+                        new TextRunSegmentImpl.TextRunSegmentGraphic(
+                                (GraphicAttribute)fontOrGAttr,
+                                endLevelRun - levelPos,
+                                levelPos + runStart)
+                    );
+                    Arrays.fill(logical2segment, levelPos, endLevelRun, runSegments.size()-1);
+                } else {
+                    TextRunSegmentImpl.TextSegmentInfo i =
+                            new TextRunSegmentImpl.TextSegmentInfo(
+                                    levels == null ? 0 : levels[ajustedPos],
+                                    (Font) fontOrGAttr,
+                                    frc,
+                                    text,
+                                    levelPos + runStart,
+                                    endLevelRun + runStart
+                            );
+
+                    runSegments.add(
+                            new TextRunSegmentImpl.TextRunSegmentCommon(
+                                    i,
+                                    (TextDecorator.Decoration) tdd
+                            )
+                    );
+                    Arrays.fill(logical2segment, levelPos, endLevelRun, runSegments.size()-1);
+                }
+
+                levelPos = endLevelRun;
+            } while (levelPos < ajustedEndStyleRun);
+
+            // Prepare next iteration
+            pos = endStyleRun;
+            tdd = decorations.get(new Integer(pos));
+            fontOrGAttr = fonts.get(new Integer(pos));
+        } while (pos < runEnd);
+    }
+
+    /**
+     * Checks if text run segments are up to date and creates the new segments if not.
+     */
+    public void createAllSegments() {
+        if ( !haveAllSegments &&
+            (logical2segment == null ||
+             logical2segment.length != segmentsEnd - segmentsStart)
+        ) { // Check if we don't have all segments yet
+            resetSegments();
+            createSegments(segmentsStart, segmentsEnd);
+        }
+
+        haveAllSegments = true;
+    }
+
+    /**
+     * Calculates position where line should be broken without
+     * taking into account word boundaries.
+     * @param start - start index
+     * @param maxAdvance - maximum advance, width of the line
+     * @return position where to break
+     */
+    public int getLineBreakIndex(int start, float maxAdvance) {
+        int breakIndex;
+        TextRunSegment s = null;
+
+        for (
+                int segmentIndex = logical2segment[start];
+                segmentIndex < runSegments.size();
+                segmentIndex++
+           ) {
+            s = runSegments.get(segmentIndex);
+            breakIndex = s.getCharIndexFromAdvance(maxAdvance, start);
+
+            if (breakIndex < s.getEnd()) {
+                return breakIndex;
+            }
+            maxAdvance -= s.getAdvanceDelta(start, s.getEnd());
+            start = s.getEnd();
+        }
+
+        return s.getEnd();
+    }
+
+    /**
+     * Inserts character into the managed text.
+     * @param newParagraph - new character iterator
+     * @param insertPos - insertion position
+     */
+    public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) {
+        aci = newParagraph;
+
+        char insChar = aci.setIndex(insertPos);
+
+        Integer key = new Integer(insertPos);
+
+        insertPos -= aci.getBeginIndex();
+
+        char newText[] = new char[text.length + 1];
+        System.arraycopy(text, 0, newText, 0, insertPos);
+        newText[insertPos] = insChar;
+        System.arraycopy(text, insertPos, newText, insertPos+1, text.length - insertPos);
+        text = newText;
+
+        if (aci.getRunStart() == key.intValue() && aci.getRunLimit() == key.intValue() + 1) {
+            createStyleRuns(); // We have to create one new run, could be optimized
+        } else {
+            shiftStyleRuns(key, 1);
+        }
+
+        resetSegments();
+
+        segmentsEnd++;
+    }
+
+    /**
+     * Deletes character from the managed text.
+     * @param newParagraph - new character iterator
+     * @param deletePos - deletion position
+     */
+    public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) {
+        aci = newParagraph;
+
+        Integer key = new Integer(deletePos);
+
+        deletePos -= aci.getBeginIndex();
+
+        char newText[] = new char[text.length - 1];
+        System.arraycopy(text, 0, newText, 0, deletePos);
+        System.arraycopy(text, deletePos+1, newText, deletePos, newText.length - deletePos);
+        text = newText;
+
+        if (fonts.get(key) != null) {
+            fonts.remove(key);
+        }
+
+        shiftStyleRuns(key, -1);
+
+        resetSegments();
+
+        segmentsEnd--;
+    }
+
+    /**
+     * Shift all runs after specified position, needed to perfom insertion
+     * or deletion in the managed text
+     * @param pos - position where to start
+     * @param shift - shift, could be negative
+     */
+    private void shiftStyleRuns(Integer pos, final int shift) {
+        ArrayList<Integer> keys = new ArrayList<Integer>();
+
+        Integer key, oldkey;
+        for (Iterator<Integer> it = fonts.keySet().iterator(); it.hasNext(); ) {
+            oldkey = it.next();
+            if (oldkey.intValue() > pos.intValue()) {
+                keys.add(oldkey);
+            }
+        }
+
+        for (int i=0; i<keys.size(); i++) {
+            oldkey = keys.get(i);
+            key = new Integer(shift + oldkey.intValue());
+            fonts.put(key, fonts.remove(oldkey));
+            decorations.put(key, decorations.remove(oldkey));
+        }
+    }
+
+    /**
+     * Resets state of the class
+     */
+    private void resetSegments() {
+        runSegments = new ArrayList<TextRunSegment>();
+        logical2segment = null;
+        segment2visual = null;
+        visual2segment = null;
+        levels = null;
+        haveAllSegments = false;
+    }
+
+    private class SegmentsInfo {
+        ArrayList<TextRunSegment> runSegments;
+        int logical2segment[];
+        int segment2visual[];
+        int visual2segment[];
+        byte levels[];
+        int segmentsStart;
+        int segmentsEnd;
+    }
+
+    /**
+     * Saves the internal state of the class
+     * @param newSegStart - new start index in the text
+     * @param newSegEnd - new end index in the text
+     */
+    public void pushSegments(int newSegStart, int newSegEnd) {
+        storedSegments = new SegmentsInfo();
+        storedSegments.runSegments = this.runSegments;
+        storedSegments.logical2segment = this.logical2segment;
+        storedSegments.segment2visual = this.segment2visual;
+        storedSegments.visual2segment = this.visual2segment;
+        storedSegments.levels = this.levels;
+        storedSegments.segmentsStart = segmentsStart;
+        storedSegments.segmentsEnd = segmentsEnd;
+
+        resetSegments();
+
+        segmentsStart = newSegStart;
+        segmentsEnd = newSegEnd;
+    }
+
+    /**
+     * Restores the internal state of the class
+     */
+    public void popSegments() {
+        if (storedSegments == null) {
+            return;
+        }
+
+        this.runSegments = storedSegments.runSegments;
+        this.logical2segment = storedSegments.logical2segment;
+        this.segment2visual = storedSegments.segment2visual;
+        this.visual2segment = storedSegments.visual2segment;
+        this.levels = storedSegments.levels;
+        this.segmentsStart = storedSegments.segmentsStart;
+        this.segmentsEnd = storedSegments.segmentsEnd;
+        storedSegments = null;
+
+        if (runSegments.size() == 0 && logical2segment == null) {
+            haveAllSegments = false;
+        } else {
+            haveAllSegments = true;
+        }
+    }
+
+    @Override
+    public Object clone() {
+        try {
+            TextRunBreaker res = (TextRunBreaker) super.clone();
+            res.storedSegments = null;
+            ArrayList<TextRunSegment> newSegments = new ArrayList<TextRunSegment>(runSegments.size());
+            for (int i = 0; i < runSegments.size(); i++) {
+                TextRunSegment seg =  runSegments.get(i);
+                newSegments.add((TextRunSegment)seg.clone());
+            }
+            res.runSegments = newSegments;
+            return res;
+        } catch (CloneNotSupportedException e) {
+            // awt.3E=Clone not supported
+            throw new UnsupportedOperationException(Messages.getString("awt.3E")); //$NON-NLS-1$
+        }
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof TextRunBreaker)) {
+            return false;
+        }
+
+        TextRunBreaker br = (TextRunBreaker) obj;
+
+        if (br.getACI().equals(aci) && br.frc.equals(frc)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return HashCode.combine(aci.hashCode(), frc.hashCode());
+    }
+
+    /**
+     * Renders the managed text
+     * @param g2d - graphics where to render
+     * @param xOffset - offset in X direction to the upper left corner
+     * of the layout from the origin of the graphics
+     * @param yOffset - offset in Y direction to the upper left corner
+     * of the layout from the origin of the graphics
+     */
+    public void drawSegments(Graphics2D g2d, float xOffset, float yOffset) {
+        for (int i=0; i<runSegments.size(); i++) {
+            runSegments.get(i).draw(g2d, xOffset, yOffset);
+        }
+    }
+
+    /**
+     * Creates the black box bounds shape
+     * @param firstEndpoint - start position
+     * @param secondEndpoint - end position
+     * @return black box bounds shape
+     */
+    public Shape getBlackBoxBounds(int firstEndpoint, int secondEndpoint) {
+        GeneralPath bounds = new GeneralPath();
+
+        TextRunSegment segment;
+
+        for (int idx = firstEndpoint; idx < secondEndpoint; idx=segment.getEnd()) {
+            segment = runSegments.get(logical2segment[idx]);
+            bounds.append(segment.getCharsBlackBoxBounds(idx, secondEndpoint), false);
+        }
+
+        return bounds;
+    }
+
+    /**
+     * Creates visual bounds shape
+     * @return visual bounds rectangle
+     */
+    public Rectangle2D getVisualBounds() {
+        Rectangle2D bounds = null;
+
+        for (int i=0; i<runSegments.size(); i++) {
+            TextRunSegment s = runSegments.get(i);
+            if (bounds != null) {
+                Rectangle2D.union(bounds, s.getVisualBounds(), bounds);
+            } else {
+                bounds = s.getVisualBounds();
+            }
+        }
+
+        return bounds;
+    }
+
+    /**
+     * Creates logical bounds shape
+     * @return logical bounds rectangle
+     */
+    public Rectangle2D getLogicalBounds() {
+        Rectangle2D bounds = null;
+
+        for (int i=0; i<runSegments.size(); i++) {
+            TextRunSegment s = runSegments.get(i);
+            if (bounds != null) {
+                Rectangle2D.union(bounds, s.getLogicalBounds(), bounds);
+            } else {
+                bounds = s.getLogicalBounds();
+            }
+        }
+
+        return bounds;
+    }
+
+    public int getCharCount() {
+        return segmentsEnd - segmentsStart;
+    }
+
+    public byte getLevel(int idx) {
+        if (levels == null) {
+            return 0;
+        }
+        return levels[idx];
+    }
+
+    public int getBaseLevel() {
+        return 0;
+    }
+
+    public boolean isLTR() {
+        return true;
+    }
+
+    public char getChar(int index) {
+        return text[index];
+    }
+
+    public AttributedCharacterIterator getACI() {
+        return aci;
+    }
+
+    /**
+     * Creates outline shape for the managed text
+     * @return outline
+     */
+    public GeneralPath getOutline() {
+        GeneralPath outline = new GeneralPath();
+
+        TextRunSegment segment;
+
+        for (int i = 0; i < runSegments.size(); i++) {
+            segment = runSegments.get(i);
+            outline.append(segment.getOutline(), false);
+        }
+
+        return outline;
+    }
+
+    /**
+     * Calculates text hit info from the screen coordinates.
+     * Current implementation totally ignores Y coordinate.
+     * If X coordinate is outside of the layout boundaries, this
+     * method returns leftmost or rightmost hit.
+     * @param x - x coordinate of the hit
+     * @param y - y coordinate of the hit
+     * @return hit info
+     */
+    public TextHitInfo hitTest(float x, float y) {
+        TextRunSegment segment;
+
+        double endOfPrevSeg = -1;
+        for (int i = 0; i < runSegments.size(); i++) {
+            segment = runSegments.get(i);
+            Rectangle2D bounds = segment.getVisualBounds();
+            if ((bounds.getMinX() <= x && bounds.getMaxX() >= x) || // We are in the segment
+               (endOfPrevSeg < x && bounds.getMinX() > x)) { // We are somewhere between the segments
+                return segment.hitTest(x,y);
+            }
+            endOfPrevSeg = bounds.getMaxX();
+        }
+
+        return isLTR() ? TextHitInfo.trailing(text.length) : TextHitInfo.leading(0);
+    }
+
+    public float getJustification() {
+        return justification;
+    }
+
+    /**
+     * Calculates position of the last non whitespace character
+     * in the managed text.
+     * @return position of the last non whitespace character
+     */
+    public int getLastNonWhitespace() {
+        int lastNonWhitespace = text.length;
+
+        while (lastNonWhitespace >= 0) {
+            lastNonWhitespace--;
+            if (!Character.isWhitespace(text[lastNonWhitespace])) {
+                break;
+            }
+        }
+
+        return lastNonWhitespace;
+    }
+
+    /**
+     * Performs justification of the managed text by changing segment positions
+     * and positions of the glyphs inside of the segments.
+     * @param gap - amount of space which should be compensated by justification
+     */
+    public void justify(float gap) {
+        // Ignore trailing logical whitespace
+        int firstIdx = segmentsStart;
+        int lastIdx = getLastNonWhitespace() + segmentsStart;
+        JustificationInfo jInfos[] = new JustificationInfo[5];
+        float gapLeft = gap;
+
+        int highestPriority = -1;
+        // GlyphJustificationInfo.PRIORITY_KASHIDA is 0
+        // GlyphJustificationInfo.PRIORITY_NONE is 3
+        for (int priority = 0; priority <= GlyphJustificationInfo.PRIORITY_NONE + 1; priority++) {
+            JustificationInfo jInfo = new JustificationInfo();
+            jInfo.lastIdx = lastIdx;
+            jInfo.firstIdx = firstIdx;
+            jInfo.grow = gap > 0;
+            jInfo.gapToFill = gapLeft;
+
+            if (priority <= GlyphJustificationInfo.PRIORITY_NONE) {
+                jInfo.priority = priority;
+            } else {
+                jInfo.priority = highestPriority; // Last pass
+            }
+
+            for (int i = 0; i < runSegments.size(); i++) {
+                TextRunSegment segment = runSegments.get(i);
+                if (segment.getStart() <= lastIdx) {
+                    segment.updateJustificationInfo(jInfo);
+                }
+            }
+
+            if (jInfo.priority == highestPriority) {
+                jInfo.absorb = true;
+                jInfo.absorbedWeight = jInfo.weight;
+            }
+
+            if (jInfo.weight != 0) {
+                if (highestPriority < 0) {
+                    highestPriority = priority;
+                }
+                jInfos[priority] = jInfo;
+            } else {
+                continue;
+            }
+
+            gapLeft -= jInfo.growLimit;
+
+            if (((gapLeft > 0) ^ jInfo.grow) || gapLeft == 0) {
+                gapLeft = 0;
+                jInfo.gapPerUnit = jInfo.gapToFill/jInfo.weight;
+                break;
+            }
+            jInfo.useLimits = true;
+
+            if (jInfo.absorbedWeight > 0) {
+                jInfo.absorb = true;
+                jInfo.absorbedGapPerUnit =
+                        (jInfo.gapToFill-jInfo.growLimit)/jInfo.absorbedWeight;
+                break;
+            }
+        }
+
+        float currJustificationOffset = 0;
+        for (int i = 0; i < runSegments.size(); i++) {
+            TextRunSegment segment =
+                    runSegments.get(getSegmentFromVisualOrder(i));
+            segment.x += currJustificationOffset;
+            currJustificationOffset += segment.doJustification(jInfos);
+        }
+
+        justification = -1; // Make further justification impossible
+    }
+
+    /**
+     * This class represents the information collected before the actual
+     * justification is started and needed to perform the justification.
+     * This information is closely related to the information stored in the
+     * GlyphJustificationInfo for the text represented by glyph vectors.
+     */
+    class JustificationInfo {
+        boolean grow;
+        boolean absorb = false;
+        boolean useLimits = false;
+        int priority = 0;
+        float weight = 0;
+        float absorbedWeight = 0;
+        float growLimit = 0;
+
+        int lastIdx;
+        int firstIdx;
+
+        float gapToFill;
+
+        float gapPerUnit = 0; // Precalculated value, gapToFill / weight
+        float absorbedGapPerUnit = 0; // Precalculated value, gapToFill / weight
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/TextRunSegment.java b/awt/org/apache/harmony/awt/gl/font/TextRunSegment.java
new file mode 100644
index 0000000..1cd2c05
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextRunSegment.java
@@ -0,0 +1,165 @@
+/*
+ *  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.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.font.TextHitInfo;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * Abstract class which represents the segment of the text with constant attributes
+ * running in one direction (i.e. constant level).
+ */
+public abstract class TextRunSegment implements Cloneable {
+    float x; // Calculated x location of this segment on the screen
+    float y; // Calculated y location of this segment on the screen
+
+    BasicMetrics metrics; // Metrics of this text run segment
+    TextDecorator.Decoration decoration; // Underline, srikethrough, etc.
+    Rectangle2D logicalBounds = null; // Logical bounding box for the segment
+    Rectangle2D visualBounds = null; // Visual bounding box for the segment
+
+    /**
+     * Returns start index of the segment
+     * @return start index
+     */
+    abstract int getStart();
+
+    /**
+     * Returns end index of the segment
+     * @return end index
+     */
+    abstract int getEnd();
+
+    /**
+     * Returns the number of characters in the segment
+     * @return number of characters
+     */
+    abstract int getLength();
+
+    /**
+     * Renders this text run segment
+     * @param g2d - graphics to render to
+     * @param xOffset - X offset from the graphics origin to the
+     * origin of the text layout
+     * @param yOffset - Y offset from the graphics origin to the
+     * origin of the text layout
+     */
+    abstract void draw(Graphics2D g2d, float xOffset, float yOffset);
+
+    /**
+     * Creates black box bounds shape for the specified range
+     * @param start - range sart
+     * @param limit - range end
+     * @return black box bounds shape
+     */
+    abstract Shape getCharsBlackBoxBounds(int start, int limit);
+
+    /**
+     * Returns the outline shape
+     * @return outline
+     */
+    abstract Shape getOutline();
+
+    /**
+     * Returns visual bounds of this segment
+     * @return visual bounds
+     */
+    abstract Rectangle2D getVisualBounds();
+
+    /**
+     * Returns logical bounds of this segment
+     * @return logical bounds
+     */
+    abstract Rectangle2D getLogicalBounds();
+
+    /**
+     * Calculates advance of the segment
+     * @return advance
+     */
+    abstract float getAdvance();
+
+    /**
+     * Calculates advance delta between two characters
+     * @param start - 1st position
+     * @param end - 2nd position
+     * @return advance increment between specified positions
+     */
+    abstract float getAdvanceDelta(int start, int end);
+
+    /**
+     * Calculates index of the character which advance is equal to
+     * the given. If the given advance is greater then the segment
+     * advance it returns the position after the last character.
+     * @param advance - given advance
+     * @param start - character, from which to start measuring advance
+     * @return character index
+     */
+    abstract int getCharIndexFromAdvance(float advance, int start);
+
+    /**
+     * Checks if the character doesn't contribute to the text advance
+     * @param index - character index
+     * @return true if the character has zero advance
+     */
+    abstract boolean charHasZeroAdvance(int index);
+
+    /**
+     * Calculates position of the character on the screen
+     * @param index - character index
+     * @return X coordinate of the character position
+     */
+    abstract float getCharPosition(int index);
+
+    /**
+     * Returns the advance of the individual character
+     * @param index - character index
+     * @return character advance
+     */
+    abstract float getCharAdvance(int index);
+
+    /**
+     * Creates text hit info from the hit position
+     * @param x - X coordinate relative to the origin of the layout
+     * @param y - Y coordinate relative to the origin of the layout
+     * @return hit info
+     */
+    abstract TextHitInfo hitTest(float x, float y);
+
+    /**
+     * Collects justification information into JustificationInfo object
+     * @param jInfo - JustificationInfo object
+     */
+    abstract void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo);
+
+    /**
+     * Performs justification of the segment.
+     * Updates positions of individual characters.
+     * @param jInfos - justification information, gathered by the previous passes
+     * @return amount of growth or shrink of the segment
+     */    
+    abstract float doJustification(TextRunBreaker.JustificationInfo jInfos[]);
+
+    @Override
+    public abstract Object clone();
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java b/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java
new file mode 100644
index 0000000..0ec2d05
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java
@@ -0,0 +1,979 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.*;
+import java.awt.font.*;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+// XXX - TODO - bidi not implemented yet
+//import java.text.Bidi;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * Date: Apr 25, 2005
+ * Time: 4:33:18 PM
+ *
+ * This class contains the implementation of the behavior of the
+ * text run segment with constant text attributes and direction.
+ */
+public class TextRunSegmentImpl {
+
+    /**
+     * This class contains basic information required for creation
+     * of the glyph-based text run segment.
+     */
+    public static class TextSegmentInfo {
+        // XXX - TODO - bidi not implemented yet
+        //Bidi bidi;
+
+        Font font;
+        FontRenderContext frc;
+
+        char text[];
+
+        int start;
+        int end;
+        int length;
+
+        int flags = 0;
+
+        byte level = 0;
+
+        TextSegmentInfo(
+                byte level,
+                Font font, FontRenderContext frc,
+                char text[], int start, int end
+        ) {
+            this.font = font;
+            this.frc = frc;
+            this.text = text;
+            this.start = start;
+            this.end = end;
+            this.level = level;
+            length = end - start;
+        }
+    }
+
+    /**
+     * This class represents a simple text segment backed by the glyph vector
+     */
+    public static class TextRunSegmentCommon extends TextRunSegment {
+        TextSegmentInfo info;
+        private GlyphVector gv;
+        private float advanceIncrements[];
+        private int char2glyph[];
+        private GlyphJustificationInfo gjis[]; // Glyph justification info
+
+        TextRunSegmentCommon(TextSegmentInfo i, TextDecorator.Decoration d) {
+            // XXX - todo - check support bidi
+            i.flags &= ~0x09; // Clear bidi flags
+
+            if ((i.level & 0x1) != 0) {
+                i.flags |= Font.LAYOUT_RIGHT_TO_LEFT;
+            }
+
+            info = i;
+            this.decoration = d;
+
+            LineMetrics lm = i.font.getLineMetrics(i.text, i.start, i.end, i.frc);
+            this.metrics = new BasicMetrics(lm, i.font);
+
+            if (lm.getNumChars() != i.length) { // XXX todo - This should be handled
+                // awt.41=Font returned unsupported type of line metrics. This case is known, but not supported yet.
+                throw new UnsupportedOperationException(
+                        Messages.getString("awt.41")); //$NON-NLS-1$
+            }
+        }
+
+        @Override
+        public Object clone() {
+            return new TextRunSegmentCommon(info, decoration);
+        }
+
+        /**
+         * Creates glyph vector from the managed text if needed
+         * @return glyph vector
+         */
+        private GlyphVector getGlyphVector() {
+            if (gv==null) {
+                gv = info.font.layoutGlyphVector(
+                        info.frc,
+                        info.text,
+                        info.start,
+                        info.end - info.start, // NOTE: This parameter violates
+                                               // spec, it is count,
+                                               // not limit as spec states
+                        info.flags
+                );
+            }
+
+            return gv;
+        }
+
+        /**
+         * Renders this text run segment
+         * @param g2d - graphics to render to
+         * @param xOffset - X offset from the graphics origin to the
+         * origin of the text layout
+         * @param yOffset - Y offset from the graphics origin to the
+         * origin of the text layout
+         */
+        @Override
+        void draw(Graphics2D g2d, float xOffset, float yOffset) {
+            if (decoration == null) {
+                g2d.drawGlyphVector(getGlyphVector(), xOffset + x, yOffset + y);
+            } else {
+                TextDecorator.prepareGraphics(this, g2d, xOffset, yOffset);
+                g2d.drawGlyphVector(getGlyphVector(), xOffset + x, yOffset + y);
+                TextDecorator.drawTextDecorations(this, g2d, xOffset, yOffset);
+                TextDecorator.restoreGraphics(decoration, g2d);
+            }
+        }
+
+        /**
+         * Returns visual bounds of this segment
+         * @return visual bounds
+         */
+        @Override
+        Rectangle2D getVisualBounds() {
+            if (visualBounds == null) {
+                visualBounds =
+                        TextDecorator.extendVisualBounds(
+                                this,
+                                getGlyphVector().getVisualBounds(),
+                                decoration
+                        );
+
+                visualBounds.setRect(
+                        x + visualBounds.getX(),
+                        y + visualBounds.getY(),
+                        visualBounds.getWidth(),
+                        visualBounds.getHeight()
+                );
+            }
+
+            return (Rectangle2D) visualBounds.clone();
+        }
+
+        /**
+         * Returns logical bounds of this segment
+         * @return logical bounds
+         */
+        @Override
+        Rectangle2D getLogicalBounds() {
+            if (logicalBounds == null) {
+                logicalBounds = getGlyphVector().getLogicalBounds();
+
+                logicalBounds.setRect(
+                        x + logicalBounds.getX(),
+                        y + logicalBounds.getY(),
+                        logicalBounds.getWidth(),
+                        logicalBounds.getHeight()
+                );
+            }
+
+            return (Rectangle2D) logicalBounds.clone();
+        }
+
+        @Override
+        float getAdvance() {
+            return (float) getLogicalBounds().getWidth();
+        }
+
+        /**
+         * Attemts to map each character to the corresponding advance increment
+         */
+        void initAdvanceMapping() {
+            GlyphVector gv = getGlyphVector();
+            int charIndicies[] = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null);
+            advanceIncrements = new float[info.length];
+
+            for (int i=0; i<charIndicies.length; i++) {
+                advanceIncrements[charIndicies[i]] = gv.getGlyphMetrics(i).getAdvance();
+            }
+        }
+
+        /**
+         * Calculates advance delta between two characters
+         * @param start - 1st position
+         * @param end - 2nd position
+         * @return advance increment between specified positions
+         */
+        @Override
+        float getAdvanceDelta(int start, int end) {
+            // Get coordinates in the segment context
+            start -= info.start;
+            end -= info.start;
+
+            if (advanceIncrements == null) {
+                initAdvanceMapping();
+            }
+
+            if (start < 0) {
+                start = 0;
+            }
+            if (end > info.length) {
+                end = info.length;
+            }
+
+            float sum = 0;
+            for (int i=start; i<end; i++) {
+                sum += advanceIncrements[i];
+            }
+
+            return sum;
+        }
+
+        /**
+         * Calculates index of the character which advance is equal to
+         * the given. If the given advance is greater then the segment
+         * advance it returns the position after the last character.
+         * @param advance - given advance
+         * @param start - character, from which to start measuring advance
+         * @return character index
+         */
+        @Override
+        int getCharIndexFromAdvance(float advance, int start) {
+            // XXX - todo - probably, possible to optimize
+            // Add check if the given advance is greater then
+            // the segment advance in the beginning. In this case
+            // we don't need to run through all increments
+            if (advanceIncrements == null) {
+                initAdvanceMapping();
+            }
+
+            start -= info.start;
+
+            if (start < 0) {
+                start = 0;
+            }
+
+            int i = start;
+            for (; i<info.length; i++) {
+                advance -= advanceIncrements[i];
+                if (advance < 0) {
+                    break;
+                }
+            }
+
+            return i + info.start;
+        }
+
+        @Override
+        int getStart() {
+            return info.start;
+        }
+
+        @Override
+        int getEnd() {
+            return info.end;
+        }
+
+        @Override
+        int getLength() {
+            return info.length;
+        }
+
+        /**
+         * Attemts to create mapping of the characters to glyphs in the glyph vector.
+         * @return array where for each character index stored corresponding glyph index
+         */
+        private int[] getChar2Glyph() {
+            if (char2glyph == null) {
+                GlyphVector gv = getGlyphVector();
+                char2glyph = new int[info.length];
+                Arrays.fill(char2glyph, -1);
+
+                // Fill glyph indicies for first characters corresponding to each glyph
+                int charIndicies[] = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null);
+                for (int i=0; i<charIndicies.length; i++) {
+                    char2glyph[charIndicies[i]] = i;
+                }
+
+                // If several characters corresponds to one glyph, create mapping for them
+                // Suppose that these characters are going all together
+                int currIndex = 0;
+                for (int i=0; i<char2glyph.length; i++) {
+                    if (char2glyph[i] < 0) {
+                        char2glyph[i] = currIndex;
+                    } else {
+                        currIndex = char2glyph[i];
+                    }
+                }
+            }
+
+            return char2glyph;
+        }
+
+        /**
+         * Creates black box bounds shape for the specified range
+         * @param start - range sart
+         * @param limit - range end
+         * @return black box bounds shape
+         */
+        @Override
+        Shape getCharsBlackBoxBounds(int start, int limit) {
+            start -= info.start;
+            limit -= info.start;
+
+            if (limit > info.length) {
+                limit = info.length;
+            }
+
+            GeneralPath result = new GeneralPath();
+
+            int glyphIndex = 0;
+
+            for (int i=start; i<limit; i++) {
+                glyphIndex = getChar2Glyph()[i];
+                result.append(getGlyphVector().getGlyphVisualBounds(glyphIndex), false);
+            }
+
+            // Shift to the segment's coordinates
+            result.transform(AffineTransform.getTranslateInstance(x, y));
+
+            return result;
+        }
+
+        /**
+         * Calculates position of the character on the screen
+         * @param index - character index
+         * @return X coordinate of the character position
+         */
+        @Override
+        float getCharPosition(int index) {
+            index -= info.start;
+
+            if (index > info.length) {
+                index = info.length;
+            }
+
+            float result = 0;
+
+            int glyphIndex = getChar2Glyph()[index];
+            result = (float) getGlyphVector().getGlyphPosition(glyphIndex).getX();
+
+            // Shift to the segment's coordinates
+            result += x;
+
+            return result;
+        }
+
+        /**
+         * Returns the advance of the individual character
+         * @param index - character index
+         * @return character advance
+         */
+        @Override
+        float getCharAdvance(int index) {
+            if (advanceIncrements == null) {
+                initAdvanceMapping();
+            }
+
+            return advanceIncrements[index - this.getStart()];
+        }
+
+        /**
+         * Returns the outline shape
+         * @return outline
+         */
+        @Override
+        Shape getOutline() {
+            AffineTransform t = AffineTransform.getTranslateInstance(x, y);
+            return t.createTransformedShape(
+                    TextDecorator.extendOutline(
+                            this,
+                            getGlyphVector().getOutline(),
+                            decoration
+                    )
+            );
+        }
+
+        /**
+         * Checks if the character doesn't contribute to the text advance
+         * @param index - character index
+         * @return true if the character has zero advance
+         */
+        @Override
+        boolean charHasZeroAdvance(int index) {
+            if (advanceIncrements == null) {
+                initAdvanceMapping();
+            }
+
+            return advanceIncrements[index - this.getStart()] == 0;
+        }
+
+        /**
+         * Creates text hit info from the hit position
+         * @param hitX - X coordinate relative to the origin of the layout
+         * @param hitY - Y coordinate relative to the origin of the layout
+         * @return hit info
+         */
+        @Override
+        TextHitInfo hitTest(float hitX, float hitY) {
+            hitX -= x;
+
+            float glyphPositions[] =
+                    getGlyphVector().getGlyphPositions(0, info.length+1, null);
+
+            int glyphIdx;
+            boolean leading = false;
+            for (glyphIdx = 1; glyphIdx <= info.length; glyphIdx++) {
+                if (glyphPositions[(glyphIdx)*2] >= hitX) {
+                    float advance =
+                            glyphPositions[(glyphIdx)*2] - glyphPositions[(glyphIdx-1)*2];
+                    leading = glyphPositions[(glyphIdx-1)*2] + advance/2 > hitX ? true : false;
+                    glyphIdx--;
+                    break;
+                }
+            }
+
+            if (glyphIdx == info.length) {
+                glyphIdx--;
+            }
+
+            int charIdx = getGlyphVector().getGlyphCharIndex(glyphIdx);
+
+            return (leading) ^ ((info.level & 0x1) == 0x1)?
+                    TextHitInfo.leading(charIdx + info.start) :
+                    TextHitInfo.trailing(charIdx + info.start);
+        }
+
+        /**
+         * Collects GlyphJustificationInfo objects from the glyph vector
+         * @return array of all GlyphJustificationInfo objects
+         */
+        private GlyphJustificationInfo[] getGlyphJustificationInfos() {
+            if (gjis == null) {
+                GlyphVector gv = getGlyphVector();
+                int nGlyphs = gv.getNumGlyphs();
+                int charIndicies[] = gv.getGlyphCharIndices(0, nGlyphs, null);
+                gjis = new GlyphJustificationInfo[nGlyphs];
+
+                // Patch: temporary patch, getGlyphJustificationInfo is not implemented
+                float fontSize = info.font.getSize2D();
+                GlyphJustificationInfo defaultInfo =
+                        new GlyphJustificationInfo(
+                                0, // weight
+                                false, GlyphJustificationInfo.PRIORITY_NONE, 0, 0, // grow
+                                false, GlyphJustificationInfo.PRIORITY_NONE, 0, 0); // shrink
+                GlyphJustificationInfo spaceInfo = new GlyphJustificationInfo(
+                        fontSize, // weight
+                        true, GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, fontSize, // grow
+                        true, GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, fontSize); // shrink
+
+                ////////
+                // Temporary patch, getGlyphJustificationInfo is not implemented
+                for (int i = 0; i < nGlyphs; i++) {
+                    //gjis[i] = getGlyphVector().getGlyphJustificationInfo(i);
+
+                    char c = info.text[charIndicies[i] + info.start];
+                    if (Character.isWhitespace(c)) {
+                        gjis[i] = spaceInfo;
+                    } else {
+                        gjis[i] = defaultInfo;
+                    }
+                    // End patch
+                }
+            }
+
+            return gjis;
+        }
+
+        /**
+         * Collects justification information into JustificationInfo object
+         * @param jInfo - JustificationInfo object
+         */
+        @Override
+        void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo) {
+            int lastChar = Math.min(jInfo.lastIdx, info.end) - info.start;
+            boolean haveFirst = info.start <= jInfo.firstIdx;
+            boolean haveLast = info.end >= (jInfo.lastIdx + 1);
+
+            int prevGlyphIdx = -1;
+            int currGlyphIdx;
+
+            if (jInfo.grow) { // Check how much we can grow/shrink on current priority level
+                for (int i=0; i<lastChar; i++) {
+                    currGlyphIdx = getChar2Glyph()[i];
+
+                    if (currGlyphIdx == prevGlyphIdx) {
+                        // Several chars could be represented by one glyph,
+                        // suppose they are contiguous
+                        continue;
+                    }
+                    prevGlyphIdx = currGlyphIdx;
+
+                    GlyphJustificationInfo gji = getGlyphJustificationInfos()[currGlyphIdx];
+                    if (gji.growPriority == jInfo.priority) {
+                        jInfo.weight += gji.weight * 2;
+                        jInfo.growLimit += gji.growLeftLimit;
+                        jInfo.growLimit += gji.growRightLimit;
+                        if (gji.growAbsorb) {
+                            jInfo.absorbedWeight += gji.weight * 2;
+                        }
+                    }
+                }
+            } else {
+                for (int i=0; i<lastChar; i++) {
+                    currGlyphIdx = getChar2Glyph()[i];
+                    if (currGlyphIdx == prevGlyphIdx) {
+                        continue;
+                    }
+                    prevGlyphIdx = currGlyphIdx;
+
+                    GlyphJustificationInfo gji = getGlyphJustificationInfos()[currGlyphIdx];
+                    if (gji.shrinkPriority == jInfo.priority) {
+                        jInfo.weight += gji.weight * 2;
+                        jInfo.growLimit -= gji.shrinkLeftLimit;
+                        jInfo.growLimit -= gji.shrinkRightLimit;
+                        if (gji.shrinkAbsorb) {
+                            jInfo.absorbedWeight += gji.weight * 2;
+                        }
+                    }
+                }
+            }
+
+            if (haveFirst) {  // Don't add padding before first char
+                GlyphJustificationInfo gji = getGlyphJustificationInfos()[getChar2Glyph()[0]];
+                jInfo.weight -= gji.weight;
+                if (jInfo.grow) {
+                    jInfo.growLimit -= gji.growLeftLimit;
+                    if (gji.growAbsorb) {
+                        jInfo.absorbedWeight -= gji.weight;
+                    }
+                } else {
+                    jInfo.growLimit += gji.shrinkLeftLimit;
+                    if (gji.shrinkAbsorb) {
+                        jInfo.absorbedWeight -= gji.weight;
+                    }
+                }
+            }
+
+            if (haveLast) {   // Don't add padding after last char
+                GlyphJustificationInfo gji =
+                        getGlyphJustificationInfos()[getChar2Glyph()[lastChar]];
+                jInfo.weight -= gji.weight;
+                if (jInfo.grow) {
+                    jInfo.growLimit -= gji.growRightLimit;
+                    if (gji.growAbsorb) {
+                        jInfo.absorbedWeight -= gji.weight;
+                    }
+                } else {
+                    jInfo.growLimit += gji.shrinkRightLimit;
+                    if (gji.shrinkAbsorb) {
+                        jInfo.absorbedWeight -= gji.weight;
+                    }
+                }
+            }
+        }
+
+        /**
+         * Performs justification of the segment.
+         * Updates positions of individual characters.
+         * @param jInfos - justification information, gathered by the previous passes
+         * @return amount of growth or shrink of the segment
+         */
+        @Override
+        float doJustification(TextRunBreaker.JustificationInfo jInfos[]) {
+            int lastPriority =
+                    jInfos[jInfos.length-1] == null ?
+                    -1 : jInfos[jInfos.length-1].priority;
+
+            // Get the highest priority
+            int highestPriority = 0;
+            for (; highestPriority<jInfos.length; highestPriority++) {
+                if (jInfos[highestPriority] != null) {
+                    break;
+                }
+            }
+
+            if (highestPriority == jInfos.length) {
+                return 0;
+            }
+
+            TextRunBreaker.JustificationInfo firstInfo = jInfos[highestPriority];
+            TextRunBreaker.JustificationInfo lastInfo =
+                    lastPriority > 0 ? jInfos[lastPriority] : null;
+
+            boolean haveFirst = info.start <= firstInfo.firstIdx;
+            boolean haveLast = info.end >= (firstInfo.lastIdx + 1);
+
+            // Here we suppose that GLYPHS are ordered LEFT TO RIGHT
+            int firstGlyph = haveFirst ?
+                    getChar2Glyph()[firstInfo.firstIdx - info.start] :
+                    getChar2Glyph()[0];
+
+            int lastGlyph = haveLast ?
+                    getChar2Glyph()[firstInfo.lastIdx - info.start] :
+                    getChar2Glyph()[info.length - 1];
+            if (haveLast) {
+                lastGlyph--;
+            }
+
+            TextRunBreaker.JustificationInfo currInfo;
+            float glyphOffset = 0;
+            float positionIncrement = 0;
+            float sideIncrement = 0;
+
+            if (haveFirst) {  // Don't add padding before first char
+                GlyphJustificationInfo gji = getGlyphJustificationInfos()[firstGlyph];
+                currInfo = jInfos[gji.growPriority];
+                if (currInfo != null) {
+                    if (currInfo.useLimits) {
+                        if (currInfo.absorb) {
+                            glyphOffset += gji.weight * currInfo.absorbedGapPerUnit;
+                        } else if (
+                                lastInfo != null &&
+                                lastInfo.priority == currInfo.priority
+                        ) {
+                            glyphOffset += gji.weight * lastInfo.absorbedGapPerUnit;
+                        }
+                        glyphOffset +=
+                                firstInfo.grow ?
+                                gji.growRightLimit :
+                                -gji.shrinkRightLimit;
+                    } else {
+                        glyphOffset += gji.weight * currInfo.gapPerUnit;
+                    }
+                }
+
+                firstGlyph++;
+            }
+
+            if (firstInfo.grow) {
+                for (int i=firstGlyph; i<=lastGlyph; i++) {
+                    GlyphJustificationInfo gji = getGlyphJustificationInfos()[i];
+                    currInfo = jInfos[gji.growPriority];
+                    if (currInfo == null) {
+                        // We still have to increment glyph position
+                        Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+                        glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
+                        getGlyphVector().setGlyphPosition(i, glyphPos);
+
+                        continue;
+                    }
+
+                    if (currInfo.useLimits) {
+                        glyphOffset += gji.growLeftLimit;
+                        if (currInfo.absorb) {
+                            sideIncrement = gji.weight * currInfo.absorbedGapPerUnit;
+                            glyphOffset += sideIncrement;
+                            positionIncrement = glyphOffset;
+                            glyphOffset += sideIncrement;
+                        } else if (lastInfo != null && lastInfo.priority == currInfo.priority) {
+                            sideIncrement = gji.weight * lastInfo.absorbedGapPerUnit;
+                            glyphOffset += sideIncrement;
+                            positionIncrement = glyphOffset;
+                            glyphOffset += sideIncrement;
+                        } else {
+                            positionIncrement = glyphOffset;
+                        }
+                        glyphOffset += gji.growRightLimit;
+                    } else {
+                        sideIncrement = gji.weight * currInfo.gapPerUnit;
+                        glyphOffset += sideIncrement;
+                        positionIncrement = glyphOffset;
+                        glyphOffset += sideIncrement;
+                    }
+
+                    Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+                    glyphPos.setLocation(glyphPos.getX() + positionIncrement, glyphPos.getY());
+                    getGlyphVector().setGlyphPosition(i, glyphPos);
+                }
+            } else {
+                for (int i=firstGlyph; i<=lastGlyph; i++) {
+                    GlyphJustificationInfo gji = getGlyphJustificationInfos()[i];
+                    currInfo = jInfos[gji.shrinkPriority];
+                    if (currInfo == null) {
+                        // We still have to increment glyph position
+                        Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+                        glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
+                        getGlyphVector().setGlyphPosition(i, glyphPos);
+
+                        continue;
+                    }
+
+                    if (currInfo.useLimits) {
+                        glyphOffset -= gji.shrinkLeftLimit;
+                        if (currInfo.absorb) {
+                            sideIncrement = gji.weight * currInfo.absorbedGapPerUnit;
+                            glyphOffset += sideIncrement;
+                            positionIncrement = glyphOffset;
+                            glyphOffset += sideIncrement;
+                        } else if (lastInfo != null && lastInfo.priority == currInfo.priority) {
+                            sideIncrement = gji.weight * lastInfo.absorbedGapPerUnit;
+                            glyphOffset += sideIncrement;
+                            positionIncrement = glyphOffset;
+                            glyphOffset += sideIncrement;
+                        } else {
+                            positionIncrement = glyphOffset;
+                        }
+                        glyphOffset -= gji.shrinkRightLimit;
+                    } else {
+                        sideIncrement =  gji.weight * currInfo.gapPerUnit;
+                        glyphOffset += sideIncrement;
+                        positionIncrement = glyphOffset;
+                        glyphOffset += sideIncrement;
+                    }
+
+                    Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+                    glyphPos.setLocation(glyphPos.getX() + positionIncrement, glyphPos.getY());
+                    getGlyphVector().setGlyphPosition(i, glyphPos);
+                }
+            }
+
+
+            if (haveLast) {   // Don't add padding after last char
+                lastGlyph++;
+
+                GlyphJustificationInfo gji = getGlyphJustificationInfos()[lastGlyph];
+                currInfo = jInfos[gji.growPriority];
+
+                if (currInfo != null) {
+                    if (currInfo.useLimits) {
+                        glyphOffset += firstInfo.grow ? gji.growLeftLimit : -gji.shrinkLeftLimit;
+                        if (currInfo.absorb) {
+                            glyphOffset += gji.weight * currInfo.absorbedGapPerUnit;
+                        } else if (lastInfo != null && lastInfo.priority == currInfo.priority) {
+                            glyphOffset += gji.weight * lastInfo.absorbedGapPerUnit;
+                        }
+                    } else {
+                        glyphOffset += gji.weight * currInfo.gapPerUnit;
+                    }
+                }
+
+                // Ajust positions of all glyphs after last glyph
+                for (int i=lastGlyph; i<getGlyphVector().getNumGlyphs()+1; i++) {
+                    Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+                    glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
+                    getGlyphVector().setGlyphPosition(i, glyphPos);
+                }
+            } else { // Update position after last glyph in glyph vector -
+                // to get correct advance for it
+                Point2D glyphPos = getGlyphVector().getGlyphPosition(lastGlyph+1);
+                glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
+                getGlyphVector().setGlyphPosition(lastGlyph+1, glyphPos);
+            }
+
+            gjis = null; // We don't need justification infos any more
+            // Also we have to reset cached bounds and metrics
+            this.visualBounds = null;
+            this.logicalBounds = null;
+
+            return glyphOffset; // How much our segment grown or shrunk
+        }
+    }
+
+    public static class TextRunSegmentGraphic extends TextRunSegment {
+        GraphicAttribute ga;
+        int start;
+        int length;
+        float fullAdvance;
+
+        TextRunSegmentGraphic(GraphicAttribute attr, int len, int start) {
+            this.start = start;
+            length = len;
+            ga = attr;
+            metrics = new BasicMetrics(ga);
+            fullAdvance = ga.getAdvance() * length;
+        }
+
+        @Override
+        public Object clone() {
+            return new TextRunSegmentGraphic(ga, length, start);
+        }
+
+        // Renders this text run segment
+        @Override
+        void draw(Graphics2D g2d, float xOffset, float yOffset) {
+            if (decoration != null) {
+                TextDecorator.prepareGraphics(this, g2d, xOffset, yOffset);
+            }
+
+            float xPos = x + xOffset;
+            float yPos = y + yOffset;
+
+            for (int i=0; i < length; i++) {
+                ga.draw(g2d, xPos, yPos);
+                xPos += ga.getAdvance();
+            }
+
+            if (decoration != null) {
+                TextDecorator.drawTextDecorations(this, g2d, xOffset, yOffset);
+                TextDecorator.restoreGraphics(decoration, g2d);
+            }
+        }
+
+        // Returns visual bounds of this segment
+        @Override
+        Rectangle2D getVisualBounds() {
+            if (visualBounds == null) {
+                Rectangle2D bounds = ga.getBounds();
+
+                // First and last chars can be out of logical bounds, so we calculate
+                // (bounds.getWidth() - ga.getAdvance()) which is exactly the difference
+                bounds.setRect(
+                        bounds.getMinX() + x,
+                        bounds.getMinY() + y,
+                        bounds.getWidth() - ga.getAdvance() + getAdvance(),
+                        bounds.getHeight()
+                );
+                visualBounds = TextDecorator.extendVisualBounds(this, bounds, decoration);
+            }
+
+            return (Rectangle2D) visualBounds.clone();
+        }
+
+        @Override
+        Rectangle2D getLogicalBounds() {
+            if (logicalBounds == null) {
+                logicalBounds =
+                        new Rectangle2D.Float(
+                                x, y - metrics.ascent,
+                                getAdvance(), metrics.ascent + metrics.descent
+                        );
+            }
+
+            return (Rectangle2D) logicalBounds.clone();
+        }
+
+        @Override
+        float getAdvance() {
+            return fullAdvance;
+        }
+
+        @Override
+        float getAdvanceDelta(int start, int end) {
+            return ga.getAdvance() * (end - start);
+        }
+
+        @Override
+        int getCharIndexFromAdvance(float advance, int start) {
+            start -= this.start;
+
+            if (start < 0) {
+                start = 0;
+            }
+
+            int charOffset = (int) (advance/ga.getAdvance());
+
+            if (charOffset + start > length) {
+                return length + this.start;
+            }
+            return charOffset + start + this.start;
+        }
+
+        @Override
+        int getStart() {
+            return start;
+        }
+
+        @Override
+        int getEnd() {
+            return start + length;
+        }
+
+        @Override
+        int getLength() {
+            return length;
+        }
+
+        @Override
+        Shape getCharsBlackBoxBounds(int start, int limit) {
+            start -= this.start;
+            limit -= this.start;
+
+            if (limit > length) {
+                limit = length;
+            }
+
+            Rectangle2D charBounds = ga.getBounds();
+            charBounds.setRect(
+                    charBounds.getX() + ga.getAdvance() * start + x,
+                    charBounds.getY() + y,
+                    charBounds.getWidth() + ga.getAdvance() * (limit - start),
+                    charBounds.getHeight()
+            );
+
+            return charBounds;
+        }
+
+        @Override
+        float getCharPosition(int index) {
+            index -= start;
+            if (index > length) {
+                index = length;
+            }
+
+            return ga.getAdvance() * index + x;
+        }
+
+        @Override
+        float getCharAdvance(int index) {
+            return ga.getAdvance();
+        }
+
+        @Override
+        Shape getOutline() {
+            AffineTransform t = AffineTransform.getTranslateInstance(x, y);
+            return t.createTransformedShape(
+                    TextDecorator.extendOutline(this, getVisualBounds(), decoration)
+            );
+        }
+
+        @Override
+        boolean charHasZeroAdvance(int index) {
+            return false;
+        }
+
+        @Override
+        TextHitInfo hitTest(float hitX, float hitY) {
+            hitX -= x;
+
+            float tmp = hitX / ga.getAdvance();
+            int hitIndex = Math.round(tmp);
+
+            if (tmp > hitIndex) {
+                return TextHitInfo.leading(hitIndex + this.start);
+            }
+            return TextHitInfo.trailing(hitIndex + this.start);
+        }
+
+        @Override
+        void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo) {
+            // Do nothing
+        }
+
+        @Override
+        float doJustification(TextRunBreaker.JustificationInfo jInfos[]) {
+            // Do nothing
+            return 0;
+        }
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java b/awt/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java
new file mode 100644
index 0000000..f1d64fb
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java
@@ -0,0 +1,79 @@
+/*
+ *  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.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.Graphics;
+import java.awt.GraphicsConfiguration;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.WritableRaster;
+
+import org.apache.harmony.awt.gl.CommonGraphics2D;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.render.JavaBlitter;
+import org.apache.harmony.awt.gl.render.NativeImageBlitter;
+
+/**
+ * BufferedImageGraphics2D is implementation of CommonGraphics2D for
+ * drawing on buffered images. 
+ */
+public class BufferedImageGraphics2D extends CommonGraphics2D {
+    private BufferedImage bi = null;
+    private Rectangle bounds = null;
+
+    public BufferedImageGraphics2D(BufferedImage bi) {
+        super();
+        this.bi = bi;
+        this.bounds = new Rectangle(0, 0, bi.getWidth(), bi.getHeight());
+        clip(bounds);
+        dstSurf = Surface.getImageSurface(bi);
+        if(dstSurf.isNativeDrawable()){
+            blitter = NativeImageBlitter.getInstance();
+        }else{
+            blitter = JavaBlitter.getInstance();
+        }
+    }
+
+    @Override
+    public void copyArea(int x, int y, int width, int height, int dx, int dy) {
+    }
+
+    @Override
+    public Graphics create() {
+        BufferedImageGraphics2D res = new BufferedImageGraphics2D(bi);
+        copyInternalFields(res);
+        return res;
+    }
+
+    @Override
+    public GraphicsConfiguration getDeviceConfiguration() {
+        return null;
+    }
+
+    public ColorModel getColorModel() {
+        return bi.getColorModel();
+    }
+
+    public WritableRaster getWritableRaster() {
+        return bi.getRaster();
+    }
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/image/BufferedImageSource.java b/awt/org/apache/harmony/awt/gl/image/BufferedImageSource.java
new file mode 100644
index 0000000..0fe25a2
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/BufferedImageSource.java
@@ -0,0 +1,136 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageProducer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.WritableRaster;
+import java.util.Hashtable;
+
+public class BufferedImageSource implements ImageProducer {
+
+    private Hashtable<?, ?> properties;
+    private ColorModel cm;
+    private WritableRaster raster;
+    private int width;
+    private int height;
+
+    private ImageConsumer ic;
+
+    public BufferedImageSource(BufferedImage image, Hashtable<?, ?> properties){
+        if(properties == null) {
+            this.properties = new Hashtable<Object, Object>();
+        } else {
+            this.properties = properties;
+        }
+
+        width = image.getWidth();
+        height = image.getHeight();
+        cm = image.getColorModel();
+        raster = image.getRaster();
+    }
+
+    public BufferedImageSource(BufferedImage image){
+        this(image, null);
+    }
+
+    public boolean isConsumer(ImageConsumer ic) {
+        return (this.ic == ic);
+    }
+
+    public void startProduction(ImageConsumer ic) {
+        addConsumer(ic);
+    }
+
+    public void requestTopDownLeftRightResend(ImageConsumer ic) {
+    }
+
+    public void removeConsumer(ImageConsumer ic) {
+        if (this.ic == ic) {
+            this.ic = null;
+        }
+    }
+
+    public void addConsumer(ImageConsumer ic) {
+        this.ic = ic;
+        startProduction();
+    }
+
+    private void startProduction(){
+        try {
+            ic.setDimensions(width, height);
+            ic.setProperties(properties);
+            ic.setColorModel(cm);
+            ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT |
+                    ImageConsumer.COMPLETESCANLINES |
+                    ImageConsumer.SINGLEFRAME |
+                    ImageConsumer.SINGLEPASS);
+            if(cm instanceof IndexColorModel &&
+                    raster.getTransferType() == DataBuffer.TYPE_BYTE ||
+                    cm instanceof ComponentColorModel &&
+                    raster.getTransferType() == DataBuffer.TYPE_BYTE &&
+                    raster.getNumDataElements() == 1){
+                DataBufferByte dbb = (DataBufferByte) raster.getDataBuffer();
+                byte data[] = dbb.getData();
+                int off = dbb.getOffset();
+                ic.setPixels(0, 0, width, height, cm, data, off, width);
+            }else if(cm instanceof DirectColorModel &&
+                    raster.getTransferType() == DataBuffer.TYPE_INT){
+                DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
+                int data[] = dbi.getData();
+                int off = dbi.getOffset();
+                ic.setPixels(0, 0, width, height, cm, data, off, width);
+            }else if(cm instanceof DirectColorModel &&
+                    raster.getTransferType() == DataBuffer.TYPE_BYTE){
+                DataBufferByte dbb = (DataBufferByte) raster.getDataBuffer();
+                byte data[] = dbb.getData();
+                int off = dbb.getOffset();
+                ic.setPixels(0, 0, width, height, cm, data, off, width);
+            }else{
+                ColorModel rgbCM = ColorModel.getRGBdefault();
+                int pixels[] = new int[width];
+                Object pix = null;
+                for(int y = 0; y < height; y++){
+                    for(int x = 0 ; x < width; x++){
+                        pix = raster.getDataElements(x, y, pix);
+                        pixels[x] = cm.getRGB(pix);
+                    }
+                    ic.setPixels(0, y, width, 1, rgbCM, pixels, 0, width);
+                }
+            }
+            ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
+        }catch (NullPointerException e){
+            if (ic != null) {
+                ic.imageComplete(ImageConsumer.IMAGEERROR);
+            }
+        }
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java b/awt/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java
new file mode 100644
index 0000000..cc6d7cf
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java
@@ -0,0 +1,62 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 10.02.2005
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+public class ByteArrayDecodingImageSource extends DecodingImageSource {
+
+    byte imagedata[];
+    int imageoffset;
+    int imagelength;
+
+    public ByteArrayDecodingImageSource(byte imagedata[], int imageoffset,
+            int imagelength){
+        this.imagedata = imagedata;
+        this.imageoffset = imageoffset;
+        this.imagelength = imagelength;
+    }
+
+    public ByteArrayDecodingImageSource(byte imagedata[]){
+        this(imagedata, 0, imagedata.length);
+    }
+
+    @Override
+    protected boolean checkConnection() {
+        return true;
+    }
+
+    @Override
+    protected InputStream getInputStream() {
+        // BEGIN android-modified
+        // TODO: Why does a ByteArrayInputStream need to be buffered at all?
+        return new BufferedInputStream(new ByteArrayInputStream(imagedata,
+                        imageoffset, imagelength), 1024);
+        // END android-modified
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/DataBufferListener.java b/awt/org/apache/harmony/awt/gl/image/DataBufferListener.java
new file mode 100644
index 0000000..8793050
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/DataBufferListener.java
@@ -0,0 +1,31 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 13.03.2006
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+public interface DataBufferListener {
+    
+    void dataChanged();
+    void dataTaken();
+    void dataReleased();
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/DecodingImageSource.java b/awt/org/apache/harmony/awt/gl/image/DecodingImageSource.java
new file mode 100644
index 0000000..958d691
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/DecodingImageSource.java
@@ -0,0 +1,261 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+ * Created on 18.01.2005
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageProducer;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This is an abstract class that encapsulates a main part of ImageProducer functionality
+ * for the images being decoded by the native decoders, like PNG, JPEG and GIF.
+ * It helps to integrate image decoders into producer/consumer model. It provides
+ * functionality for working with several decoder instances and several image consumers
+ * simultaneously.
+ */
+public abstract class DecodingImageSource implements ImageProducer {
+    List<ImageConsumer> consumers = new ArrayList<ImageConsumer>(5);
+    List<ImageDecoder> decoders = new ArrayList<ImageDecoder>(5);
+    boolean loading;
+
+    ImageDecoder decoder;
+
+    protected abstract boolean checkConnection();
+
+    protected abstract InputStream getInputStream();
+
+    public synchronized void addConsumer(ImageConsumer ic) {
+        if (!checkConnection()) { // No permission for this consumer
+            ic.imageComplete(ImageConsumer.IMAGEERROR);
+            return;
+        }
+
+        ImageConsumer cons = findConsumer(consumers, ic);
+
+        if (cons == null) { // Try to look in the decoders
+            ImageDecoder d = null;
+
+            // Check for all existing decoders
+            for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
+                d = i.next();
+                cons = findConsumer(d.consumers, ic);
+                if (cons != null) {
+                    break;
+                }
+            }
+        }
+
+        if (cons == null) { // Not found, add this consumer
+            consumers.add(ic);
+        }
+    }
+
+    /**
+     * This method stops sending data to the given consumer
+     * @param ic - consumer
+     */
+    private void abortConsumer(ImageConsumer ic) {
+        ic.imageComplete(ImageConsumer.IMAGEERROR);
+        consumers.remove(ic);
+    }
+
+    /**
+     * This method stops sending data to the list of consumers.
+     * @param consumersList - list of consumers
+     */
+    private void abortAllConsumers(List<ImageConsumer> consumersList) {
+        for (ImageConsumer imageConsumer : consumersList) {
+            abortConsumer(imageConsumer);
+        }
+    }
+
+    public synchronized void removeConsumer(ImageConsumer ic) {
+        ImageDecoder d = null;
+
+        // Remove in all existing decoders
+        for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
+            d = i.next();
+            removeConsumer(d.consumers, ic);
+            if (d.consumers.size() <= 0) {
+                d.terminate();
+            }
+        }
+
+        // Remove in the current queue of consumers
+        removeConsumer(consumers, ic);
+    }
+
+    /**
+     * Static implementation of removeConsumer method
+     * @param consumersList - list of consumers
+     * @param ic - consumer to be removed
+     */
+    private static void removeConsumer(List<ImageConsumer> consumersList, ImageConsumer ic) {
+        ImageConsumer cons = null;
+
+        for (Iterator<ImageConsumer> i = consumersList.iterator(); i.hasNext();) {
+            cons = i.next();
+            if (cons.equals(ic)) {
+                i.remove();
+            }
+        }
+    }
+
+    public void requestTopDownLeftRightResend(ImageConsumer consumer) {
+        // Do nothing
+    }
+
+    public synchronized void startProduction(ImageConsumer ic) {
+        if (ic != null) {
+            addConsumer(ic);
+        }
+
+        if (!loading && consumers.size() > 0) {
+            ImageLoader.addImageSource(this);
+            loading = true;
+        }
+    }
+
+    public synchronized boolean isConsumer(ImageConsumer ic) {
+        ImageDecoder d = null;
+
+        // Check for all existing decoders
+        for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
+            d = i.next();
+            if (findConsumer(d.consumers, ic) != null) {
+                return true;
+            }
+        }
+
+        // Check current queue of consumers
+        return findConsumer(consumers, ic) != null;
+    }
+
+    /**
+     * Checks if the consumer is in the list and returns it it is there
+     * @param consumersList - list of consumers
+     * @param ic - consumer
+     * @return consumer if found, null otherwise
+     */
+    private static ImageConsumer findConsumer(List<ImageConsumer> consumersList, ImageConsumer ic) {
+        ImageConsumer res = null;
+
+        for (Iterator<ImageConsumer> i = consumersList.iterator(); i.hasNext();) {
+            res = i.next();
+            if (res.equals(ic)) {
+                return res;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Use this method to finish decoding or lock the list of consumers
+     * for a particular decoder
+     * @param d - decoder
+     */
+    synchronized void lockDecoder(ImageDecoder d) {
+        if (d == decoder) {
+            decoder = null;
+            startProduction(null);
+        }
+    }
+
+    /**
+     * Tries to find an appropriate decoder for the input stream and adds it
+     * to the list of decoders
+     * @return created decoder
+     */
+    private ImageDecoder createDecoder() {
+        InputStream is = getInputStream();
+
+        ImageDecoder decoder;
+
+        if (is == null) {
+            decoder = null;
+        } else {
+            decoder = ImageDecoder.createDecoder(this, is);
+        }
+
+        if (decoder != null) {
+            synchronized (this) {
+                decoders.add(decoder);
+                this.decoder = decoder;
+                loading = false;
+                consumers = new ArrayList<ImageConsumer>(5); // Reset queue
+            }
+
+            return decoder;
+        }
+        // We were not able to find appropriate decoder
+        List<ImageConsumer> cs;
+        synchronized (this) {
+            cs = consumers;
+            consumers = new ArrayList<ImageConsumer>(5);
+            loading = false;
+        }
+        abortAllConsumers(cs);
+
+        return null;
+    }
+
+    /**
+     * Stop the given decoder and remove it from the list
+     * @param dr - decoder
+     */
+    private synchronized void removeDecoder(ImageDecoder dr) {
+        lockDecoder(dr);
+        decoders.remove(dr);
+    }
+
+    /**
+     * This method serves as an entry point.
+     * It starts the decoder and loads the image data.
+     */
+    public void load() {
+        synchronized (this) {
+            if (consumers.size() == 0) {
+                loading = false;
+                return;
+            }
+        }
+
+        ImageDecoder d = createDecoder();
+        if (d != null) {
+            try {
+                decoder.decodeImage();
+            } catch (IOException e) {
+                e.printStackTrace();
+            } finally {
+                removeDecoder(d);
+                abortAllConsumers(d.consumers);
+            }
+        }
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java b/awt/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java
new file mode 100644
index 0000000..54d4664
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java
@@ -0,0 +1,68 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+ * Created on 20.01.2005
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+public class FileDecodingImageSource extends DecodingImageSource {
+  String filename;
+
+  public FileDecodingImageSource(String file) {
+    SecurityManager security = System.getSecurityManager();
+    if (security != null) {
+        security.checkRead(file);
+    }
+
+    filename = file;
+  }
+
+  @Override
+protected boolean checkConnection() {
+      SecurityManager security = System.getSecurityManager();
+      if (security != null) {
+          try {
+            security.checkRead(filename);
+          } catch (SecurityException e) {
+              return false;
+          }
+      }
+
+      return true;
+  }
+
+  @Override
+protected InputStream getInputStream() {
+    try {
+      // BEGIN android-modified
+      return new BufferedInputStream(new FileInputStream(filename), 8192);
+      // END android-modified
+    } catch (FileNotFoundException e) {
+      return null;
+    }
+  }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/GifDecoder.java b/awt/org/apache/harmony/awt/gl/image/GifDecoder.java
new file mode 100644
index 0000000..7ecb15b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/GifDecoder.java
@@ -0,0 +1,692 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+* Created on 27.01.2005
+*/
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.image.ColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.IndexColorModel;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
+public class GifDecoder extends ImageDecoder {
+    // initializes proper field IDs
+    private static native void initIDs();
+
+    static {
+        System.loadLibrary("gl"); //$NON-NLS-1$
+        initIDs();
+    }
+
+    // ImageConsumer hints: common
+    private static final int baseHints =
+            ImageConsumer.SINGLEPASS | ImageConsumer.COMPLETESCANLINES |
+            ImageConsumer.SINGLEFRAME;
+    // ImageConsumer hints: interlaced
+    private static final int interlacedHints =
+            baseHints | ImageConsumer.RANDOMPIXELORDER;
+
+    // Impossible color value - no translucent pixels allowed
+    static final int IMPOSSIBLE_VALUE = 0x0FFFFFFF;
+
+    // I/O buffer
+    private static final int BUFFER_SIZE = 1024;
+    private byte buffer[] = new byte[BUFFER_SIZE];
+
+    GifDataStream gifDataStream = new GifDataStream();
+    GifGraphicBlock currBlock;
+
+    // Pointer to native structure which store decoding state
+    // between subsequent decoding/IO-suspension cycles
+    private long hNativeDecoder; // NULL initially
+
+    // Number of bytes eaten by the native decoder
+    private int bytesConsumed;
+
+    private boolean consumersPrepared;
+    private Hashtable<String, String> properties = new Hashtable<String, String>();
+
+    // Could be set up by java code or native method when
+    // transparent pixel index changes or local color table encountered
+    private boolean forceRGB;
+
+    private byte screenBuffer[];
+    private int screenRGBBuffer[];
+
+    public GifDecoder(DecodingImageSource src, InputStream is) {
+        super(src, is);
+    }
+
+    private static native int[] toRGB(byte imageData[], byte colormap[], int transparentColor);
+
+    private static native void releaseNativeDecoder(long hDecoder);
+
+    private native int decode(
+            byte input[],
+            int bytesInBuffer,
+            long hDecoder,
+            GifDataStream dataStream,
+            GifGraphicBlock currBlock
+            );
+
+    private int[] getScreenRGBBuffer() {
+        if (screenRGBBuffer == null) {
+            if (screenBuffer != null) {
+                int transparentColor =
+                        gifDataStream.logicalScreen.globalColorTable.cm.getTransparentPixel();
+                transparentColor = transparentColor > 0 ? transparentColor : IMPOSSIBLE_VALUE;
+                screenRGBBuffer =
+                        toRGB(
+                                screenBuffer,
+                                gifDataStream.logicalScreen.globalColorTable.colors,
+                                transparentColor
+                        );
+            } else {
+                int size = gifDataStream.logicalScreen.logicalScreenHeight *
+                        gifDataStream.logicalScreen.logicalScreenWidth;
+                screenRGBBuffer = new int[size];
+            }
+        }
+
+        return screenRGBBuffer;
+    }
+
+    private void prepareConsumers() {
+        GifLogicalScreen gls = gifDataStream.logicalScreen;
+        setDimensions(gls.logicalScreenWidth,
+                gls.logicalScreenHeight);
+        setProperties(properties);
+
+        currBlock = gifDataStream.graphicBlocks.get(0);
+        if (forceRGB) {
+            setColorModel(ColorModel.getRGBdefault());
+        } else {
+            setColorModel(gls.globalColorTable.getColorModel(currBlock.transparentColor));
+        }
+
+        // Fill screen buffer with the background or transparent color
+        if (forceRGB) {
+            int fillColor = 0xFF000000;
+            if (gls.backgroundColor != IMPOSSIBLE_VALUE) {
+                fillColor = gls.backgroundColor;
+            }
+
+            Arrays.fill(getScreenRGBBuffer(), fillColor);
+        } else {
+            int fillColor = 0;
+
+            if (gls.backgroundColor != IMPOSSIBLE_VALUE) {
+                fillColor = gls.backgroundColor;
+            } else {
+                fillColor = gls.globalColorTable.cm.getTransparentPixel();
+            }
+
+            screenBuffer = new byte[gls.logicalScreenHeight*gls.logicalScreenWidth];
+            Arrays.fill(screenBuffer, (byte) fillColor);
+        }
+
+        setHints(interlacedHints); // XXX - always random pixel order
+    }
+
+    @Override
+    public void decodeImage() throws IOException {
+        try {
+            int bytesRead = 0;
+            int needBytes, offset, bytesInBuffer = 0;
+            boolean eosReached = false;
+            GifGraphicBlock blockToDispose = null;
+
+            // Create new graphic block
+            if (currBlock == null) {
+                currBlock = new GifGraphicBlock();
+                gifDataStream.graphicBlocks.add(currBlock);
+            }
+
+            // Read from the input stream
+            for (;;) {
+                needBytes = BUFFER_SIZE - bytesInBuffer;
+                offset = bytesInBuffer;
+
+                bytesRead = inputStream.read(buffer, offset, needBytes);
+
+                if (bytesRead < 0) {
+                    eosReached = true;
+                    bytesRead = 0;
+                } // Don't break, maybe something left in buffer
+
+                // Keep track on how much bytes left in buffer
+                bytesInBuffer += bytesRead;
+
+                // Here we pass number of new bytes read from the input stream (bytesRead)
+                // since native decoder uses java buffer and doesn't have its own
+                // buffer. So it adds this number to the number of bytes left
+                // in buffer from the previous call.
+                int numLines = decode(
+                        buffer,
+                        bytesRead,
+                        hNativeDecoder,
+                        gifDataStream,
+                        currBlock);
+
+                // Keep track on how much bytes left in buffer
+                bytesInBuffer -= bytesConsumed;
+
+                if (
+                        !consumersPrepared &&
+                        gifDataStream.logicalScreen.completed &&
+                        gifDataStream.logicalScreen.globalColorTable.completed &&
+                        (currBlock.imageData != null || // Have transparent pixel filled
+                        currBlock.rgbImageData != null)
+                ) {
+                    prepareConsumers();
+                    consumersPrepared = true;
+                }
+
+                if (bytesConsumed < 0) {
+                    break; // Error exit
+                }
+
+                if (currBlock != null) {
+                    if (numLines != 0) {
+                        // Dispose previous image only before showing next
+                        if (blockToDispose != null) {
+                            blockToDispose.dispose();
+                            blockToDispose = null;
+                        }
+
+                        currBlock.sendNewData(this, numLines);
+                    }
+
+                    if (currBlock.completed && hNativeDecoder != 0) {
+                        blockToDispose = currBlock; // Dispose only before showing new pixels
+                        currBlock = new GifGraphicBlock();
+                        gifDataStream.graphicBlocks.add(currBlock);
+                    }
+                }
+
+                if (hNativeDecoder == 0) {
+                    break;
+                }
+
+                if (eosReached && numLines == 0) { // Maybe image is truncated...
+                    releaseNativeDecoder(hNativeDecoder);
+                    break;
+                }
+            }
+        } finally {
+            closeStream();
+        }
+
+        // Here all animation goes
+        // Repeat image loopCount-1 times or infinitely if loopCount = 0
+        if (gifDataStream.loopCount != 1) {
+            if (currBlock.completed == false) {
+                gifDataStream.graphicBlocks.remove(currBlock);
+            }
+
+            int numFrames = gifDataStream.graphicBlocks.size();
+            // At first last block will be disposed
+            GifGraphicBlock gb =
+                    gifDataStream.graphicBlocks.get(numFrames-1);
+
+            ImageLoader.beginAnimation();
+
+            while (gifDataStream.loopCount != 1) {
+                if (gifDataStream.loopCount != 0) {
+                    gifDataStream.loopCount--;
+                }
+
+                // Show all frames
+                for (int i=0; i<numFrames; i++) {
+                    gb.dispose();
+                    gb = gifDataStream.graphicBlocks.get(i);
+
+                    // Show one frame
+                    if (forceRGB) {
+                        setPixels(
+                                gb.imageLeft,
+                                gb.imageTop,
+                                gb.imageWidth,
+                                gb.imageHeight,
+                                ColorModel.getRGBdefault(),
+                                gb.getRgbImageData(),
+                                0,
+                                gb.imageWidth
+                        );
+                    } else {
+                        setPixels(
+                                gb.imageLeft,
+                                gb.imageTop,
+                                gb.imageWidth,
+                                gb.imageHeight,
+                                null,
+                                gb.imageData,
+                                0,
+                                gb.imageWidth
+                        );
+                    }
+                }
+            }
+            ImageLoader.endAnimation();
+        }
+
+        imageComplete(ImageConsumer.STATICIMAGEDONE);
+    }
+
+    void setComment(String newComment) {
+        Object currComment = properties.get("comment"); //$NON-NLS-1$
+
+        if (currComment == null) {
+            properties.put("comment", newComment); //$NON-NLS-1$
+        } else {
+            properties.put("comment", (String) currComment + "\n" + newComment); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        setProperties(properties);
+    }
+
+    class GifDataStream {
+        //  Indicates that reading of the whole data stream accomplished
+        boolean completed = false;
+
+        // Added to support Netscape 2.0 application
+        // extension block.
+        int loopCount = 1;
+
+        GifLogicalScreen logicalScreen = new GifLogicalScreen();
+        List<GifGraphicBlock> graphicBlocks = new ArrayList<GifGraphicBlock>(10); // Of GifGraphicBlocks
+
+        // Comments from the image
+        String comments[];
+    }
+
+    class GifLogicalScreen {
+        //  Indicates that reading of this block accomplished
+        boolean completed = false;
+
+        int logicalScreenWidth;
+        int logicalScreenHeight;
+
+        int backgroundColor = IMPOSSIBLE_VALUE;
+
+        GifColorTable globalColorTable = new GifColorTable();
+    }
+
+    class GifGraphicBlock {
+        //  Indicates that reading of this block accomplished
+        boolean completed = false;
+
+        final static int DISPOSAL_NONE = 0;
+        final static int DISPOSAL_NODISPOSAL = 1;
+        final static int DISPOSAL_BACKGROUND = 2;
+        final static int DISPOSAL_RESTORE = 3;
+
+        int disposalMethod;
+        int delayTime; // Multiplied by 10 already
+        int transparentColor = IMPOSSIBLE_VALUE;
+
+        int imageLeft;
+        int imageTop;
+        int imageWidth;
+        int imageHeight;
+
+        // Auxilliary variables to minimize computations
+        int imageRight;
+        int imageBottom;
+
+        boolean interlace;
+
+        // Don't need local color table - if it is specified
+        // image data are converted to RGB in the native code
+
+        byte imageData[] = null;
+        int rgbImageData[] = null;
+
+        private int currY = 0; // Current output scanline
+
+        int[] getRgbImageData() {
+            if (rgbImageData == null) {
+                rgbImageData =
+                        toRGB(
+                                imageData,
+                                gifDataStream.logicalScreen.globalColorTable.colors,
+                                transparentColor
+                        );
+                if (transparentColor != IMPOSSIBLE_VALUE) {
+                    transparentColor =
+                            gifDataStream.logicalScreen.globalColorTable.cm.getRGB(transparentColor);
+                    transparentColor &= 0x00FFFFFF;
+                }
+            }
+            return rgbImageData;
+        }
+
+        private void replaceTransparentPixels(int numLines) {
+            List<GifGraphicBlock> graphicBlocks = gifDataStream.graphicBlocks;
+            int prevBlockIndex = graphicBlocks.indexOf(this) - 1;
+
+            if (prevBlockIndex >= 0) {
+                int maxY = currY + numLines + imageTop;
+                int offset = currY * imageWidth;
+
+                // Update right and bottom coordinates
+                imageRight = imageLeft + imageWidth;
+                imageBottom = imageTop + imageHeight;
+
+                int globalWidth = gifDataStream.logicalScreen.logicalScreenWidth;
+                int pixelValue, imageOffset;
+                int rgbData[] = forceRGB ? getRgbImageData() : null;
+
+                for (int y = currY + imageTop; y < maxY; y++) {
+                    imageOffset = globalWidth * y + imageLeft;
+                    for (int x = imageLeft; x < imageRight; x++) {
+                        pixelValue = forceRGB ?
+                                rgbData[offset] :
+                                imageData[offset] & 0xFF;
+                        if (pixelValue == transparentColor) {
+                            if (forceRGB) {
+                                pixelValue = getScreenRGBBuffer() [imageOffset];
+                                rgbData[offset] = pixelValue;
+                            } else {
+                                pixelValue = screenBuffer [imageOffset];
+                                imageData[offset] = (byte) pixelValue;
+                            }
+                        }
+                        offset++;
+                        imageOffset++;
+                    } // for
+                } // for
+
+            } // if (prevBlockIndex >= 0)
+        }
+
+        public void sendNewData(GifDecoder decoder, int numLines) {
+            // Get values for transparent pixels
+            // from the perevious frames
+            if (transparentColor != IMPOSSIBLE_VALUE) {
+                replaceTransparentPixels(numLines);
+            }
+
+            if (forceRGB) {
+                decoder.setPixels(
+                        imageLeft,
+                        imageTop + currY,
+                        imageWidth,
+                        numLines,
+                        ColorModel.getRGBdefault(),
+                        getRgbImageData(),
+                        currY*imageWidth,
+                        imageWidth
+                );
+            } else {
+                decoder.setPixels(
+                        imageLeft,
+                        imageTop + currY,
+                        imageWidth,
+                        numLines,
+                        null,
+                        imageData,
+                        currY*imageWidth,
+                        imageWidth
+                );
+            }
+
+            currY += numLines;
+        }
+
+        public void dispose() {
+            imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+
+            // Show current frame until delayInterval will not elapse
+            if (delayTime > 0) {
+                try {
+                    Thread.sleep(delayTime);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            } else {
+                Thread.yield(); // Allow consumers to consume data
+            }
+
+            // Don't dispose if image is outside of the visible area
+            if (imageLeft > gifDataStream.logicalScreen.logicalScreenWidth ||
+                    imageTop > gifDataStream.logicalScreen.logicalScreenHeight) {
+                disposalMethod = DISPOSAL_NONE;
+            }
+
+            switch(disposalMethod) {
+                case DISPOSAL_BACKGROUND: {
+                    if (forceRGB) {
+                        getRgbImageData(); // Ensure that transparentColor is RGB, not index
+
+                        int data[] = new int[imageWidth*imageHeight];
+
+                        // Compatibility: Fill with transparent color if we have one
+                        if (transparentColor != IMPOSSIBLE_VALUE) {
+                            Arrays.fill(
+                                    data,
+                                    transparentColor
+                            );
+                        } else {
+                            Arrays.fill(
+                                    data,
+                                    gifDataStream.logicalScreen.backgroundColor
+                            );
+                        }
+
+                        setPixels(
+                                imageLeft,
+                                imageTop,
+                                imageWidth,
+                                imageHeight,
+                                ColorModel.getRGBdefault(),
+                                data,
+                                0,
+                                imageWidth
+                        );
+
+                        sendToScreenBuffer(data);
+                    } else {
+                        byte data[] = new byte[imageWidth*imageHeight];
+
+                        // Compatibility: Fill with transparent color if we have one
+                        if (transparentColor != IMPOSSIBLE_VALUE) {
+                            Arrays.fill(
+                                    data,
+                                    (byte) transparentColor
+                            );
+                        } else {
+                            Arrays.fill(
+                                    data,
+                                    (byte) gifDataStream.logicalScreen.backgroundColor
+                            );
+                        }
+
+                        setPixels(
+                                imageLeft,
+                                imageTop,
+                                imageWidth,
+                                imageHeight,
+                                null,
+                                data,
+                                0,
+                                imageWidth
+                        );
+
+                        sendToScreenBuffer(data);
+                    }
+                    break;
+                }
+                case DISPOSAL_RESTORE: {
+                    screenBufferToScreen();
+                    break;
+                }
+                case DISPOSAL_NONE:
+                case DISPOSAL_NODISPOSAL:
+                default: {
+                    // Copy transmitted data to the screen buffer
+                    Object data = forceRGB ? (Object) getRgbImageData() : imageData;
+                    sendToScreenBuffer(data);
+                    break;
+                }
+            }
+        }
+
+        private void sendToScreenBuffer(Object data) {
+            int dataInt[];
+            byte dataByte[];
+
+            int width = gifDataStream.logicalScreen.logicalScreenWidth;
+
+
+            if (forceRGB) {
+                dataInt = (int[]) data;
+
+                if (imageWidth == width) {
+                    System.arraycopy(dataInt,
+                            0,
+                            getScreenRGBBuffer(),
+                            imageLeft + imageTop*width,
+                            dataInt.length
+                    );
+                } else { // Each scanline
+                    copyScanlines(dataInt, getScreenRGBBuffer(), width);
+                }
+            } else {
+                dataByte = (byte[]) data;
+
+                if (imageWidth == width) {
+                    System.arraycopy(dataByte,
+                            0,
+                            screenBuffer,
+                            imageLeft + imageTop*width,
+                            dataByte.length
+                    );
+                } else { // Each scanline
+                    copyScanlines(dataByte, screenBuffer, width);
+                }
+            }
+        } // sendToScreenBuffer
+
+        private void copyScanlines(Object src, Object dst, int width) {
+            for (int i=0; i<imageHeight; i++) {
+                System.arraycopy(src,
+                        i*imageWidth,
+                        dst,
+                        imageLeft + i*width + imageTop*width,
+                        imageWidth
+                );
+            } // for
+        }
+
+        private void screenBufferToScreen() {
+            int width = gifDataStream.logicalScreen.logicalScreenWidth;
+
+            Object dst = forceRGB ?
+                    (Object) new int[imageWidth*imageHeight] :
+                    new byte[imageWidth*imageHeight];
+
+            Object src = forceRGB ?
+                    getScreenRGBBuffer() :
+                    (Object) screenBuffer;
+
+            int offset = 0;
+            Object toSend;
+
+            if (width == imageWidth) {
+                offset = imageWidth * imageTop;
+                toSend = src;
+            } else {
+                for (int i=0; i<imageHeight; i++) {
+                    System.arraycopy(src,
+                            imageLeft + i*width + imageTop*width,
+                            dst,
+                            i*imageWidth,
+                            imageWidth
+                    );
+                } // for
+                toSend = dst;
+            }
+
+            if (forceRGB) {
+                setPixels(
+                        imageLeft,
+                        imageTop,
+                        imageWidth,
+                        imageHeight,
+                        ColorModel.getRGBdefault(),
+                        (int [])toSend,
+                        offset,
+                        imageWidth
+                );
+            } else {
+                setPixels(
+                        imageLeft,
+                        imageTop,
+                        imageWidth,
+                        imageHeight,
+                        null,
+                        (byte [])toSend,
+                        offset,
+                        imageWidth
+                );
+            }
+        }
+    }
+
+    class GifColorTable {
+        //  Indicates that reading of this block accomplished
+        boolean completed = false;
+
+        IndexColorModel cm = null;
+        int size = 0; // Actual number of colors in the color table
+        byte colors[] = new byte[256*3];
+
+        IndexColorModel getColorModel(int transparentColor) {
+            if (cm != null) {
+                if (transparentColor != cm.getTransparentPixel()) {
+                    return cm = null; // Force default ARGB color model
+                }
+                return cm;
+            } else
+                if (completed && size > 0) {
+                    if (transparentColor == IMPOSSIBLE_VALUE) {
+                        return cm =
+                                new IndexColorModel(8, size, colors, 0, false);
+                    }
+
+                    if (transparentColor > size) {
+                        size = transparentColor + 1;
+                    }
+                    return cm =
+                            new IndexColorModel(8, size, colors, 0, false, transparentColor);
+                }
+
+            return cm = null; // Force default ARGB color model
+        }
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/ImageDecoder.java b/awt/org/apache/harmony/awt/gl/image/ImageDecoder.java
new file mode 100644
index 0000000..d16128e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/ImageDecoder.java
@@ -0,0 +1,258 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+ * Created on 18.01.2005
+ */
+package org.apache.harmony.awt.gl.image;
+
+import com.android.internal.awt.AndroidImageDecoder;
+
+import java.awt.image.ColorModel;
+import java.awt.image.ImageConsumer;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ConcurrentModificationException;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * This class contains common functionality for all image decoders.
+ */
+public abstract class ImageDecoder {
+    
+    /** Image types */
+    public static final int GENERIC_DECODER = 0;
+    public static final int JPG_DECODER = 1;
+    public static final int GIF_DECODER = 2;
+    public static final int PNG_DECODER = 3;
+    
+    private static final int MAX_BYTES_IN_SIGNATURE = 8;
+
+    protected List<ImageConsumer> consumers;
+    protected InputStream inputStream;
+    protected DecodingImageSource src;
+
+    protected boolean terminated;
+
+    /**
+     * Chooses appropriate image decoder by looking into input stream and checking
+     * the image signature.
+     * @param src - image producer, required for passing data to it from the
+     * created decoder via callbacks
+     * @param is - stream
+     * @return decoder
+     */
+    static ImageDecoder createDecoder(DecodingImageSource src, InputStream is) {
+        InputStream markable;
+
+        if (!is.markSupported()) {
+            // BEGIN android-modified
+            markable = new BufferedInputStream(is, 8192);
+            // END android-modified
+        } else {
+            markable = is;
+        }
+            
+        // Read the signature from the stream and then reset it back
+        try {
+            markable.mark(MAX_BYTES_IN_SIGNATURE);
+
+            byte[] signature = new byte[MAX_BYTES_IN_SIGNATURE];
+            markable.read(signature, 0, MAX_BYTES_IN_SIGNATURE);
+            markable.reset();
+
+            if ((signature[0] & 0xFF) == 0xFF &&
+                    (signature[1] & 0xFF) == 0xD8 &&
+                    (signature[2] & 0xFF) == 0xFF) { // JPEG
+                return loadDecoder(PNG_DECODER, src, is);
+            } else if ((signature[0] & 0xFF) == 0x47 && // G
+                    (signature[1] & 0xFF) == 0x49 && // I
+                    (signature[2] & 0xFF) == 0x46) { // F
+                return loadDecoder(GIF_DECODER, src, is);
+            } else if ((signature[0] & 0xFF) == 137 && // PNG signature: 137 80 78 71 13 10 26 10
+                    (signature[1] & 0xFF) == 80 &&
+                    (signature[2] & 0xFF) == 78 &&
+                    (signature[3] & 0xFF) == 71 &&
+                    (signature[4] & 0xFF) == 13 &&
+                    (signature[5] & 0xFF) == 10 &&
+                    (signature[6] & 0xFF) == 26 &&
+                    (signature[7] & 0xFF) == 10) {
+                return loadDecoder(JPG_DECODER, src, is);
+            }
+
+            return loadDecoder(GENERIC_DECODER, src, is);
+            
+        } catch (IOException e) { // Silently
+        }
+
+        return null;
+    }
+    
+    /*
+     * In the future, we might return different decoders for differen image types.
+     * But for now, we always return the generic one.
+     * Also: we could add a factory to load image decoder.
+     */
+    private static ImageDecoder loadDecoder(int type, DecodingImageSource src, 
+            InputStream is) {
+        return new AndroidImageDecoder(src, is);
+    }
+
+    protected ImageDecoder(DecodingImageSource _src, InputStream is) {
+        src = _src;
+        consumers = src.consumers;
+        inputStream = is;
+    }
+
+    public abstract void decodeImage() throws IOException;
+
+    public synchronized void closeStream() {
+        if (inputStream != null) {
+            try {
+                inputStream.close();
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    /**
+     * Stops the decoding by interrupting the current decoding thread.
+     * Used when all consumers are removed and there's no more need to
+     * run the decoder.
+     */
+    public void terminate() {
+        src.lockDecoder(this);
+        closeStream();
+
+        AccessController.doPrivileged(
+                new PrivilegedAction<Void>() {
+                    public Void run() {
+                        Thread.currentThread().interrupt();
+                        return null;
+                    }
+                }
+        );
+
+        terminated = true;
+    }
+
+    protected void setDimensions(int w, int h) {
+        if (terminated) {
+            return;
+        }
+
+        for (ImageConsumer ic : consumers) {
+            ic.setDimensions(w, h);
+        }
+    }
+
+    protected void setProperties(Hashtable<?, ?> props) {
+        if (terminated) {
+            return;
+        }
+
+        for (ImageConsumer ic : consumers) {
+            ic.setProperties(props);
+        }
+    }
+
+    protected void setColorModel(ColorModel cm) {
+        if (terminated) {
+            return;
+        }
+
+        for (ImageConsumer ic : consumers) {
+            ic.setColorModel(cm);
+        }
+    }
+
+    protected void setHints(int hints) {
+        if (terminated) {
+            return;
+        }
+
+        for (ImageConsumer ic : consumers) {
+            ic.setHints(hints);
+        }
+    }
+
+    protected void setPixels(
+            int x, int y,
+            int w, int h,
+            ColorModel model,
+            byte pix[],
+            int off, int scansize
+            ) {
+        if (terminated) {
+            return;
+        }
+
+        src.lockDecoder(this);
+
+        for (ImageConsumer ic : consumers) {
+            ic.setPixels(x, y, w, h, model, pix, off, scansize);
+        }
+    }
+
+    protected void setPixels(
+            int x, int y,
+            int w, int h,
+            ColorModel model,
+            int pix[],
+            int off, int scansize
+            ) {
+        if (terminated) {
+            return;
+        }
+
+        src.lockDecoder(this);
+
+        for (ImageConsumer ic : consumers) {
+            ic.setPixels(x, y, w, h, model, pix, off, scansize);
+        }
+    }
+
+    protected void imageComplete(int status) {
+        if (terminated) {
+            return;
+        }
+
+        src.lockDecoder(this);
+
+        ImageConsumer ic = null;
+
+        for (Iterator<ImageConsumer> i = consumers.iterator(); i.hasNext();) {
+            try {
+                ic = i.next();
+            } catch (ConcurrentModificationException e) {
+                i = consumers.iterator();
+                continue;
+            }
+            ic.imageComplete(status);
+        }
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/ImageLoader.java b/awt/org/apache/harmony/awt/gl/image/ImageLoader.java
new file mode 100644
index 0000000..5c7d180
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/ImageLoader.java
@@ -0,0 +1,208 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+ * Created on 18.01.2005
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This class provides functionality for simultaneous loading of
+ * several images and running animation.
+ */
+public class ImageLoader extends Thread {
+    // Contains ImageLoader objects
+    // and queue of image sources waiting to be loaded
+    static class ImageLoadersStorage {
+        private static final int MAX_THREADS = 5;
+        private static final int TIMEOUT = 4000;
+        static ImageLoadersStorage instance;
+
+        List<DecodingImageSource> queue = new LinkedList<DecodingImageSource>();
+        List<Thread> loaders = new ArrayList<Thread>(MAX_THREADS);
+
+        private int freeLoaders;
+
+        private ImageLoadersStorage() {}
+
+        static ImageLoadersStorage getStorage() {
+            if (instance == null) {
+                instance = new ImageLoadersStorage();
+            }
+
+            return instance;
+        }
+    }
+
+    ImageLoader() {
+        super();
+        setDaemon(true);
+    }
+
+    /**
+     * This method creates a new thread which is able to load an image
+     * or run animation (if the number of existing loader threads does not
+     * exceed the limit).
+     */
+    private static void createLoader() {
+        final ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+
+        synchronized(storage.loaders) {
+            if (storage.loaders.size() < ImageLoadersStorage.MAX_THREADS) {
+                AccessController.doPrivileged(
+                        new PrivilegedAction<Void>() {
+                            public Void run() {
+                                ImageLoader loader = new ImageLoader();
+                                storage.loaders.add(loader);
+                                loader.start();
+                                return null;
+                            }
+                        });
+            }
+        }
+    }
+
+    /**
+     * Adds a new image source to the queue and starts a new loader
+     * thread if required
+     * @param imgSrc - image source
+     */
+    public static void addImageSource(DecodingImageSource imgSrc) {
+        ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+        synchronized(storage.queue) {
+            if (!storage.queue.contains(imgSrc)) {
+                storage.queue.add(imgSrc);
+            }
+            if (storage.freeLoaders == 0) {
+                createLoader();
+            }
+
+            storage.queue.notify();
+        }
+    }
+
+    /**
+     * Waits for a new ImageSource until timout expires.
+     * Loader thread will terminate after returning from this method
+     * if timeout expired and image source was not picked up from the queue.
+     * @return image source picked up from the queue or null if timeout expired
+     */
+    private static DecodingImageSource getWaitingImageSource() {
+        ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+
+        synchronized(storage.queue) {
+            DecodingImageSource isrc = null;
+
+            if (storage.queue.size() == 0) {
+                try {
+                    storage.freeLoaders++;
+                    storage.queue.wait(ImageLoadersStorage.TIMEOUT);
+                } catch (InterruptedException e) {
+                    return null;
+                } finally {
+                    storage.freeLoaders--;
+                }
+            }
+
+            if (storage.queue.size() > 0) {
+                isrc = storage.queue.get(0);
+                storage.queue.remove(0);
+            }
+
+            return isrc;
+        }
+    }
+
+    /**
+     * Entry point of the loader thread. Picks up image sources and
+     * runs decoders for them while there are available image sources in the queue.
+     * If there are no and timeout expires it terminates.
+     */
+    @Override
+    public void run() {
+        ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+
+        try {
+            while (storage.loaders.contains(this)) {
+                Thread.interrupted(); // Reset the interrupted flag
+                DecodingImageSource isrc = getWaitingImageSource();
+                if (isrc != null) {
+                    try {
+                        isrc.load();
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                } else {
+                    break; // Don't wait if timeout expired - terminate loader
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            synchronized(storage.loaders) {
+                storage.loaders.remove(Thread.currentThread());
+            }
+        }
+    }
+
+    /**
+     * Removes current thread from loaders (so we are able
+     * to create more loaders) and decreases its priority.
+     */
+    static void beginAnimation() {
+        ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+        Thread currThread = Thread.currentThread();
+
+        synchronized(storage) {
+            storage.loaders.remove(currThread);
+
+            if (storage.freeLoaders < storage.queue.size()) {
+                createLoader();
+            }
+        }
+
+        currThread.setPriority(Thread.MIN_PRIORITY);
+    }
+
+    /**
+     * Sends the current thread to wait for the new images to load
+     * if there are free placeholders for loaders
+     */
+    static void endAnimation() {
+        ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+        Thread currThread = Thread.currentThread();
+
+        synchronized(storage) {
+            if (storage.loaders.size() < ImageLoadersStorage.MAX_THREADS &&
+                    !storage.loaders.contains(currThread)
+            ) {
+                storage.loaders.add(currThread);
+            }
+        }
+
+        currThread.setPriority(Thread.NORM_PRIORITY);
+    }
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/image/JpegDecoder.java b/awt/org/apache/harmony/awt/gl/image/JpegDecoder.java
new file mode 100644
index 0000000..2e64427
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/JpegDecoder.java
@@ -0,0 +1,231 @@
+/*
+*  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.
+*/
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.image.*;
+import java.awt.color.ColorSpace;
+import java.awt.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class JpegDecoder extends ImageDecoder {
+    // Only 2 output colorspaces expected. Others are converted into
+    // these ones.
+    // 1. Grayscale
+    public static final int JCS_GRAYSCALE = 1;
+    // 2. RGB
+    public static final int JCS_RGB = 2;
+
+    // Flags for the consumer, progressive JPEG
+    private static final int hintflagsProgressive =
+            ImageConsumer.SINGLEFRAME | // JPEG is a static image
+            ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible
+            ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines
+    // Flags for the consumer, singlepass JPEG
+    private static final int hintflagsSingle =
+            ImageConsumer.SINGLEPASS |
+            hintflagsProgressive;
+
+    // Buffer for the stream
+    private static final int BUFFER_SIZE = 1024;
+    private byte buffer[] = new byte[BUFFER_SIZE];
+
+    // 3 possible color models only
+    private static ColorModel cmRGB;
+    private static ColorModel cmGray;
+
+    // initializes proper field IDs
+    private static native void initIDs();
+
+    // Pointer to native structure which store decoding state
+    // between subsequent decoding/IO-suspension cycles
+    private long hNativeDecoder = 0; // NULL initially
+
+    private boolean headerDone = false;
+
+    // Next 4 members are filled by the native method (decompress).
+    // We can simply check if imageWidth is still negative to find
+    // out if they are already filled.
+    private int imageWidth = -1;
+    private int imageHeight = -1;
+    private boolean progressive = false;
+    private int jpegColorSpace = 0;
+
+    // Stores number of bytes consumed by the native decoder
+    private int bytesConsumed = 0;
+    // Stores current scanline returned by the decoder
+    private int currScanline = 0;
+
+    private ColorModel cm = null;
+
+    static {
+        System.loadLibrary("jpegdecoder"); //$NON-NLS-1$
+
+        cmGray = new ComponentColorModel(
+                ColorSpace.getInstance(ColorSpace.CS_GRAY),
+                false, false,
+                Transparency.OPAQUE, DataBuffer.TYPE_BYTE
+        );
+
+        // Create RGB color model
+        cmRGB = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF);
+
+        initIDs();
+    }
+
+    public JpegDecoder(DecodingImageSource src, InputStream is) {
+        super(src, is);
+    }
+
+    /*
+    public JpegDecoder(InputStream iStream, ImageConsumer iConsumer) {
+    inputStream = iStream;
+    consumer = iConsumer;
+    }
+    */
+
+    /**
+     * @return - not NULL if call is successful
+     */
+    private native Object decode(
+            byte[] input,
+            int bytesInBuffer,
+            long hDecoder);
+
+    private static native void releaseNativeDecoder(long hDecoder);
+
+    @Override
+    public void decodeImage() throws IOException {
+        try {
+            int bytesRead = 0, dataLength = 0;
+            boolean eosReached = false;
+            int needBytes, offset, bytesInBuffer = 0;
+            byte byteOut[] = null;
+            int intOut[] = null;
+            // Read from the input stream
+            for (;;) {
+                needBytes = BUFFER_SIZE - bytesInBuffer;
+                offset = bytesInBuffer;
+
+                bytesRead = inputStream.read(buffer, offset, needBytes);
+
+                if (bytesRead < 0) {
+                    bytesRead = 0;//break;
+                    eosReached = true;
+                } // Don't break, maybe something left in buffer
+
+                // Keep track on how much bytes left in buffer
+                bytesInBuffer += bytesRead;
+
+                // Here we pass overall number of bytes left in the java buffer
+                // (bytesInBuffer) since jpeg decoder has its own buffer and consumes
+                // as many bytes as it can. If there are any unconsumed bytes
+                // it didn't add them to its buffer...
+                Object arr = decode(
+                        buffer,
+                        bytesInBuffer,
+                        hNativeDecoder);
+
+                // Keep track on how much bytes left in buffer
+                bytesInBuffer -= bytesConsumed;
+
+                if (!headerDone && imageWidth != -1) {
+                    returnHeader();
+                    headerDone = true;
+                }
+
+                if (bytesConsumed < 0) {
+                    break; // Error exit
+                }
+
+                if (arr instanceof byte[]) {
+                    byteOut = (byte[]) arr;
+                    dataLength = byteOut.length;
+                    returnData(byteOut, currScanline);
+                } else if (arr instanceof int[]) {
+                    intOut = (int[]) arr;
+                    dataLength = intOut.length;
+                    returnData(intOut, currScanline);
+                } else {
+                    dataLength = 0;
+                }
+
+                if (hNativeDecoder == 0) {
+                    break;
+                }
+
+                if (dataLength == 0 && eosReached) {
+                    releaseNativeDecoder(hNativeDecoder);
+                    break; // Probably image is truncated
+                }
+            }
+            imageComplete(ImageConsumer.STATICIMAGEDONE);
+        } catch (IOException e) {
+            throw e;
+        } finally {
+            closeStream();
+        }
+    }
+
+    public void returnHeader() {
+        setDimensions(imageWidth, imageHeight);
+
+        switch (jpegColorSpace) {
+            case JCS_GRAYSCALE: cm = cmGray; break;
+            case JCS_RGB: cm = cmRGB; break;
+            default: 
+                // awt.3D=Unknown colorspace
+                throw new IllegalArgumentException(Messages.getString("awt.3D")); //$NON-NLS-1$
+        }
+        setColorModel(cm);
+
+        setHints(progressive ? hintflagsProgressive : hintflagsSingle);
+
+        setProperties(new Hashtable<Object, Object>()); // Empty
+    }
+
+    // Send the data to the consumer
+    public void returnData(int data[], int currScanLine) {
+        // Send 1 or more scanlines to the consumer.
+        int numScanlines = data.length / imageWidth;
+        if (numScanlines > 0) {
+            setPixels(
+                    0, currScanLine - numScanlines,
+                    imageWidth, numScanlines,
+                    cm, data, 0, imageWidth
+            );
+        }
+    }
+
+    public void returnData(byte data[], int currScanLine) {
+        int numScanlines = data.length / imageWidth;
+        if (numScanlines > 0) {
+            setPixels(
+                    0, currScanLine - numScanlines,
+                    imageWidth, numScanlines,
+                    cm, data, 0, imageWidth
+            );
+        }
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/OffscreenImage.java b/awt/org/apache/harmony/awt/gl/image/OffscreenImage.java
new file mode 100644
index 0000000..3445f8e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/OffscreenImage.java
@@ -0,0 +1,532 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 22.12.2004
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.WritableRaster;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * This class represent implementation of abstract Image class
+ */
+public class OffscreenImage extends Image implements ImageConsumer {
+
+    static final ColorModel rgbCM = ColorModel.getRGBdefault();
+    ImageProducer src;
+    BufferedImage image;
+    ColorModel cm;
+    WritableRaster raster;
+    boolean isIntRGB;
+    Hashtable<?, ?> properties;
+    Vector<ImageObserver> observers;
+    int width;
+    int height;
+    int imageState;
+    int hints;
+    private boolean producing;
+    private ImageSurface imageSurf;
+
+    public OffscreenImage(ImageProducer ip){
+        imageState = 0;
+        src = ip;
+        width = -1;
+        height = -1;
+        observers = new Vector<ImageObserver>();
+        producing = false;
+    }
+
+    @Override
+    public Object getProperty(String name, ImageObserver observer) {
+        if(name == null) {
+            // awt.38=Property name is not defined
+            throw new NullPointerException(Messages.getString("awt.38")); //$NON-NLS-1$
+        }
+        if(properties == null){
+            addObserver(observer);
+            startProduction();
+            if(properties == null) {
+                return null;
+            }
+        }
+        Object prop = properties.get(name);
+        if(prop == null) {
+            prop = UndefinedProperty;
+        }
+        return prop;
+    }
+
+    @Override
+    public ImageProducer getSource() {
+        return src;
+    }
+
+    @Override
+    public int getWidth(ImageObserver observer) {
+        if((imageState & ImageObserver.WIDTH) == 0){
+            addObserver(observer);
+            startProduction();
+            if((imageState & ImageObserver.WIDTH) == 0) {
+                return -1;
+            }
+        }
+        return width;
+    }
+
+    @Override
+    public int getHeight(ImageObserver observer) {
+        if((imageState & ImageObserver.HEIGHT) == 0){
+            addObserver(observer);
+            startProduction();
+            if((imageState & ImageObserver.HEIGHT) == 0) {
+                return -1;
+            }
+        }
+        return height;
+    }
+
+    @Override
+    public Graphics getGraphics() {
+        // awt.39=This method is not implemented for image obtained from ImageProducer
+        throw new UnsupportedOperationException(Messages.getString("awt.39")); //$NON-NLS-1$
+    }
+
+    @Override
+    public void flush() {
+        stopProduction();
+        imageUpdate(this, ImageObserver.ABORT, -1, -1, -1, -1);
+        imageState &= ~ImageObserver.ERROR;
+        imageState = 0;
+        image = null;
+        cm = null;
+        raster = null;
+        hints = 0;
+        width = -1;
+        height = -1;
+    }
+
+    public void setProperties(Hashtable<?, ?> properties) {
+        this.properties = properties;
+        imageUpdate(this, ImageObserver.PROPERTIES, 0, 0, width, height);
+    }
+
+    public void setColorModel(ColorModel cm) {
+        this.cm = cm;
+    }
+
+    /*
+     * We suppose what in case loading JPEG image then image has DirectColorModel
+     * and for infill image Raster will use setPixels method with int array.
+     *
+     * In case loading GIF image, for raster infill, is used setPixels method with
+     * byte array and Color Model is IndexColorModel. But Color Model may
+     * be changed during this process. Then is called setPixels method with
+     * int array and image force to default color model - int ARGB. The rest
+     * pixels are sending in DirectColorModel.
+     */
+    public void setPixels(int x, int y, int w, int h, ColorModel model,
+            int[] pixels, int off, int scansize) {
+        if(raster == null){
+            if(cm == null){
+                if(model == null) {
+                    // awt.3A=Color Model is null
+                    throw new NullPointerException(Messages.getString("awt.3A")); //$NON-NLS-1$
+                }
+                cm = model;
+            }
+            createRaster();
+        }
+
+        if(model == null) {
+            model = cm;
+        }
+        if(cm != model){
+            forceToIntARGB();
+        }
+
+        if(cm == model && model.getTransferType() == DataBuffer.TYPE_INT &&
+                raster.getNumDataElements() == 1){
+
+            DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
+            int data[] = dbi.getData();
+            int scanline = raster.getWidth();
+            int rof = dbi.getOffset() + y * scanline + x;
+            for(int lineOff = off, line = y; line < y + h;
+                line++, lineOff += scansize, rof += scanline){
+
+                System.arraycopy(pixels, lineOff, data, rof, w);
+            }
+
+        }else if(isIntRGB){
+            int buff[] = new int[w];
+            DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
+            int data[] = dbi.getData();
+            int scanline = raster.getWidth();
+            int rof = dbi.getOffset() + y * scanline + x;
+            for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize,
+                rof += scanline) {
+
+                for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+                    buff[idx] = model.getRGB(pixels[sOff + idx]);
+                }
+                System.arraycopy(buff, 0, data, rof, w);
+            }
+        }else{
+            Object buf = null;
+            for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) {
+                for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+                    int rgb = model.getRGB(pixels[sOff + idx]);
+                    buf = cm.getDataElements(rgb, buf);
+                    raster.setDataElements(sx, sy, buf);
+                }
+            }
+        }
+
+        if (imageSurf != null) {
+            imageSurf.invalidate();
+        }
+
+        imageUpdate(this, ImageObserver.SOMEBITS, 0, 0, width, height);
+    }
+
+    public void setPixels(int x, int y, int w, int h, ColorModel model,
+            byte[] pixels, int off, int scansize) {
+
+        if(raster == null){
+            if(cm == null){
+                if(model == null) {
+                    // awt.3A=Color Model is null
+                    throw new NullPointerException(Messages.getString("awt.3A")); //$NON-NLS-1$
+                }
+                cm = model;
+            }
+            createRaster();
+        }
+        if(model == null) {
+            model = cm;
+        }
+        if(model != cm){
+            forceToIntARGB();
+        }
+
+        if(isIntRGB){
+            int buff[] = new int[w];
+            IndexColorModel icm = (IndexColorModel) model;
+            int colorMap[] = new int[icm.getMapSize()];
+            icm.getRGBs(colorMap);
+            DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
+            int data[] = dbi.getData();
+            int scanline = raster.getWidth();
+            int rof = dbi.getOffset() + y * scanline + x;
+            if(model instanceof IndexColorModel){
+
+                for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize,
+                    rof += scanline) {
+                    for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+                        buff[idx] = colorMap[pixels[sOff + idx] & 0xff];
+                    }
+                    System.arraycopy(buff, 0, data, rof, w);
+                }
+            }else{
+
+                for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize,
+                    rof += scanline) {
+                    for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+                        buff[idx] = model.getRGB(pixels[sOff + idx] & 0xff);
+                    }
+                    System.arraycopy(buff, 0, data, rof, w);
+                }
+            }
+        }else if(model == cm && model.getTransferType() == DataBuffer.TYPE_BYTE &&
+                raster.getNumDataElements() == 1){
+
+            DataBufferByte dbb = (DataBufferByte)raster.getDataBuffer();
+            byte data[] = dbb.getData();
+            int scanline = raster.getWidth();
+            int rof = dbb.getOffset() + y * scanline + x;
+            for(int lineOff = off, line = y; line < y + h;
+                line++, lineOff += scansize, rof += scanline){
+                System.arraycopy(pixels, lineOff, data, rof, w);
+            }
+        // BEGIN android-added (taken from newer Harmony)
+        }else if(model == cm && model.getTransferType() == DataBuffer.TYPE_BYTE &&
+                cm instanceof ComponentColorModel){
+
+            int nc = cm.getNumComponents();
+            byte stride[] = new byte[scansize];
+            for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) {
+                System.arraycopy(pixels, sOff, stride, 0, scansize);
+                
+                raster.setDataElements(x, sy, w, 1, stride);
+            }
+        // END android-added
+        }else {
+            for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) {
+                for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+                    int rgb = model.getRGB(pixels[sOff + idx] & 0xff);
+                    raster.setDataElements(sx, sy, cm.getDataElements(rgb, null));
+                }
+            }
+        }
+
+        if (imageSurf != null) {
+            imageSurf.invalidate();
+        }
+
+        imageUpdate(this, ImageObserver.SOMEBITS, 0, 0, width, height);
+    }
+
+    public void setDimensions(int width, int height) {
+        if(width <= 0 || height <= 0){
+            imageComplete(ImageObserver.ERROR);
+            return;
+        }
+
+        this.width = width;
+        this.height = height;
+        imageUpdate(this, (ImageObserver.HEIGHT | ImageObserver.WIDTH),
+                0, 0, width, height);
+    }
+
+    public void setHints(int hints) {
+        this.hints = hints;
+    }
+
+    public void imageComplete(int state) {
+        int flag;
+        switch(state){
+        case IMAGEABORTED:
+            flag = ImageObserver.ABORT;
+            break;
+        case IMAGEERROR:
+            flag = ImageObserver.ERROR | ImageObserver.ABORT;
+            break;
+        case SINGLEFRAMEDONE:
+            flag = ImageObserver.FRAMEBITS;
+            break;
+        case STATICIMAGEDONE:
+            flag = ImageObserver.ALLBITS;
+            break;
+        default:
+            // awt.3B=Incorrect ImageConsumer completion status
+            throw new IllegalArgumentException(Messages.getString("awt.3B")); //$NON-NLS-1$
+        }
+        imageUpdate(this, flag, 0, 0, width, height);
+
+        if((flag & (ImageObserver.ERROR | ImageObserver.ABORT |
+                ImageObserver.ALLBITS)) != 0 ) {
+            stopProduction();
+            observers.removeAllElements();
+        }
+    }
+
+    public /*synchronized*/ BufferedImage getBufferedImage(){
+        if(image == null){
+            ColorModel model = getColorModel();
+            WritableRaster wr = getRaster();
+            if(model != null && wr != null) {
+                image = new BufferedImage(model, wr, model.isAlphaPremultiplied(), null);
+            }
+        }
+        return image;
+    }
+
+    public /*synchronized*/ int checkImage(ImageObserver observer){
+        addObserver(observer);
+        return imageState;
+    }
+
+    public /*synchronized*/ boolean prepareImage(ImageObserver observer){
+        if((imageState & ImageObserver.ERROR) != 0){
+            if(observer != null){
+                observer.imageUpdate(this, ImageObserver.ERROR |
+                        ImageObserver.ABORT, -1, -1, -1, -1);
+            }
+            return false;
+        }
+        if((imageState & ImageObserver.ALLBITS) != 0) {
+            return true;
+        }
+        addObserver(observer);
+        startProduction();
+        return ((imageState & ImageObserver.ALLBITS) != 0);
+    }
+
+    public /*synchronized*/ ColorModel getColorModel(){
+        if(cm == null) {
+            startProduction();
+        }
+        return cm;
+    }
+
+    public /*synchronized*/ WritableRaster getRaster(){
+        if(raster == null) {
+            startProduction();
+        }
+        return raster;
+    }
+
+    public int getState(){
+        return imageState;
+    }
+
+    private /*synchronized*/ void addObserver(ImageObserver observer){
+        if(observer != null){
+          if(observers.contains(observer)) {
+            return;
+        }
+          if((imageState & ImageObserver.ERROR) != 0){
+              observer.imageUpdate(this, ImageObserver.ERROR |
+                      ImageObserver.ABORT, -1, -1, -1, -1);
+              return;
+          }
+          if((imageState & ImageObserver.ALLBITS) != 0){
+              observer.imageUpdate(this, imageState, 0, 0, width, height);
+              return;
+          }
+          observers.addElement(observer);
+        }
+    }
+
+    private synchronized void startProduction(){
+        if(!producing){
+            imageState &= ~ImageObserver.ABORT;
+            producing = true;
+            src.startProduction(this);
+        }
+    }
+
+    private synchronized void stopProduction(){
+        producing = false;
+        src.removeConsumer(this);
+    }
+
+    private void createRaster(){
+        try{
+            raster = cm.createCompatibleWritableRaster(width, height);
+            isIntRGB = false;
+            if(cm instanceof DirectColorModel){
+                DirectColorModel dcm = (DirectColorModel) cm;
+                if(dcm.getTransferType() == DataBuffer.TYPE_INT &&
+                        dcm.getRedMask() == 0xff0000 &&
+                        dcm.getGreenMask() == 0xff00 &&
+                        dcm.getBlueMask() == 0xff){
+                    isIntRGB = true;
+                }
+            }
+        }catch(Exception e){
+            cm = ColorModel.getRGBdefault();
+            raster = cm.createCompatibleWritableRaster(width, height);
+            isIntRGB = true;
+        }
+    }
+
+    private /*synchronized*/ void imageUpdate(Image img, int infoflags, int x, int y,
+            int width, int height){
+
+        imageState |= infoflags;
+        for (ImageObserver observer : observers) {
+            observer.imageUpdate(this, infoflags, x, y, width, height);
+        }
+
+//            notifyAll();
+    }
+
+    private void forceToIntARGB(){
+
+        int w = raster.getWidth();
+        int h = raster.getHeight();
+
+        WritableRaster destRaster = rgbCM.createCompatibleWritableRaster(w, h);
+
+        Object obj = null;
+        int pixels[] = new int[w];
+
+        if(cm instanceof IndexColorModel){
+            IndexColorModel icm = (IndexColorModel) cm;
+            int colorMap[] = new int[icm.getMapSize()];
+            icm.getRGBs(colorMap);
+
+            for (int y = 0; y < h; y++) {
+                obj = raster.getDataElements(0, y, w, 1, obj);
+                byte ba[] = (byte[]) obj;
+                for (int x = 0; x < ba.length; x++) {
+                    pixels[x] = colorMap[ba[x] & 0xff];
+                }
+                destRaster.setDataElements(0, y, w, 1, pixels);
+            }
+
+        }else{
+            for(int y = 0; y < h; y++){
+                for(int x = 0; x < w; x++){
+                    obj = raster.getDataElements(x, y, obj);
+                    pixels[x] = cm.getRGB(obj);
+                }
+                destRaster.setDataElements(0, y, w, 1, pixels);
+            }
+        }
+
+        synchronized(this){
+            if(imageSurf != null){
+                imageSurf.dispose();
+                imageSurf = null;
+            }
+            if(image != null){
+                image.flush();
+                image = null;
+            }
+            cm = rgbCM;
+            raster = destRaster;
+            isIntRGB = true;
+        }
+    }
+
+    public ImageSurface getImageSurface() {
+        if (imageSurf == null) {
+            ColorModel model = getColorModel();
+            WritableRaster wr = getRaster();
+            if(model != null && wr != null) {
+                imageSurf = new ImageSurface(model, wr);
+            }
+        }
+        return imageSurf;
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java b/awt/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java
new file mode 100644
index 0000000..1748e1b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java
@@ -0,0 +1,153 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 30.09.2004
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+
+public class OrdinaryWritableRaster extends WritableRaster {
+
+    public OrdinaryWritableRaster(SampleModel sampleModel,
+            DataBuffer dataBuffer, Rectangle aRegion,
+            Point sampleModelTranslate, WritableRaster parent) {
+        super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent);
+    }
+
+    public OrdinaryWritableRaster(SampleModel sampleModel,
+            DataBuffer dataBuffer, Point origin) {
+        super(sampleModel, dataBuffer, origin);
+    }
+
+    public OrdinaryWritableRaster(SampleModel sampleModel, Point origin) {
+        super(sampleModel, origin);
+    }
+
+    @Override
+    public void setDataElements(int x, int y, Object inData) {
+        super.setDataElements(x, y, inData);
+    }
+
+    @Override
+    public void setDataElements(int x, int y, int w, int h, Object inData) {
+        super.setDataElements(x, y, w, h, inData);
+    }
+
+    @Override
+    public WritableRaster createWritableChild(int parentX, int parentY, int w,
+            int h, int childMinX, int childMinY, int[] bandList) {
+        return super.createWritableChild(parentX, parentY, w, h, childMinX,
+                childMinY, bandList);
+    }
+
+    @Override
+    public WritableRaster createWritableTranslatedChild(int childMinX,
+            int childMinY) {
+        return super.createWritableTranslatedChild(childMinX, childMinY);
+    }
+
+    @Override
+    public WritableRaster getWritableParent() {
+        return super.getWritableParent();
+    }
+
+    @Override
+    public void setRect(Raster srcRaster) {
+        super.setRect(srcRaster);
+    }
+
+    @Override
+    public void setRect(int dx, int dy, Raster srcRaster) {
+        super.setRect(dx, dy, srcRaster);
+    }
+
+    @Override
+    public void setDataElements(int x, int y, Raster inRaster) {
+        super.setDataElements(x, y, inRaster);
+    }
+
+    @Override
+    public void setPixel(int x, int y, int[] iArray) {
+        super.setPixel(x, y, iArray);
+    }
+
+    @Override
+    public void setPixel(int x, int y, float[] fArray) {
+        super.setPixel(x, y, fArray);
+    }
+
+    @Override
+    public void setPixel(int x, int y, double[] dArray) {
+        super.setPixel(x, y, dArray);
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, int[] iArray) {
+        super.setPixels(x, y, w, h, iArray);
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, float[] fArray) {
+        super.setPixels(x, y, w, h, fArray);
+    }
+
+    @Override
+    public void setPixels(int x, int y, int w, int h, double[] dArray) {
+        super.setPixels(x, y, w, h, dArray);
+    }
+
+    @Override
+    public void setSamples(int x, int y, int w, int h, int b, int[] iArray) {
+        super.setSamples(x, y, w, h, b, iArray);
+    }
+
+    @Override
+    public void setSamples(int x, int y, int w, int h, int b, float[] fArray) {
+        super.setSamples(x, y, w, h, b, fArray);
+    }
+
+    @Override
+    public void setSamples(int x, int y, int w, int h, int b, double[] dArray) {
+        super.setSamples(x, y, w, h, b, dArray);
+    }
+
+    @Override
+    public void setSample(int x, int y, int b, int s) {
+        super.setSample(x, y, b, s);
+    }
+
+    @Override
+    public void setSample(int x, int y, int b, float s) {
+        super.setSample(x, y, b, s);
+    }
+
+    @Override
+    public void setSample(int x, int y, int b, double s) {
+        super.setSample(x, y, b, s);
+    }
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/image/PngDecoder.java b/awt/org/apache/harmony/awt/gl/image/PngDecoder.java
new file mode 100644
index 0000000..7e85600
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/PngDecoder.java
@@ -0,0 +1,270 @@
+/*
+ *  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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Jul 22, 2005
+ */
+
+package org.apache.harmony.awt.gl.image;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+import java.awt.color.ColorSpace;
+import java.awt.image.*;
+import java.awt.*;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class PngDecoder extends ImageDecoder {
+    // initializes proper field IDs
+    private static native void initIDs();
+
+    static {
+        System.loadLibrary("gl"); //$NON-NLS-1$
+        initIDs();
+    }
+
+    private static final int hintflags =
+            ImageConsumer.SINGLEFRAME | // PNG is a static image
+            ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible
+            ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines
+
+    // Each pixel is a grayscale sample.
+    private static final int PNG_COLOR_TYPE_GRAY = 0;
+    // Each pixel is an R,G,B triple.
+    private static final int PNG_COLOR_TYPE_RGB = 2;
+    // Each pixel is a palette index, a PLTE chunk must appear.
+    private static final int PNG_COLOR_TYPE_PLTE = 3;
+    // Each pixel is a grayscale sample, followed by an alpha sample.
+    private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4;
+    // Each pixel is an R,G,B triple, followed by an alpha sample.
+    private static final int PNG_COLOR_TYPE_RGBA = 6;
+
+    private static final int INPUT_BUFFER_SIZE = 4096;
+    private byte buffer[] = new byte[INPUT_BUFFER_SIZE];
+
+    // Buffers for decoded image data
+    byte byteOut[];
+    int intOut[];
+
+    // Native pointer to png decoder data
+    private long hNativeDecoder;
+
+    int imageWidth, imageHeight;
+    int colorType;
+    int bitDepth;
+    byte cmap[];
+
+    boolean transferInts; // Is transfer type int?.. or byte?
+    int dataElementsPerPixel = 1;
+
+    ColorModel cm;
+
+    int updateFromScanline; // First scanline to update
+    int numScanlines; // Number of scanlines to update
+
+    private native long decode(byte[] input, int bytesInBuffer, long hDecoder);
+
+    private static native void releaseNativeDecoder(long hDecoder);
+
+    public PngDecoder(DecodingImageSource src, InputStream is) {
+        super(src, is);
+    }
+
+    @Override
+    public void decodeImage() throws IOException {
+        try {
+            int bytesRead = 0;
+            int needBytes, offset, bytesInBuffer = 0;
+            // Read from the input stream
+            for (;;) {
+                needBytes = INPUT_BUFFER_SIZE - bytesInBuffer;
+                offset = bytesInBuffer;
+
+                bytesRead = inputStream.read(buffer, offset, needBytes);
+
+                if (bytesRead < 0) { // Break, nothing to read from buffer, image truncated?
+                    releaseNativeDecoder(hNativeDecoder);
+                    break;
+                }
+
+                // Keep track on how much bytes left in buffer
+                bytesInBuffer += bytesRead;
+                hNativeDecoder = decode(buffer, bytesInBuffer, hNativeDecoder);
+                // PNG decoder always consumes all bytes at once
+                bytesInBuffer = 0;
+
+                // if (bytesConsumed < 0)
+                //break; // Error exit
+
+                returnData();
+
+                // OK, we decoded all the picture in the right way...
+                if (hNativeDecoder == 0) {
+                    break;
+                }
+            }
+
+            imageComplete(ImageConsumer.STATICIMAGEDONE);
+        } catch (IOException e) {
+            throw e;
+        } catch (RuntimeException e) {
+            imageComplete(ImageConsumer.IMAGEERROR);
+            throw e;
+        } finally {
+            closeStream();
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private void returnHeader() { // Called from native code
+        setDimensions(imageWidth, imageHeight);
+
+        switch (colorType) {
+            case PNG_COLOR_TYPE_GRAY: {
+                if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) {
+                    // awt.3C=Unknown PNG color type
+                    throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+                }
+
+                // Create gray color model
+                int numEntries = 1 << bitDepth;
+                int scaleFactor = 255 / (numEntries-1);
+                byte comps[] = new byte[numEntries];
+                for (int i = 0; i < numEntries; i++) {
+                    comps[i] = (byte) (i * scaleFactor);
+                }
+                cm = new IndexColorModel(/*bitDepth*/8, numEntries, comps, comps, comps);
+
+                transferInts = false;
+                break;
+            }
+
+            case PNG_COLOR_TYPE_RGB: {
+                if (bitDepth != 8) {
+                    // awt.3C=Unknown PNG color type
+                    throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+                }
+
+                cm = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF);
+
+                transferInts = true;
+                break;
+            }
+
+            case PNG_COLOR_TYPE_PLTE: {
+                if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) {
+                    // awt.3C=Unknown PNG color type
+                    throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+                }
+
+                cm = new IndexColorModel(/*bitDepth*/8, cmap.length / 3, cmap, 0, false);
+
+                transferInts = false;
+                break;
+            }
+
+            case PNG_COLOR_TYPE_GRAY_ALPHA: {
+                if (bitDepth != 8) {
+                    // awt.3C=Unknown PNG color type
+                    throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+                }
+
+                cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
+                        true, false,
+                        Transparency.TRANSLUCENT,
+                        DataBuffer.TYPE_BYTE);
+
+                transferInts = false;
+                dataElementsPerPixel = 2;
+                break;
+            }
+
+            case PNG_COLOR_TYPE_RGBA: {
+                if (bitDepth != 8) {
+                    // awt.3C=Unknown PNG color type
+                    throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+                }
+
+                cm = ColorModel.getRGBdefault();
+
+                transferInts = true;
+                break;
+            }
+            default:
+                // awt.3C=Unknown PNG color type
+                throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+        }
+
+        // Create output buffer
+        if (transferInts) {
+            intOut = new int[imageWidth * imageHeight];
+        } else {
+            byteOut = new byte[imageWidth * imageHeight * dataElementsPerPixel];
+        }
+
+        setColorModel(cm);
+
+        setHints(hintflags);
+        setProperties(new Hashtable<Object, Object>()); // Empty
+    }
+
+    // Send the data to the consumer
+    private void returnData() {
+        // Send 1 or more scanlines to the consumer.
+        if (numScanlines > 0) {
+            // Native decoder could have returned
+            // some data from the next pass, handle it here
+            int pass1, pass2;
+            if (updateFromScanline + numScanlines > imageHeight) {
+                pass1 = imageHeight - updateFromScanline;
+                pass2 = updateFromScanline + numScanlines - imageHeight;
+            } else {
+                pass1 = numScanlines;
+                pass2 = 0;
+            }
+
+            transfer(updateFromScanline, pass1);
+            if (pass2 != 0) {
+                transfer(0, pass2);
+            }
+        }
+    }
+
+    private void transfer(int updateFromScanline, int numScanlines) {
+        if (transferInts) {
+            setPixels(
+                    0, updateFromScanline,
+                    imageWidth, numScanlines,
+                    cm, intOut,
+                    updateFromScanline * imageWidth,
+                    imageWidth
+            );
+        } else {
+            setPixels(
+                    0, updateFromScanline,
+                    imageWidth, numScanlines,
+                    cm, byteOut,
+                    updateFromScanline * imageWidth * dataElementsPerPixel,
+                    imageWidth * dataElementsPerPixel
+            );
+        }
+    }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/PngDecoderJava.java b/awt/org/apache/harmony/awt/gl/image/PngDecoderJava.java
new file mode 100644
index 0000000..46545f9
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/PngDecoderJava.java
@@ -0,0 +1,282 @@
+package org.apache.harmony.awt.gl.image;
+
+// A simple PNG decoder source code in Java.
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.IndexColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.zip.CRC32;
+import java.util.zip.InflaterInputStream;
+
+//import javax.swing.JFrame;
+
+public class PngDecoderJava {
+ 
+/*
+  public static void main(String[] args) throws Exception {
+    String name = "logo.png";
+    if (args.length > 0)
+      name = args[0];
+    InputStream in = PngDecoderJava.class.getResourceAsStream(name);
+    final BufferedImage image = PngDecoderJava.decode(in);
+    in.close();
+
+    JFrame f = new JFrame() {
+      public void paint(Graphics g) {
+        Insets insets = getInsets();
+        g.drawImage(image, insets.left, insets.top, null);
+      }
+    };
+    f.setVisible(true);
+    Insets insets = f.getInsets();
+    f.setSize(image.getWidth() + insets.left + insets.right, image
+        .getHeight()
+        + insets.top + insets.bottom);
+  }
+  */
+
+  public static BufferedImage decode(InputStream in) throws IOException {
+    DataInputStream dataIn = new DataInputStream(in);
+    readSignature(dataIn);
+    PNGData chunks = readChunks(dataIn);
+
+    long widthLong = chunks.getWidth();
+    long heightLong = chunks.getHeight();
+    if (widthLong > Integer.MAX_VALUE || heightLong > Integer.MAX_VALUE)
+      throw new IOException("That image is too wide or tall.");
+    int width = (int) widthLong;
+    int height = (int) heightLong;
+
+    ColorModel cm = chunks.getColorModel();
+    WritableRaster raster = chunks.getRaster();
+
+    BufferedImage image = new BufferedImage(cm, raster, false, null);
+
+    return image;
+  }
+
+  protected static void readSignature(DataInputStream in) throws IOException {
+    long signature = in.readLong();
+    if (signature != 0x89504e470d0a1a0aL)
+      throw new IOException("PNG signature not found!");
+  }
+
+  protected static PNGData readChunks(DataInputStream in) throws IOException {
+    PNGData chunks = new PNGData();
+
+    boolean trucking = true;
+    while (trucking) {
+      try {
+        // Read the length.
+        int length = in.readInt();
+        if (length < 0)
+          throw new IOException("Sorry, that file is too long.");
+        // Read the type.
+        byte[] typeBytes = new byte[4];
+        in.readFully(typeBytes);
+        // Read the data.
+        byte[] data = new byte[length];
+        in.readFully(data);
+        // Read the CRC.
+        long crc = in.readInt() & 0x00000000ffffffffL; // Make it
+        // unsigned.
+        if (verifyCRC(typeBytes, data, crc) == false)
+          throw new IOException("That file appears to be corrupted.");
+
+        PNGChunk chunk = new PNGChunk(typeBytes, data);
+        chunks.add(chunk);
+      } catch (EOFException eofe) {
+        trucking = false;
+      }
+    }
+    return chunks;
+  }
+
+  protected static boolean verifyCRC(byte[] typeBytes, byte[] data, long crc) {
+    CRC32 crc32 = new CRC32();
+    crc32.update(typeBytes);
+    crc32.update(data);
+    long calculated = crc32.getValue();
+    return (calculated == crc);
+  }
+}
+
+class PNGData {
+  private int mNumberOfChunks;
+
+  private PNGChunk[] mChunks;
+
+  public PNGData() {
+    mNumberOfChunks = 0;
+    mChunks = new PNGChunk[10];
+  }
+
+  public void add(PNGChunk chunk) {
+    mChunks[mNumberOfChunks++] = chunk;
+    if (mNumberOfChunks >= mChunks.length) {
+      PNGChunk[] largerArray = new PNGChunk[mChunks.length + 10];
+      System.arraycopy(mChunks, 0, largerArray, 0, mChunks.length);
+      mChunks = largerArray;
+    }
+  }
+
+  public long getWidth() {
+    return getChunk("IHDR").getUnsignedInt(0);
+  }
+
+  public long getHeight() {    return getChunk("IHDR").getUnsignedInt(4);
+  }
+
+  public short getBitsPerPixel() {
+    return getChunk("IHDR").getUnsignedByte(8);
+  }
+
+  public short getColorType() {
+    return getChunk("IHDR").getUnsignedByte(9);
+  }
+
+  public short getCompression() {
+    return getChunk("IHDR").getUnsignedByte(10);
+  }
+
+  public short getFilter() {
+    return getChunk("IHDR").getUnsignedByte(11);
+  }
+
+  public short getInterlace() {
+    return getChunk("IHDR").getUnsignedByte(12);
+  }
+
+  public ColorModel getColorModel() {
+    short colorType = getColorType();
+    int bitsPerPixel = getBitsPerPixel();
+
+    if (colorType == 3) {
+      byte[] paletteData = getChunk("PLTE").getData();
+      int paletteLength = paletteData.length / 3;
+      return new IndexColorModel(bitsPerPixel, paletteLength,
+          paletteData, 0, false);
+    }
+    System.out.println("Unsupported color type: " + colorType);
+    return null;
+  }
+
+  public WritableRaster getRaster() {
+    int width = (int) getWidth();
+    int height = (int) getHeight();
+    int bitsPerPixel = getBitsPerPixel();
+    short colorType = getColorType();
+
+    if (colorType == 3) {
+      byte[] imageData = getImageData();
+      //Orig: DataBuffer db = new DataBufferByte(imageData, imageData.length);
+      int len = Math.max(imageData.length, (width - 1) * (height -1));
+      DataBuffer db = new DataBufferByte(imageData, len);
+      WritableRaster raster = Raster.createPackedRaster(db, width,
+          height, bitsPerPixel, null);
+      return raster;
+    } else
+      System.out.println("Unsupported color type!");
+    return null;
+  }
+
+  public byte[] getImageData() {
+    try {
+      ByteArrayOutputStream out = new ByteArrayOutputStream();
+      // Write all the IDAT data into the array.
+      for (int i = 0; i < mNumberOfChunks; i++) {
+        PNGChunk chunk = mChunks[i];
+        if (chunk.getTypeString().equals("IDAT")) {
+          out.write(chunk.getData());
+        }
+      }
+      out.flush();
+      // Now deflate the data.
+      InflaterInputStream in = new InflaterInputStream(
+          new ByteArrayInputStream(out.toByteArray()));
+      ByteArrayOutputStream inflatedOut = new ByteArrayOutputStream();
+      int readLength;
+      byte[] block = new byte[8192];
+      while ((readLength = in.read(block)) != -1)
+        inflatedOut.write(block, 0, readLength);
+      inflatedOut.flush();
+      byte[] imageData = inflatedOut.toByteArray();
+      // Compute the real length.
+      int width = (int) getWidth();
+      int height = (int) getHeight();
+      int bitsPerPixel = getBitsPerPixel();
+      int length = width * height * bitsPerPixel / 8;
+
+      byte[] prunedData = new byte[length];
+
+      // We can only deal with non-interlaced images.
+      if (getInterlace() == 0) {
+        int index = 0;
+        for (int i = 0; i < length; i++) {
+          if ((i * 8 / bitsPerPixel) % width == 0) {
+            index++; // Skip the filter byte.
+          }
+          prunedData[i] = imageData[index++];
+        }
+      } else
+        System.out.println("Couldn't undo interlacing.");
+
+      return prunedData;
+    } catch (IOException ioe) {
+    }
+    return null;
+  }
+
+  public PNGChunk getChunk(String type) {
+    for (int i = 0; i < mNumberOfChunks; i++)
+      if (mChunks[i].getTypeString().equals(type))
+        return mChunks[i];
+    return null;
+  }
+}
+
+class PNGChunk {
+  private byte[] mType;
+
+  private byte[] mData;
+
+  public PNGChunk(byte[] type, byte[] data) {
+    mType = type;
+    mData = data;
+  }
+
+  public String getTypeString() {
+    try {
+      return new String(mType, "UTF8");
+    } catch (UnsupportedEncodingException uee) {
+      return "";
+    }
+  }
+
+  public byte[] getData() {
+    return mData;
+  }
+
+  public long getUnsignedInt(int offset) {
+    long value = 0;
+    for (int i = 0; i < 4; i++)
+      value += (mData[offset + i] & 0xff) << ((3 - i) * 8);
+    return value;
+  }
+
+  public short getUnsignedByte(int offset) {
+    return (short) (mData[offset] & 0x00ff);
+  }
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java b/awt/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java
new file mode 100644
index 0000000..a1899d6
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java
@@ -0,0 +1,77 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 10.02.2005
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.Permission;
+
+public class URLDecodingImageSource extends DecodingImageSource {
+
+    URL url;
+
+    public URLDecodingImageSource(URL url){
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkConnect(url.getHost(), url.getPort());
+            try {
+                Permission p = url.openConnection().getPermission();
+                security.checkPermission(p);
+            } catch (IOException e) {
+            }
+        }
+        this.url = url;
+    }
+
+    @Override
+    protected boolean checkConnection() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            try {
+                security.checkConnect(url.getHost(), url.getPort());
+                return true;
+            } catch (SecurityException e) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    protected InputStream getInputStream() {
+        try{
+            URLConnection uc = url.openConnection();
+            // BEGIN android-modified
+            return new BufferedInputStream(uc.getInputStream(), 8192);
+            // END android-modified
+        }catch(IOException e){
+            return null;
+        }
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/Blitter.java b/awt/org/apache/harmony/awt/gl/render/Blitter.java
new file mode 100644
index 0000000..3b8012e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/Blitter.java
@@ -0,0 +1,53 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 14.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.geom.AffineTransform;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+
+/**
+ * The interface for objects which can drawing Images on other Images which have 
+ * Graphics or on the display.  
+ */
+public interface Blitter {
+
+    public abstract void blit(int srcX, int srcY, Surface srcSurf,
+            int dstX, int dstY, Surface dstSurf, int width, int height,
+            AffineTransform sysxform, AffineTransform xform,
+            Composite comp, Color bgcolor,
+            MultiRectArea clip);
+
+    public abstract void blit(int srcX, int srcY, Surface srcSurf,
+            int dstX, int dstY, Surface dstSurf, int width, int height,
+            AffineTransform sysxform, Composite comp, Color bgcolor,
+            MultiRectArea clip);
+
+    public abstract void blit(int srcX, int srcY, Surface srcSurf,
+            int dstX, int dstY, Surface dstSurf, int width, int height,
+            Composite comp, Color bgcolor, MultiRectArea clip);
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java b/awt/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java
new file mode 100644
index 0000000..b643b41
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java
@@ -0,0 +1,502 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.render;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+
+public class JavaArcRasterizer {
+
+    /**
+     * Adds particular arc segment to mra 
+     */
+    static void addX0LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+        int x1 = 0;
+        for(int i = 0; i < line.length; i++) {
+            int x2 = line[i];
+            int y = cy + (b - i);
+            if (x1 <= finish && x2 >= start) {
+                mra.addRect(cx + Math.max(x1, start), y, cx + Math.min(x2, finish), y);
+            }
+            x1 = x2 + 1;
+        }
+    }
+
+    static void addX1LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+        int x1 = 0;
+        for(int i = 0; i < line.length; i++) {
+            int x2 = line[i];
+            int y = cy - (b - i);
+            if (x1 <= finish && x2 >= start) {
+                mra.addRect(cx + Math.max(x1, start), y, cx + Math.min(x2, finish), y);
+            }
+            x1 = x2 + 1;
+        }
+    }
+
+    static void addX2LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+        int x1 = 0;
+        for(int i = 0; i < line.length; i++) {
+            int x2 = line[i];
+            int y = cy - (b - i);
+            if (x1 <= finish && x2 >= start) {
+                mra.addRect(cx - Math.min(x2, finish), y, cx - Math.max(x1, start), y);
+            }
+            x1 = x2 + 1;
+        }
+    }
+
+    static void addX3LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+        int x1 = 0;
+        for(int i = 0; i < line.length; i++) {
+            int x2 = line[i];
+            int y = cy + (b - i);
+            if (x1 <= finish && x2 >= start) {
+                mra.addRect(cx - Math.min(x2, finish), y, cx - Math.max(x1, start), y);
+            }
+            x1 = x2 + 1;
+        }
+    }
+
+    static void addY0LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+        int y1 = 0;
+        for(int i = 0; i < line.length; i++) {
+            int x = cx + (b - i);
+            int y2 = line[i];
+            if (y1 <= finish && y2 >= start) {
+                mra.addRect(x, cy + Math.max(y1, start), x, cy + Math.min(y2, finish));
+            }
+            y1 = y2 + 1;
+        }
+    }
+
+    static void addY1LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+        int y1 = 0;
+        for(int i = 0; i < line.length; i++) {
+            int x = cx - (b - i);
+            int y2 = line[i];
+            if (y1 <= finish && y2 >= start) {
+                mra.addRect(x, cy + Math.max(y1, start), x, cy + Math.min(y2, finish));
+            }
+            y1 = y2 + 1;
+        }
+    }
+
+    static void addY2LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+        int y1 = 0;
+        for(int i = 0; i < line.length; i++) {
+            int x = cx - (b - i);
+            int y2 = line[i];
+            if (y1 <= finish && y2 >= start) {
+                mra.addRect(x, cy - Math.min(y2, finish), x, cy - Math.max(y1, start));
+            }
+            y1 = y2 + 1;
+        }
+    }
+
+    static void addY3LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+        int y1 = 0;
+        for(int i = 0; i < line.length; i++) {
+            int x = cx + (b - i);
+            int y2 = line[i];
+            if (y1 <= finish && y2 >= start) {
+                mra.addRect(x, cy - Math.min(y2, finish), x, cy - Math.max(y1, start));
+            }
+            y1 = y2 + 1;
+        }
+    }
+
+    static void addX0Line(MultiRectArea mra, int[] line, int cx, int cy, int b) {
+        int prev = 0;
+        for(int i = 0; i < line.length; i++) {
+            mra.addRect(cx + prev, cy + (b - i), cx + line[i], cy + (b - i));
+            prev = line[i] + 1;
+        }
+    }
+
+    static void addX1Line(MultiRectArea mra, int[] line, int cx, int cy, int b) {
+        int prev = 0;
+        for(int i = 0; i < line.length; i++) {
+            mra.addRect(cx + prev, cy - (b - i), cx + line[i], cy - (b - i));
+            prev = line[i] + 1;
+        }
+    }
+
+    static void addX2Line(MultiRectArea mra, int[] line, int cx, int cy, int b) {
+        int prev = 0;
+        for(int i = 0; i < line.length; i++) {
+            mra.addRect(cx - line[i], cy - (b - i), cx - prev, cy - (b - i));
+            prev = line[i] + 1;
+        }
+    }
+
+    static void addX3Line(MultiRectArea mra, int[] line, int cx, int cy, int b) {
+        int prev = 0;
+        for(int i = 0; i < line.length; i++) {
+            mra.addRect(cx - line[i], cy + (b - i), cx - prev, cy + (b - i));
+            prev = line[i] + 1;
+        }
+    }
+
+    static void addY0Line(MultiRectArea mra, int[] line, int cx, int cy, int a) {
+        int prev = 0;
+        for(int i = 0; i < line.length; i++) {
+            mra.addRect(cx + (a - i), cy + prev, cx + (a - i), cy + line[i]);
+            prev = line[i] + 1;
+        }
+    }
+
+    static void addY1Line(MultiRectArea mra, int[] line, int cx, int cy, int a) {
+        int prev = 0;
+        for(int i = 0; i < line.length; i++) {
+            mra.addRect(cx - (a - i), cy + prev, cx - (a - i), cy + line[i]);
+            prev = line[i] + 1;
+        }
+    }
+
+    static void addY2Line(MultiRectArea mra, int[] line, int cx, int cy, int a) {
+        int prev = 0;
+        for(int i = 0; i < line.length; i++) {
+            mra.addRect(cx - (a - i), cy - line[i], cx - (a - i), cy - prev);
+            prev = line[i] + 1;
+        }
+    }
+
+    static void addY3Line(MultiRectArea mra, int[] line, int cx, int cy, int a) {
+        int prev = 0;
+        for(int i = 0; i < line.length; i++) {
+            mra.addRect(cx + (a - i), cy - line[i], cx + (a - i), cy - prev);
+            prev = line[i] + 1;
+        }
+    }
+
+    /**
+     * Returns normalized angle (from 0 to 360 degrees)
+     */
+    static double getNormAngle(double angle) {
+        angle -= Math.floor(angle / 360) * 360;
+        if (angle < 0) {
+            angle += 360;
+        }
+        return angle;
+    }
+
+    /**
+     * Creates arc lookup table
+     */
+    static int[] createLine(int a, int b, int xcount, int ycount) {
+        int[] buf = new int[b - ycount + 1];
+        int d = a * a + 2 * b * b - 2 * a * a * b;
+        int x = 0;
+        int y = b;
+        while (y >= ycount) {
+            if (d < 0) {
+                d = d + b * b * (4 * x + 6);
+            } else {
+                buf[b - y] = x;
+                d = d + b * b * (4 * x + 6) + 4 * a * a * (1 - y);
+                y--;
+            }
+            x++;
+        }
+        return buf;
+    }
+
+    /**
+     * Adds head/tail arc segment to MultiRectArea
+     */
+    static void addSeg(MultiRectArea mra, int cx1, int cy1, int cx2, int cy2, int a, int b, int[] xline, int[] yline, int[] bounds) {
+        switch(bounds[0]) {
+        case 0:
+            addY3LineSeg(mra, yline, cx2, cy1, a, bounds[1], bounds[2]);
+            break;
+        case 1:
+            addX1LineSeg(mra, xline, cx2, cy1, b, bounds[1], bounds[2]);
+            break;
+        case 2:
+            addX2LineSeg(mra, xline, cx1, cy1, b, bounds[1], bounds[2]);
+            break;
+        case 3:
+            addY2LineSeg(mra, yline, cx1, cy1, a, bounds[1], bounds[2]);
+            break;
+        case 4:
+            addY1LineSeg(mra, yline, cx1, cy2, a, bounds[1], bounds[2]);
+            break;
+        case 5:
+            addX3LineSeg(mra, xline, cx1, cy2, b, bounds[1], bounds[2]);
+            break;
+        case 6:
+            addX0LineSeg(mra, xline, cx2, cy2, b, bounds[1], bounds[2]);
+            break;
+        case 7:
+            addY0LineSeg(mra, yline, cx2, cy2, a, bounds[1], bounds[2]);
+            break;
+        }
+    }
+
+    /**
+     * Returns bounds for non quadratic arc head
+     */
+    static int[] getSegment1(double angle, int ax, int ay, int xcount, int ycount) {
+        int[] bounds = new int[3];
+        switch((int)(angle / 90)) {
+        case 0:
+            if (xcount <  ax) {
+                bounds[0] = 0; // Y3
+                bounds[1] = -ay;
+                bounds[2] = ycount;
+            } else {
+                bounds[0] = 1; // X1
+                bounds[1] = 0;
+                bounds[2] = ax;
+            }
+            break;
+        case 1:
+            if (xcount > -ax) {
+                bounds[0] = 2; // X2
+                bounds[1] = -ax;
+                bounds[2] = xcount;
+            } else {
+                bounds[0] = 3; // Y2
+                bounds[1] = 0;
+                bounds[2] = -ay;
+            }
+            break;
+        case 2:
+            if (xcount < -ax) {
+                bounds[0] = 4; // Y1
+                bounds[1] = ay;
+                bounds[2] = ycount;
+            } else {
+                bounds[0] = 5; // X3
+                bounds[1] = 0;
+                bounds[2] = -ax;
+            }
+            break;
+        case 3:
+            if (xcount >  ax) {
+                bounds[0] = 6; // X0
+                bounds[1] = ax;
+                bounds[2] = xcount;
+            } else {
+                bounds[0] = 7; // Y0
+                bounds[1] = 0;
+                bounds[2] = ay;
+            }
+            break;
+        }
+        return bounds;
+    }
+
+    /**
+     * Returns bounds for non quadratic arc tail
+     */
+    static int[] getSegment2(double angle, int ax, int ay, int xcount, int ycount) {
+        int[] bounds = new int[3];
+        switch((int)(angle / 90)) {
+        case 0:
+            if (xcount <  ax) {
+                bounds[0] = 0; // Y3
+                bounds[1] = 0;
+                bounds[2] = -ay;
+            } else {
+                bounds[0] = 1; // X1
+                bounds[1] = ax;
+                bounds[2] = xcount;
+            }
+            break;
+        case 1:
+            if (xcount > -ax) {
+                bounds[0] = 2; // X2
+                bounds[1] = 0;
+                bounds[2] = -ax;
+            } else {
+                bounds[0] = 3; // Y2
+                bounds[1] = -ay;
+                bounds[2] = ycount;
+            }
+            break;
+        case 2:
+            if (xcount < -ax) {
+                bounds[0] = 4; // Y1
+                bounds[1] = 0;
+                bounds[2] = ay;
+            } else {
+                bounds[0] = 5; // X3
+                bounds[1] = -ax;
+                bounds[2] = xcount;
+            }
+            break;
+        case 3:
+            if (xcount >  ax) {
+                bounds[0] = 6; // X0
+                bounds[1] = 0;
+                bounds[2] = ax;
+            } else {
+                bounds[0] = 7; // Y0
+                bounds[1] = ay;
+                bounds[2] = ycount;
+            }
+            break;
+        }
+        return bounds;
+    }
+
+    /**
+     * Rasterizes arc using clippind and dashing style
+     * @param x1 - the x coordinate of the left-upper corner of the arc bounds
+     * @param y1 - the y coordinate of the left-upper corner of the arc bounds
+     * @param width - the width of the arc bounds
+     * @param height - the height of the arc bounds
+     * @param angleStart - the start angle of the arc in degrees
+     * @param angleExtent - the angle extent in degrees
+     * @param clip - the MultiRectArea object of clipping area
+     * @return a MultiRectArea of rasterizer arc
+     */
+    public static MultiRectArea rasterize(int x, int y, int width, int height, double angleStart, double angleExtent, MultiRectArea clip) {
+
+        MultiRectArea mra = new MultiRectArea(false);
+
+        int cx1, cx2, cy1, cy2;
+        cx1 = cx2 = x + width / 2;
+        cy1 = cy2 = y + height / 2;
+
+        if (width % 2 == 0) {
+            cx2--;
+        }
+
+        if (height % 2 == 0) {
+            cy2--;
+        }
+
+        int a = width / 2;
+        int b = height / 2;
+        double c = Math.sqrt(a * a + b * b);
+
+        int xcount, ycount;
+        if (a < b) {
+            xcount = (int)Math.ceil(a * a / c);
+            ycount = (int)Math.floor(b * b / c);
+        } else {
+            xcount = (int)Math.floor(a * a / c);
+            ycount = (int)Math.ceil(b * b / c);
+        }
+
+        int[] xline = createLine(a, b, xcount, ycount);
+        int[] yline = createLine(b, a, ycount, xcount);
+
+        // Correct lines
+        int i = xline.length;
+        while(xline[--i] > xcount) {
+            xline[i] = xcount;
+        }
+
+        i = yline.length;
+        while(yline[--i] > ycount) {
+            yline[i] = ycount;
+        }
+
+        if (Math.abs(angleExtent) >= 360) {
+            // Rasterize CIRCLE
+            addX0Line(mra, xline, cx2, cy2, b);
+            addX1Line(mra, xline, cx2, cy1, b);
+            addX2Line(mra, xline, cx1, cy1, b);
+            addX3Line(mra, xline, cx1, cy2, b);
+            addY0Line(mra, yline, cx2, cy2, a);
+            addY1Line(mra, yline, cx1, cy2, a);
+            addY2Line(mra, yline, cx1, cy1, a);
+            addY3Line(mra, yline, cx2, cy1, a);
+        } else {
+            // Rasterize ARC
+            angleStart = getNormAngle(angleStart);
+            double angleFinish = getNormAngle(angleStart + angleExtent);
+
+            if (angleExtent < 0) {
+                double tmp = angleStart;
+                angleStart = angleFinish;
+                angleFinish = tmp;
+            }
+
+            double radStart = -Math.toRadians(angleStart);
+            double radFinish = -Math.toRadians(angleFinish);
+            int ax1 = (int)(a * Math.cos(radStart));
+            int ay1 = (int)(b * Math.sin(radStart));
+            int ax2 = (int)(a * Math.cos(radFinish));
+            int ay2 = (int)(b * Math.sin(radFinish));
+
+            int[] seg1 = getSegment1(angleStart, ax1, ay1, xcount, ycount);
+            int[] seg2 = getSegment2(angleFinish, ax2, ay2, xcount, ycount);
+
+            // Start and Finish located in the same quater
+            if (angleStart < angleFinish && seg1[0] == seg2[0]) {
+                if (seg1[0] % 2 == 0) {
+                    seg1[2] = seg2[2];
+                } else {
+                    seg1[1] = seg2[1];
+                }
+                addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg1);
+                return mra;
+            }
+
+            addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg1);
+            addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg2);
+
+            int startSeg = (seg1[0] + 1) % 8;
+            int finishSeg = seg2[0];
+
+            while (startSeg != finishSeg) {
+                switch(startSeg) {
+                case 0:
+                    addY3Line(mra, yline, cx2, cy1, a);
+                    break;
+                case 1:
+                    addX1Line(mra, xline, cx2, cy1, b);
+                    break;
+                case 2:
+                    addX2Line(mra, xline, cx1, cy1, b);
+                    break;
+                case 3:
+                    addY2Line(mra, yline, cx1, cy1, a);
+                    break;
+                case 4:
+                    addY1Line(mra, yline, cx1, cy2, a);
+                    break;
+                case 5:
+                    addX3Line(mra, xline, cx1, cy2, b);
+                    break;
+                case 6:
+                    addX0Line(mra, xline, cx2, cy2, b);
+                    break;
+                case 7:
+                    addY0Line(mra, yline, cx2, cy2, a);
+                    break;
+                }
+                startSeg = (startSeg + 1) % 8;
+            }
+        }
+
+        if (clip != null) {
+            mra.intersect(clip);
+        }
+
+        return mra;
+    }
+
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java b/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java
new file mode 100644
index 0000000..67e0a59
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java
@@ -0,0 +1,611 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 18.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.XORComposite;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * Java implenetation of the Blitter interface. Using when we can't 
+ * draw images natively.
+ */
+public class JavaBlitter implements Blitter {
+
+    /**
+     * Instead of multiplication and division we are using values from
+     * Lookup tables.
+     */
+    static byte mulLUT[][]; // Lookup table for multiplication
+    static byte divLUT[][]; // Lookup table for division
+
+    static{
+        mulLUT = new byte[256][256];
+        for(int i = 0; i < 256; i++){
+            for(int j = 0; j < 256; j++){
+                mulLUT[i][j] = (byte)((float)(i * j)/255 + 0.5f);
+            }
+        }
+        divLUT = new byte[256][256];
+        for(int i = 1; i < 256; i++){
+            for(int j = 0; j < i; j++){
+                divLUT[i][j] = (byte)(((float)j / 255) / ((float)i/ 255) * 255 + 0.5f);
+            }
+            for(int j = i; j < 256; j++){
+                divLUT[i][j] = (byte)255;
+            }
+        }
+    }
+
+    final static int AlphaCompositeMode = 1;
+    final static int XORMode = 2;
+
+    final static JavaBlitter inst = new JavaBlitter();
+
+    public static JavaBlitter getInstance(){
+        return inst;
+    }
+
+    public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, AffineTransform sysxform,
+            AffineTransform xform, Composite comp, Color bgcolor,
+            MultiRectArea clip) {
+
+        if(xform == null){
+            blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+                    sysxform, comp, bgcolor, clip);
+        }else{
+            double scaleX = xform.getScaleX();
+            double scaleY = xform.getScaleY();
+            double scaledX = dstX / scaleX;
+            double scaledY = dstY / scaleY;
+            AffineTransform at = new AffineTransform();
+            at.setToTranslation(scaledX, scaledY);
+            xform.concatenate(at);
+            sysxform.concatenate(xform);
+            blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height,
+                    sysxform, comp, bgcolor, clip);
+        }
+
+    }
+
+    public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, AffineTransform sysxform,
+            Composite comp, Color bgcolor, MultiRectArea clip) {
+
+        if(sysxform == null) {
+            sysxform = new AffineTransform();
+        }
+        int type = sysxform.getType();
+        switch(type){
+            case AffineTransform.TYPE_TRANSLATION:
+                dstX += sysxform.getTranslateX();
+                dstY += sysxform.getTranslateY();
+            case AffineTransform.TYPE_IDENTITY:
+                 blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf,
+                        width, height, comp, bgcolor, clip);
+                break;
+            default:
+                int srcW = srcSurf.getWidth();
+                int srcH = srcSurf.getHeight();
+
+                int w = srcX + width < srcW ? width : srcW - srcX;
+                int h = srcY + height < srcH ? height : srcH - srcY;
+
+                ColorModel srcCM = srcSurf.getColorModel();
+                Raster srcR = srcSurf.getRaster().createChild(srcX, srcY,
+                        w, h, 0, 0, null);
+
+                ColorModel dstCM = dstSurf.getColorModel();
+                WritableRaster dstR = dstSurf.getRaster();
+
+                transformedBlit(srcCM, srcR, 0, 0, dstCM, dstR, dstX, dstY, w, h,
+                        sysxform, comp, bgcolor, clip);
+
+        }
+    }
+
+    public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, Composite comp,
+            Color bgcolor, MultiRectArea clip) {
+
+        javaBlt(srcX, srcY, srcSurf.getWidth(), srcSurf.getHeight(),
+                srcSurf.getColorModel(), srcSurf.getRaster(), dstX, dstY,
+                dstSurf.getWidth(), dstSurf.getHeight(),
+                dstSurf.getColorModel(), dstSurf.getRaster(),
+                width, height, comp, bgcolor, clip);
+
+    }
+    public void javaBlt(int srcX, int srcY, int srcW, int srcH,
+            ColorModel srcCM, Raster srcRast, int dstX, int dstY,
+            int dstW, int dstH, ColorModel dstCM, WritableRaster dstRast,
+            int width, int height, Composite comp, Color bgcolor,
+            MultiRectArea clip){
+
+        int srcX2 = srcW - 1;
+        int srcY2 = srcH - 1;
+        int dstX2 = dstW - 1;
+        int dstY2 = dstH - 1;
+
+        if(srcX < 0){
+            width += srcX;
+            srcX = 0;
+        }
+        if(srcY < 0){
+            height += srcY;
+            srcY = 0;
+        }
+
+        if(dstX < 0){
+            width += dstX;
+            srcX -= dstX;
+            dstX = 0;
+        }
+        if(dstY < 0){
+            height += dstY;
+            srcY -= dstY;
+            dstY = 0;
+        }
+
+        if(srcX > srcX2 || srcY > srcY2) {
+            return;
+        }
+        if(dstX > dstX2 || dstY > dstY2) {
+            return;
+        }
+
+        if(srcX + width > srcX2) {
+            width = srcX2 - srcX + 1;
+        }
+        if(srcY + height > srcY2) {
+            height = srcY2 - srcY + 1;
+        }
+        if(dstX + width > dstX2) {
+            width = dstX2 - dstX + 1;
+        }
+        if(dstY + height > dstY2) {
+            height = dstY2 - dstY + 1;
+        }
+
+        if(width <= 0 || height <= 0) {
+            return;
+        }
+
+        int clipRects[];
+        if(clip != null) {
+            clipRects = clip.rect;
+        } else {
+            clipRects = new int[]{5, 0, 0, dstW - 1, dstH - 1};
+        }
+
+        boolean isAlphaComp = false;
+        int rule = 0;
+        float alpha = 0;
+        boolean isXORComp = false;
+        Color xorcolor = null;
+        CompositeContext cont = null;
+
+        if(comp instanceof AlphaComposite){
+            isAlphaComp = true;
+            AlphaComposite ac = (AlphaComposite) comp;
+            rule = ac.getRule();
+            alpha = ac.getAlpha();
+        }else if(comp instanceof XORComposite){
+            isXORComp = true;
+            XORComposite xcomp = (XORComposite) comp;
+            xorcolor = xcomp.getXORColor();
+        }else{
+            cont = comp.createContext(srcCM, dstCM, null);
+        }
+
+        for(int i = 1; i < clipRects[0]; i += 4){
+            int _sx = srcX;
+            int _sy = srcY;
+
+            int _dx = dstX;
+            int _dy = dstY;
+
+            int _w = width;
+            int _h = height;
+
+            int cx = clipRects[i];          // Clipping left top X
+            int cy = clipRects[i + 1];      // Clipping left top Y
+            int cx2 = clipRects[i + 2];     // Clipping right bottom X
+            int cy2 = clipRects[i + 3];     // Clipping right bottom Y
+
+            if(_dx > cx2 || _dy > cy2 || dstX2 < cx || dstY2 < cy) {
+                continue;
+            }
+
+            if(cx > _dx){
+                int shx = cx - _dx;
+                _w -= shx;
+                _dx = cx;
+                _sx += shx;
+            }
+
+            if(cy > _dy){
+                int shy = cy - _dy;
+                _h -= shy;
+                _dy = cy;
+                _sy += shy;
+            }
+
+            if(_dx + _w > cx2 + 1){
+                _w = cx2 - _dx + 1;
+            }
+
+            if(_dy + _h > cy2 + 1){
+                _h = cy2 - _dy + 1;
+            }
+
+            if(_sx > srcX2 || _sy > srcY2) {
+                continue;
+            }
+
+            if(isAlphaComp){
+                alphaCompose(_sx, _sy, srcCM, srcRast, _dx, _dy,
+                        dstCM, dstRast, _w, _h, rule, alpha, bgcolor);
+            }else if(isXORComp){
+                xorCompose(_sx, _sy, srcCM, srcRast, _dx, _dy,
+                        dstCM, dstRast, _w, _h, xorcolor);
+            }else{
+                Raster sr = srcRast.createChild(_sx, _sy, _w, _h, 0, 0, null);
+                WritableRaster dr = dstRast.createWritableChild(_dx, _dy,
+                        _w, _h, 0, 0, null);
+                cont.compose(sr, dr, dr);
+            }
+        }
+    }
+
+    void alphaCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast,
+            int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast,
+            int width, int height, int rule, float alpha, Color bgcolor){
+
+        Object srcPixel, dstPixel;
+        int srcConstAllpha = (int)(alpha * 255 + 0.5f);
+        int srcRGB, dstRGB = 0;
+
+        if(bgcolor != null){
+            dstRGB = bgcolor.getRGB();
+        }
+
+        for(int sy = srcY, dy = dstY, srcYMax = srcY + height; sy < srcYMax; sy++, dy++){
+            for(int sx = srcX, dx = dstX, srcXMax = srcX + width; sx < srcXMax; sx++, dx++){
+                srcPixel = srcRast.getDataElements(sx, sy, null);
+                srcRGB = srcCM.getRGB(srcPixel);
+                if(bgcolor == null){
+                    dstPixel = dstRast.getDataElements(dx, dy, null);
+                    dstRGB = dstCM.getRGB(dstPixel);
+                }
+
+                dstRGB = compose(srcRGB, srcCM.isAlphaPremultiplied(),
+                        dstRGB, dstCM.hasAlpha(), dstCM.isAlphaPremultiplied(),
+                        rule, srcConstAllpha);
+
+                dstPixel = dstCM.getDataElements(dstRGB, null);
+                dstRast.setDataElements(dx,dy,dstPixel);
+            }
+        }
+    }
+
+    void xorCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast,
+            int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast,
+            int width, int height, Color xorcolor){
+
+        Object srcPixel, dstPixel;
+        int xorRGB = xorcolor.getRGB();
+        int srcRGB, dstRGB;
+
+        for(int sy = srcY, dy = dstY, srcYMax = srcY + height; sy < srcYMax; sy++, dy++){
+            for(int sx = srcX, dx = dstX, srcXMax = srcX + width; sx < srcXMax; sx++, dx++){
+                srcPixel = srcRast.getDataElements(sx, sy, null);
+                dstPixel = dstRast.getDataElements(dx, dy, null);
+
+                srcRGB = srcCM.getRGB(srcPixel);
+                dstRGB = dstCM.getRGB(dstPixel);
+                dstRGB = srcRGB ^ xorRGB ^ dstRGB;
+
+                dstRGB = 0xff000000 | dstRGB;
+                dstPixel = dstCM.getDataElements(dstRGB, dstPixel);
+                dstRast.setDataElements(dx,dy,dstPixel);
+
+            }
+        }
+
+    }
+
+    private void transformedBlit(ColorModel srcCM, Raster srcR, int srcX, int srcY,
+            ColorModel dstCM, WritableRaster dstR, int dstX, int dstY,
+            int width, int height, AffineTransform at, Composite comp,
+            Color bgcolor,MultiRectArea clip) {
+
+        Rectangle srcBounds = new Rectangle(width, height);
+        Rectangle dstBlitBounds = new Rectangle(dstX, dstY, srcR.getWidth(), srcR.getHeight());
+
+        Rectangle transSrcBounds = getBounds2D(at, srcBounds).getBounds();
+        Rectangle transDstBlitBounds = getBounds2D(at, dstBlitBounds).getBounds();
+
+        int translateX = transDstBlitBounds.x - transSrcBounds.x;
+        int translateY = transDstBlitBounds.y - transSrcBounds.y;
+
+        AffineTransform inv = null;
+        try {
+             inv = at.createInverse();
+        } catch (NoninvertibleTransformException e) {
+            return;
+        }
+
+        double[] m = new double[6];
+        inv.getMatrix(m);
+
+        int clipRects[];
+        if(clip != null) {
+            clipRects = clip.rect;
+        } else {
+            clipRects = new int[]{5, 0, 0, dstR.getWidth(), dstR.getHeight()};
+        }
+
+        int compType = 0;
+        int srcConstAlpha = 0;
+        int rule = 0;
+        int bgRGB = bgcolor == null ? 0 : bgcolor.getRGB();
+        int srcRGB = 0, dstRGB = 0;
+        Object srcVal = null, dstVal = null;
+        if(comp instanceof AlphaComposite){
+            compType = AlphaCompositeMode;
+            AlphaComposite ac = (AlphaComposite) comp;
+            rule = ac.getRule();
+            srcConstAlpha = (int)(ac.getAlpha() * 255 + 0.5f);
+        }else if(comp instanceof XORComposite){
+            compType = XORMode;
+            XORComposite xor = (XORComposite) comp;
+            bgRGB = xor.getXORColor().getRGB();
+        }
+
+        for(int i = 1; i < clipRects[0]; i += 4){
+            Rectangle dstBounds = new Rectangle(clipRects[i], clipRects[i + 1], 0, 0);
+            dstBounds.add(clipRects[i + 2] + 1, clipRects[i + 1]);
+            dstBounds.add(clipRects[i + 2] + 1, clipRects[i + 3] + 1);
+            dstBounds.add(clipRects[i], clipRects[i + 3] + 1);
+
+            Rectangle bounds = dstBounds.intersection(transDstBlitBounds);
+
+            int minSrcX = srcBounds.x;
+            int minSrcY = srcBounds.y;
+            int maxSrcX = minSrcX + srcBounds.width;
+            int maxSrcY = minSrcY + srcBounds.height;
+
+            int minX = bounds.x;
+            int minY = bounds.y;
+            int maxX = minX + bounds.width;
+            int maxY = minY + bounds.height;
+
+            int hx = (int)((m[0] * 256) + 0.5);
+            int hy = (int)((m[1] * 256) + 0.5);
+            int vx = (int)((m[2] * 256) + 0.5);
+            int vy = (int)((m[3] * 256) + 0.5);
+            int sx = (int)((m[4] + m[0] * (bounds.x - translateX) + m[2] * (bounds.y - translateY)) * 256 + 0.5);
+            int sy = (int)((m[5] + m[1] * (bounds.x - translateX) + m[3] * (bounds.y - translateY)) * 256 + 0.5);
+
+            vx -= hx * bounds.width;
+            vy -= hy * bounds.width;
+
+            for(int y = minY; y < maxY; y++) {
+                for(int x = minX; x < maxX; x++) {
+                    int px = sx >> 8;
+                    int py = sy >> 8;
+                    if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) {
+                        switch(compType){
+                            case AlphaCompositeMode:
+                                srcVal = srcR.getDataElements(px , py , null);
+                                srcRGB = srcCM.getRGB(srcVal);
+                                if(bgcolor != null){
+                                    dstRGB = bgRGB;
+                                }else{
+                                    dstVal = dstR.getDataElements(x, y, null);
+                                    dstRGB = dstCM.getRGB(dstVal);
+                                }
+                                dstRGB = compose(srcRGB, srcCM.isAlphaPremultiplied(),
+                                        dstRGB, dstCM.hasAlpha(), dstCM.isAlphaPremultiplied(),
+                                        rule, srcConstAlpha);
+                                dstVal = dstCM.getDataElements(dstRGB, null);
+                                dstR.setDataElements(x, y, dstVal);
+                                break;
+
+                            case XORMode:
+                                srcVal = srcR.getDataElements(px , py , null);
+                                srcRGB = srcCM.getRGB(srcVal);
+                                dstVal = dstR.getDataElements(x, y, null);
+                                dstRGB = dstCM.getRGB(dstVal);
+                                dstRGB = srcRGB ^ bgRGB;
+
+                                dstRGB = 0xff000000 | dstRGB;
+                                dstVal = dstCM.getDataElements(dstRGB, null);
+                                dstR.setDataElements(x, y, dstVal);
+                                break;
+
+                            default:
+                                // awt.37=Unknown  composite type {0}
+                                throw new IllegalArgumentException(Messages.getString("awt.37", //$NON-NLS-1$
+                                        comp.getClass()));
+                        }
+                    }
+                    sx += hx;
+                    sy += hy;
+                }
+                sx += vx;
+                sy += vy;
+            }
+        }
+
+    }
+
+    private Rectangle2D getBounds2D(AffineTransform at, Rectangle r) {
+        int x = r.x;
+        int y = r.y;
+        int width = r.width;
+        int height = r.height;
+
+        float[] corners = {
+            x, y,
+            x + width, y,
+            x + width, y + height,
+            x, y + height
+        };
+
+        at.transform(corners, 0, corners, 0, 4);
+
+        Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0);
+        bounds.add(corners[2], corners[3]);
+        bounds.add(corners[4], corners[5]);
+        bounds.add(corners[6], corners[7]);
+
+        return bounds;
+    }
+
+    private int compose(int srcRGB, boolean isSrcAlphaPre,
+            int dstRGB, boolean dstHasAlpha, boolean isDstAlphaPre,
+            int rule, int srcConstAlpha){
+
+        int sa, sr, sg, sb, da, dr, dg, db;
+
+        sa = (srcRGB >> 24) & 0xff;
+        sr = (srcRGB >> 16) & 0xff;
+        sg = (srcRGB >> 8) & 0xff;
+        sb = srcRGB & 0xff;
+
+        if(isSrcAlphaPre){
+            sa = mulLUT[srcConstAlpha][sa] & 0xff;
+            sr = mulLUT[srcConstAlpha][sr] & 0xff;
+            sg = mulLUT[srcConstAlpha][sg] & 0xff;
+            sb = mulLUT[srcConstAlpha][sb] & 0xff;
+        }else{
+            sa = mulLUT[srcConstAlpha][sa] & 0xff;
+            sr = mulLUT[sa][sr] & 0xff;
+            sg = mulLUT[sa][sg] & 0xff;
+            sb = mulLUT[sa][sb] & 0xff;
+        }
+
+        da = (dstRGB >> 24) & 0xff;
+        dr = (dstRGB >> 16) & 0xff;
+        dg = (dstRGB >> 8) & 0xff;
+        db = dstRGB & 0xff;
+
+        if(!isDstAlphaPre){
+            dr = mulLUT[da][dr] & 0xff;
+            dg = mulLUT[da][dg] & 0xff;
+            db = mulLUT[da][db] & 0xff;
+        }
+
+        int Fs = 0;
+        int Fd = 0;
+        switch(rule){
+        case AlphaComposite.CLEAR:
+            break;
+
+        case AlphaComposite.DST:
+            Fd = 255;
+            break;
+
+        case AlphaComposite.DST_ATOP:
+            Fs = 255 - da;
+            Fd = sa;
+            break;
+
+        case AlphaComposite.DST_IN:
+            Fd = sa;
+            break;
+
+        case AlphaComposite.DST_OUT:
+            Fd = 255 - sa;
+            break;
+
+        case AlphaComposite.DST_OVER:
+            Fs = 255 - da;
+            Fd = 255;
+            break;
+
+        case AlphaComposite.SRC:
+            Fs = 255;
+            break;
+
+        case AlphaComposite.SRC_ATOP:
+            Fs = da;
+            Fd = 255 - sa;
+            break;
+
+        case AlphaComposite.SRC_IN:
+            Fs = da;
+            break;
+
+        case AlphaComposite.SRC_OUT:
+            Fs = 255 - da;
+            break;
+
+        case AlphaComposite.SRC_OVER:
+            Fs = 255;
+            Fd = 255 - sa;
+            break;
+
+        case AlphaComposite.XOR:
+            Fs = 255 - da;
+            Fd = 255 - sa;
+            break;
+        }
+        dr = (mulLUT[sr][Fs] & 0xff) + (mulLUT[dr][Fd] & 0xff);
+        dg = (mulLUT[sg][Fs] & 0xff) + (mulLUT[dg][Fd] & 0xff);
+        db = (mulLUT[sb][Fs] & 0xff) + (mulLUT[db][Fd] & 0xff);
+
+        da = (mulLUT[sa][Fs] & 0xff) + (mulLUT[da][Fd] & 0xff);
+
+        if(!isDstAlphaPre){
+            if(da != 255){
+                dr = divLUT[da][dr] & 0xff;
+                dg = divLUT[da][dg] & 0xff;
+                db = divLUT[da][db] & 0xff;
+            }
+        }
+        if(!dstHasAlpha) {
+            da = 0xff;
+        }
+        dstRGB = (da << 24) | (dr << 16) | (dg << 8) | db;
+
+        return dstRGB;
+
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java b/awt/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java
new file mode 100644
index 0000000..eb6f7b5
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java
@@ -0,0 +1,760 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.render;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+
+
+public class JavaLineRasterizer {
+
+    /**
+     *  LineDasher class provides dashing for particular dash style
+     */
+    public static class LineDasher {
+
+        int index;
+        float pos;
+        float phase;
+        float dash[];
+        float inv[];
+        boolean visible;
+
+        public LineDasher() {
+        }
+
+        public LineDasher(float dash[], float phase) {
+            this.dash = dash;
+            this.phase = phase;
+
+            inv = new float[dash.length];
+            int j = dash.length;
+            for (float element : dash) {
+                inv[--j] = element;
+            }
+            index = 0;
+            while (phase > dash[index]) {
+                phase -= dash[index];
+                index = (index + 1) % dash.length;
+            }
+            visible = index % 2 == 0;
+        }
+
+        void move(float step) { // main dasher
+            pos += step;
+            step += phase;
+            while(step >= dash[index]) {
+                step -= dash[index];
+                index = (index + 1) % dash.length;
+                visible = !visible;
+            }
+            phase = step;
+        }
+
+        float nextDash() {
+            phase = 0.0f;
+            index = (index + 1) % dash.length;
+            visible = !visible;
+            return dash[index];
+        }
+
+        LineDasher createDiagonal(double k, float length, boolean invert) {
+            LineDasher local = new LineDasher();
+            local.dash = new float[dash.length];
+            if (invert) { // inverted dasher
+                move(length);
+                local.phase = (float)((dash[index] - phase) * k);
+                local.visible = visible;
+                local.index = inv.length - index - 1;
+                for(int i = 0; i < inv.length; i++) {
+                    local.dash[i] = (float)(inv[i] * k);
+                }
+            } else {
+                local.phase = (float)(phase * k);
+                local.visible = visible;
+                local.index = index;
+                for(int i = 0; i < dash.length; i++) {
+                    local.dash[i] = (float)(dash[i] * k);
+                }
+                move(length);
+            }
+            return local;
+        }
+
+        LineDasher createOrtogonal(float length, boolean invert) {
+            LineDasher local = new LineDasher();
+            local.dash = new float[dash.length];
+            if (invert) { // inverted dasher
+                move(length);
+                local.phase = dash[index] - phase;
+                local.visible = visible;
+                local.index = inv.length - index - 1;
+                local.dash = inv;
+            } else {
+                local.phase = phase;
+                local.visible = visible;
+                local.index = index;
+                local.dash = dash;
+                move(length);
+            }
+            return local;
+        }
+
+        LineDasher createChild(float start) {
+            LineDasher child = new LineDasher();
+            child.phase = phase;
+            child.visible = visible;
+            child.index = index;
+            child.dash = dash;
+            child.move(start);
+            return child;
+        }
+
+    }
+
+    /**
+     * Line class provides rasterization for different line types
+     */
+    abstract static class Line {
+
+        int x1, y1, x2, y2;
+        int x, y;
+        MultiRectArea dst;
+
+        Line(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+            this.x1 = x1;
+            this.y1 = y1;
+            this.x2 = x2;
+            this.y2 = y2;
+            this.dst = dst;
+        }
+
+        static abstract class Diag extends Line {
+            int dx, dy, adx, ady, sx, sy;
+            int eBase, ePos, eNeg;
+            int xcount;
+            int e;
+
+            Diag(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+                super(x1, y1, x2, y2, dst);
+                dx = x2 - x1;
+                dy = y2 - y1;
+                sy = 1;
+                if (dx > 0) {
+                    adx = dx;
+                    sx = 1;
+                } else {
+                    adx = -dx;
+                    sx = -1;
+                }
+                ady = dy;
+            }
+
+            float getLength() {
+                return (float)Math.sqrt(dx * dx + dy * dy);
+            }
+
+            static class Hor extends Diag {
+
+                Hor(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+                    super(x1, y1, x2, y2, dst);
+                    eBase = ady + ady - adx;
+                    ePos = 2 * (ady - adx);
+                    eNeg = ady + ady;
+                    xcount = adx;
+                }
+
+                @Override
+                void rasterize() {
+                    e = eBase;
+                    x = x1;
+                    y = y1;
+                    rasterize(xcount);
+                }
+
+                @Override
+                void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
+                    e = eBase + 2 * (ady * Math.abs(nx1 - x1) - adx * Math.abs(ny1 - y1));
+                    x = nx1;
+                    y = ny1;
+                    rasterize(dx > 0 ? nx2 - nx1 : nx1 - nx2);
+                }
+
+                @Override
+                void rasterize(int count) {
+                    int px = x;
+                    while (count-- > 0) {
+                        if (e >= 0) {
+                            if (sx > 0) {
+                                dst.addRect(px, y, x, y);
+                            } else {
+                                dst.addRect(x, y, px, y);
+                            }
+                            x += sx;
+                            y += sy;
+                            e += ePos;
+                            px = x;
+                        } else {
+                            e += eNeg;
+                            x += sx;
+                        }
+                    }
+                    if (sx > 0) {
+                        dst.addRect(px, y, x, y);
+                    } else {
+                        dst.addRect(x, y, px, y);
+                    }
+                }
+
+                @Override
+                void skip(int count) {
+                    while (count-- > 0) {
+                        x += sx;
+                        if (e >= 0) {
+                            y += sy;
+                            e += ePos;
+                        } else {
+                            e += eNeg;
+                        }
+                    }
+                }
+
+            }
+
+            static class Ver extends Diag {
+
+                Ver(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+                    super(x1, y1, x2, y2, dst);
+                    eBase = adx + adx - ady;
+                    ePos = 2 * (adx - ady);
+                    eNeg = adx + adx;
+                    xcount = ady;
+                }
+
+                @Override
+                void rasterize() {
+                    e = eBase;
+                    x = x1;
+                    y = y1;
+                    rasterize(xcount);
+                }
+
+                @Override
+                void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
+                    e = eBase + 2 * (adx * Math.abs(ny1 - y1) - ady * Math.abs(nx1 - x1));
+                    x = nx1;
+                    y = ny1;
+                    rasterize(ny2 - ny1);
+                }
+
+                @Override
+                void rasterize(int count) {
+                    int py = y;
+                    while (count-- > 0) {
+                        if (e >= 0) {
+                            dst.addRect(x, py, x, y);
+                            x += sx;
+                            y += sy;
+                            e += ePos;
+                            py = y;
+                        } else {
+                            y += sy;
+                            e += eNeg;
+                        }
+                    }
+                    dst.addRect(x, py, x, y);
+                }
+
+                @Override
+                void skip(int count) {
+                    while (count-- > 0) {
+                        y += sy;
+                        if (e >= 0) {
+                            x += sx;
+                            e += ePos;
+                        } else {
+                            e += eNeg;
+                        }
+                    }
+                }
+
+            }
+
+            static class HorDashed extends Hor {
+
+                LineDasher local;
+
+                HorDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher, boolean invert) {
+                    super(x1, y1, x2, y2, dst);
+                    float length = getLength();
+                    local = dasher.createDiagonal(xcount / length, length, invert);
+                }
+
+                @Override
+                void rasterize() {
+                    e = eBase;
+                    x = x1;
+                    y = y1;
+                    rasterizeDash(xcount, local);
+                }
+
+                @Override
+                void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
+                    e = eBase + 2 * (ady * Math.abs(nx1 - x1) - adx * Math.abs(ny1 - y1));
+                    x = nx1;
+                    y = ny1;
+                    rasterizeDash(Math.abs(nx2 - nx1), local.createChild(Math.abs(nx1 - x1)));
+                }
+
+            }
+
+            static class VerDashed extends Ver {
+
+                LineDasher local;
+
+                VerDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher, boolean invert) {
+                    super(x1, y1, x2, y2, dst);
+                    float length = getLength();
+                    local = dasher.createDiagonal(xcount / length, length, invert);
+                }
+
+                @Override
+                void rasterize() {
+                    e = eBase;
+                    x = x1;
+                    y = y1;
+                    rasterizeDash(xcount, local);
+                }
+
+                @Override
+                void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
+                    e = eBase + 2 * (adx * Math.abs(ny1 - y1) - ady * Math.abs(nx1 - x1));
+                    x = nx1;
+                    y = ny1;
+                    rasterizeDash(ny2 - ny1, local.createChild(ny1 - y1));
+                }
+
+            }
+
+            @Override
+            void rasterize(int[] clip, int index) {
+                int cx1 = clip[index + 0];
+                int cy1 = clip[index + 1];
+                int cx2 = clip[index + 2] + 1;
+                int cy2 = clip[index + 3] + 1;
+
+                int code1 =
+                    (x1 < cx1 ? 1 : 0) | (x1 >= cx2 ? 2 : 0) |
+                    (y1 < cy1 ? 8 : 0) | (y1 >= cy2 ? 4 : 0);
+                int code2 =
+                    (x2 < cx1 ? 1 : 0) | (x2 >= cx2 ? 2 : 0) |
+                    (y2 < cy1 ? 8 : 0) | (y2 >= cy2 ? 4 : 0);
+
+                // Outside
+                if ((code1 & code2) != 0) {
+                    return;
+                }
+
+                // Inside
+                if (code1 == 0 && code2 == 0) {
+                    rasterize();
+                    return;
+                }
+
+                // Clip
+                int nx1 = x1;
+                int ny1 = y1;
+                int nx2 = x2;
+                int ny2 = y2;
+                // need to clip
+                cx1 -= x1; cx2 -= x1;
+                cy1 -= y1; cy2 -= y1;
+//                int d;
+                int newx1 = 0, newy1 = 0, newx2 = 0, newy2 = 0;
+                if (code1 != 0) {
+                    newx1 = Integer.MAX_VALUE;
+                    if ((code1 & 8) != 0) {
+                        // clip point 1 with top clip bound
+                        newy1 = cy1;
+                        newx1 = clipY(dx, dy, newy1, true);
+
+                    } else if ((code1 & 4) != 0) {
+                        // clip point 1 with bottom clip bound
+                        newy1 = cy2 - 1;
+                        newx1 = clipY(dx, dy, newy1, false);
+                    }
+                    if ((code1 & 1) != 0 && (cx1 > newx1 || newx1 == Integer.MAX_VALUE)) {
+                        // clip point 1 with left clip bound
+                        newx1 = cx1;
+                        newy1 = clipX(dx, dy, newx1, false);
+                    } else if ((code1 & 2) != 0 && (newx1 >= cx2 || newx1 == Integer.MAX_VALUE)) {
+                        // clip point 1 with right clip bound
+                        newx1 = cx2 - 1;
+                        newy1 = clipX(dx, dy, newx1, false);
+                    }
+                    if (newx1 < cx1 || newx1 >= cx2 || newy1 < cy1 || newy1 >= cy2) {
+                        return;
+                    }
+//                    d = 2 * (ady * Math.abs(newx1) - adx * Math.abs(newy1)) + 2 * ady - adx;
+                } else {
+//                    d = (ady << 1) - adx;
+                }
+
+                if (code2 != 0) {
+                    newx2=Integer.MAX_VALUE;
+                    if ((code2 & 8) != 0) {
+                        // clip point 2 with top clip bound
+                        newy2 = cy1;
+                        newx2 = clipY(dx, dy, newy2, true);
+                    } else if ((code2 & 4) != 0) {
+                        // clip point 2 with bottom clip bound
+                        newy2 = cy2 - 1;
+                        newx2 = clipY(dx, dy, newy2, false);
+                    }
+                    if ((code2 & 1) != 0 && (cx1 > newx2 || newx2 == Integer.MAX_VALUE)) {
+                        // clip point 2 with left clip bound
+                        newx2 = cx1;
+                        newy2 = clipX(dx, dy, newx2, false);
+                    } else if ((code2 & 2) != 0 && (newx2 >= cx2 || newx2 == Integer.MAX_VALUE)) {
+                        // clip point 2 with right clip bound
+                        newx2 = cx2 - 1;
+                        newy2 = clipX(dx, dy, newx2, false);
+                    }
+                    if (newx2 < cx1 || newx2 >= cx2 || newy2 < cy1 || newy2 >= cy2) {
+                        return;
+                    }
+                    nx2 = x1 + newx2;
+                    ny2 = y1 + newy2;
+                }
+                nx1 = x1 + newx1;
+                ny1 = y1 + newy1;
+
+                rasterizeClipped(nx1, ny1, nx2, ny2);
+            }
+
+            abstract void rasterizeClipped(int nx1, int ny1, int nx2, int ny2);
+
+        }
+
+        static abstract class Ortog extends Line {
+
+            Ortog(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+                super(x1, y1, x2, y2, dst);
+            }
+
+            static class Hor extends Ortog {
+
+                int dx;
+
+                Hor(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+                    super(x1, y1, x2, y2, dst);
+                    dx = x2 - x1;
+                }
+
+                @Override
+                void rasterize() {
+                    if (dx > 0) {
+                        dst.addRect(x1, y1, x2, y2);
+                    } else {
+                        dst.addRect(x2, y2, x1, y1);
+                    }
+                }
+
+                @Override
+                void rasterize(int step) {
+                    int px = x;
+                    if (dx > 0) {
+                        x += step;
+                        dst.addRect(px, y1, x - 1, y2);
+                    } else {
+                        x -= step;
+                        dst.addRect(x + 1, y2, px, y1);
+                    }
+                }
+
+                @Override
+                void skip(int step) {
+                    if (dx > 0) {
+                        x += step;
+                    } else {
+                        x -= step;
+                    }
+                }
+
+                void rasterizeClipped(int nx1, int nx2) {
+                    if (nx1 < nx2) {
+                        dst.addRect(nx1, y1, nx2, y1);
+                    } else {
+                        dst.addRect(nx2, y1, nx1, y1);
+                    }
+                }
+
+                @Override
+                void rasterize(int[] clip, int index) {
+                    if (y1 >= clip[index + 1] && y1 <= clip[index + 3]) {
+                        int cx1 = clip[index + 0];
+                        int cx2 = clip[index + 2];
+                        if (x1 <= cx2 && x2 >= cx1) {
+                            int nx1, nx2;
+                            if (dx > 0) {
+                                nx1 = Math.max(x1, cx1);
+                                nx2 = Math.min(x2, cx2);
+                            } else {
+                                nx2 = Math.max(x2, cx1);
+                                nx1 = Math.min(x1, cx2);
+                            }
+                            rasterizeClipped(nx1, nx2);
+                        }
+                    }
+                }
+
+            }
+
+            static class Ver extends Ortog {
+
+                int dy;
+
+                Ver(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+                    super(x1, y1, x2, y2, dst);
+                    dy = y2 - y1;
+                }
+
+                @Override
+                void rasterize() {
+                    dst.addRect(x1, y1, x2, y2);
+                }
+
+                @Override
+                void rasterize(int step) {
+                    int py = y;
+                    y += step;
+                    dst.addRect(x1, py, x2, y - 1);
+                }
+
+                @Override
+                void skip(int step) {
+                    y += step;
+                }
+
+                void rasterizeClipped(int ny1, int ny2) {
+                    dst.addRect(x1, ny1, x1, ny2);
+                }
+
+                @Override
+                void rasterize(int[] clip, int index) {
+                    if (x1 >= clip[index] && x1 <= clip[index + 2]) {
+                        int cy1 = clip[index + 1];
+                        int cy2 = clip[index + 3];
+                        if (y1 <= cy2 && y2 >= cy1) {
+                            rasterizeClipped(Math.max(y1, cy1), Math.min(y2, cy2));
+                        }
+                    }
+                }
+
+            }
+
+            static class HorDashed extends Hor {
+
+                LineDasher local;
+
+                HorDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher) {
+                    super(x1, y1, x2, y2, dst);
+                    dx = x2 - x1;
+                    local = dasher.createOrtogonal(Math.abs(dx), false);
+                }
+
+                @Override
+                void rasterize() {
+                    x = x1;
+                    y = y1;
+                    rasterizeDash(Math.abs(dx), local);
+                }
+
+                @Override
+                void rasterizeClipped(int nx1, int nx2) {
+                    x = nx1;
+                    y = y1;
+                    rasterizeDash(Math.abs(nx2 - nx1), local.createChild(Math.abs(nx1 - x1)));
+                }
+
+            }
+
+            static class VerDashed extends Ver {
+
+                LineDasher local;
+
+                VerDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher, boolean invert) {
+                    super(x1, y1, x2, y2, dst);
+                    dy = y2 - y1;
+                    local = dasher.createOrtogonal(dy, invert);
+                }
+
+                @Override
+                void rasterize() {
+                    x = x1;
+                    y = y1;
+                    rasterizeDash(dy, local);
+                }
+
+                @Override
+                void rasterizeClipped(int ny1, int ny2) {
+                    x = x1;
+                    y = ny1;
+                    rasterizeDash(ny2 - ny1, local.createChild(ny1));
+                }
+
+            }
+
+        }
+
+        abstract void rasterize();
+        abstract void rasterize(int[] clip, int index);
+        abstract void rasterize(int count);
+        abstract void skip(int count);
+
+        void rasterizeDash(int count, LineDasher dasher) {
+            float delta = dasher.dash[dasher.index] - dasher.phase;
+            int step = (int)delta;
+            delta -= step;
+            while(count > step) {
+                if (dasher.visible) {
+                    rasterize(step);
+                } else {
+                    skip(step);
+                }
+                count -= step;
+                delta += dasher.nextDash();
+                step = (int)delta;
+                delta -= step;
+            }
+            if (count > 0 && dasher.visible) {
+                rasterize(count);
+                dasher.move(count);
+            }
+        }
+
+    }
+
+    /**
+     * Common clipping method
+     */
+    static int clip(int dX1, int dX2, int cX, boolean top) {
+        int adX1 = dX1 < 0 ? -dX1 : dX1;
+        int adX2 = dX2 < 0 ? -dX2 : dX2;
+        if (adX1 <= adX2) {
+            // obtuse intersection angle
+            return ((dX1 << 1) * cX + (dX1 > 0 ? dX2 : -dX2)) / (dX2 << 1);
+        }
+        int k;
+        if (top) {
+            k = -dX1 + (dX2 < 0 ? 0 : dX1 > 0 ? (dX2 << 1) : -(dX2 << 1));
+        } else {
+            k = dX1 + (dX2 > 0 ? 0 : dX1 > 0 ? (dX2 << 1) : -(dX2 << 1));
+        }
+
+        k += dX1 > 0 == dX2 > 0 ? -1 : 1;
+        return ((dX1 << 1) * cX + k) / (dX2 << 1);
+    }
+
+    /**
+     * Clipping along X axis
+     */
+    static int clipX(int dx, int dy, int cy, boolean top) {
+        return clip(dy, dx, cy, top);
+    }
+
+    /**
+     * Clipping along Y axis
+     */
+    static int clipY(int dx, int dy, int cx, boolean top) {
+        return clip(dx, dy, cx, top);
+    }
+
+    /**
+     * Rasterizes line using clippind and dashing style
+     * @param x1 - the x coordinate of the first control point
+     * @param y1 - the y coordinate of the first control point
+     * @param x2 - the x coordinate of the second control point
+     * @param y2 - the y coordinate of the second control point
+     * @param clip - the MultiRectArea object of clipping area
+     * @param dasher - the dasher style
+     * @param invert - the invert indicator, always false
+     * @return a MultiRectArea of rasterizer line
+     */
+    public static MultiRectArea rasterize(int x1, int y1, int x2, int y2, MultiRectArea clip, LineDasher dasher, boolean invert) {
+
+        MultiRectArea dst = new MultiRectArea(false);
+        int dx = x2 - x1;
+        int dy = y2 - y1;
+
+        // Point
+        if (dx == 0 && dy == 0) {
+            if ((clip == null || clip.contains(x1, y1)) && (dasher == null || dasher.visible)) {
+                dst = new MultiRectArea(x1, y1, x1, y1);
+            }
+            return dst;
+        }
+
+        if (dy < 0) {
+            return rasterize(x2, y2, x1, y1, clip, dasher, true);
+        }
+
+        Line line;
+        if (dasher == null) {
+            if (dx == 0) {
+                line = new Line.Ortog.Ver(x1, y1, x2, y2, dst);
+            } else
+                if (dy == 0) {
+                    line = new Line.Ortog.Hor(x1, y1, x2, y2, dst);
+                } else {
+                    if (dy < Math.abs(dx)) {
+                        line = new Line.Diag.Hor(x1, y1, x2, y2, dst);
+                    } else {
+                        line = new Line.Diag.Ver(x1, y1, x2, y2, dst);
+                    }
+                }
+        } else {
+            if (dx == 0) {
+                line = new Line.Ortog.VerDashed(x1, y1, x2, y2, dst, dasher, invert);
+            } else
+                if (dy == 0) {
+                    line = new Line.Ortog.HorDashed(x1, y1, x2, y2, dst, dasher);
+                } else {
+                    if (dy < Math.abs(dx)) {
+                        line = new Line.Diag.HorDashed(x1, y1, x2, y2, dst, dasher, invert);
+                    } else {
+                        line = new Line.Diag.VerDashed(x1, y1, x2, y2, dst, dasher, invert);
+                    }
+                }
+        }
+
+
+        if (clip == null || clip.isEmpty()) {
+            line.rasterize();
+        } else {
+            for(int i = 1; i < clip.rect[0]; i += 4) {
+                line.rasterize(clip.rect, i);
+            }
+        }
+
+        return dst;
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java b/awt/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java
new file mode 100644
index 0000000..dbaaf53
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java
@@ -0,0 +1,475 @@
+/*
+ *  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.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.Shape;
+import java.awt.geom.PathIterator;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class JavaShapeRasterizer {
+
+    static final int POINT_CAPACITY = 16;
+
+    int edgesCount;
+    int edgeCur;
+    int[] edgesX;
+    int[] edgesY;
+    int[] edgesYS; // Y coordinate of edge START point
+    int[] edgesN;
+    int[] edgesDY;
+    int[] bounds;
+    int boundCount;
+    boolean[] edgesExt; // Extremal points
+
+    int activeCount;
+    float[] activeX;
+    int[] activeYEnd;
+    float[] activeXStep;
+    int[] activeDY;
+    boolean[] activeExt;
+
+    int[] crossX;
+    int[] crossDY;
+
+    Filler filler;
+
+    /**
+     * Rasterization filler for different path rules
+     */
+    static abstract class Filler {
+
+        static class NonZero extends Filler {
+            @Override
+            void add(MultiRectArea.LineCash rect, int[] points, int[] orient, int length, int y) {
+
+                int[] dst = new int[length];
+                int dstLength = 1;
+                dst[0] = points[0];
+                int count = 0;
+                boolean inside = true;
+                for(int i = 0; i < length; i++) {
+                    count += orient[i] > 0 ? 1 : -1;
+                    if (count == 0) {
+                        dst[dstLength++] = points[i];
+                        inside = false;
+                    } else {
+                        if (!inside) {
+                            dst[dstLength++] = points[i];
+                            inside = true;
+                        }
+                    }
+
+                }
+
+                for(int i = 1; i < dstLength; i += 2) {
+                    dst[i]--;
+                }
+
+                dstLength = excludeEmpty(dst, dstLength);
+//              System.out.println("test");
+
+                dstLength = union(dst, dstLength);
+
+                rect.addLine(dst, dstLength);
+            }
+        }
+
+        static class EvenOdd extends Filler {
+            @Override
+            void add(MultiRectArea.LineCash rect, int[] points, int[] orient, int length, int y) {
+    /*
+                int[] buf = new int[length];
+                int j = 0;
+                for(int i = 0; i < length - 1; i++) {
+                    if (points[i] != points[i + 1]) {
+                        buf[j++] = points[i];
+                    }
+                }
+    */
+                for(int i = 1; i < length; i += 2) {
+                    points[i]--;
+                }
+
+                length = excludeEmpty(points, length);
+//              System.out.println("test");
+
+                length = union(points, length);
+                rect.addLine(points, length);
+    /*
+                for(int i = 0; i < length;) {
+                    rect.add(points[i++], y, points[i++], y);
+                }
+    */
+            }
+        }
+
+        abstract void add(MultiRectArea.LineCash rect, int[] points, int[] orient, int length, int y);
+
+        static int excludeEmpty(int[] points, int length) {
+            int i = 0;
+            while(i < length) {
+                if (points[i] <= points[i + 1]) {
+                    i += 2;
+                } else {
+                    length -= 2;
+                    System.arraycopy(points, i + 2, points, i, length - i);
+                }
+            }
+            return length;
+        }
+
+        static int union(int[] points, int length) {
+            int i = 1;
+            while(i < length - 1) {
+                if (points[i] < points[i - 1]) {
+                    System.arraycopy(points, i + 1, points, i - 1, length - i - 1);
+                    length -= 2;
+                } else
+                if (points[i] >= points[i + 1] - 1) {
+                    System.arraycopy(points, i + 2, points, i, length - i - 2);
+                    length -= 2;
+                } else {
+                    i += 2;
+                }
+            }
+            return length;
+        }
+
+    }
+
+    public JavaShapeRasterizer() {
+    }
+
+    /**
+     * Checks buffer size and realloc if necessary
+     */
+    int[] checkBufSize(int[] buf, int size) {
+        if (size == buf.length) {
+            int[] tmp;
+            tmp = new int[size + POINT_CAPACITY];
+            System.arraycopy(buf, 0, tmp, 0, buf.length);
+            buf = tmp;
+        }
+        return buf;
+    }
+
+    /**
+     * Adds to the buffers new edge 
+     */
+    void addEdge(int x, int y, int num) {
+        edgesX = checkBufSize(edgesX, edgesCount);
+        edgesY = checkBufSize(edgesY, edgesCount);
+        edgesN = checkBufSize(edgesN, edgesCount);
+        edgesX[edgesCount] = x;
+        edgesY[edgesCount] = y;
+        edgesN[edgesCount] = (num << 16) | edgesCount;
+        edgesCount++;
+    }
+
+    /**
+     * Prepare all buffers and variable to rasterize shape 
+     */
+    void makeBuffer(PathIterator path, double flatness) {
+        edgesX = new int[POINT_CAPACITY];
+        edgesY = new int[POINT_CAPACITY];
+        edgesN = new int[POINT_CAPACITY];
+        bounds = new int[POINT_CAPACITY];
+        boundCount = 0;
+        edgesCount = 0;
+
+        if (path.getWindingRule() == PathIterator.WIND_EVEN_ODD) {
+            filler = new Filler.EvenOdd();
+        } else {
+            filler = new Filler.NonZero();
+        }
+        float[] coords = new float[2];
+        boolean closed = true;
+        while (!path.isDone()) {
+            switch(path.currentSegment(coords)) {
+            case PathIterator.SEG_MOVETO:
+                if (!closed) {
+                    boundCount++;
+                    bounds = checkBufSize(bounds, boundCount);
+                    bounds[boundCount] = edgesCount;
+                }
+                addEdge((int)coords[0], (int)coords[1], boundCount);
+                closed = false;
+                break;
+            case PathIterator.SEG_LINETO:
+                addEdge((int)coords[0], (int)coords[1], boundCount);
+                break;
+            case PathIterator.SEG_CLOSE:
+                boundCount++;
+                bounds = checkBufSize(bounds, boundCount);
+                bounds[boundCount] = edgesCount;
+                closed = true;
+                break;
+            default:
+                // awt.36=Wrong segment
+                throw new RuntimeException(Messages.getString("awt.36")); //$NON-NLS-1$
+            }
+            path.next();
+        }
+        if (!closed) {
+            boundCount++;
+            bounds = checkBufSize(bounds, boundCount);
+            bounds[boundCount] = edgesCount;
+        }
+    }
+
+    /**
+     * Sort buffers
+     */
+    void sort(int[] master, int[] slave, int length) {
+        for(int i = 0; i < length - 1; i++) {
+            int num = i;
+            int min = master[num];
+            for(int j = i + 1; j < length; j++) {
+                if (master[j] < min) {
+                    num = j;
+                    min = master[num];
+                }
+            }
+            if (num != i) {
+                master[num] = master[i];
+                master[i] = min;
+                min = slave[num];
+                slave[num] = slave[i];
+                slave[i] = min;
+            }
+        }
+    }
+
+    int getNext(int cur) {
+        int n = edgesN[cur];
+        int bound = n >> 16;
+        int num = (n & 0xFFFF) + 1;
+        if (num == bounds[bound + 1]) {
+            return bounds[bound];
+        }
+        return num;
+    }
+
+    int getPrev(int cur) {
+        int n = edgesN[cur];
+        int bound = n >> 16;
+        int num = (n & 0xFFFF) - 1;
+        if (num < bounds[bound]) {
+            return bounds[bound + 1] - 1;
+        }
+        return num;
+    }
+
+    int getNextShape(int cur) {
+        int bound = edgesN[cur] >> 16;
+        return bounds[bound + 1];
+    }
+
+    void init() {
+
+        edgesYS = new int[edgesCount];
+        System.arraycopy(edgesY, 0, edgesYS, 0, edgesCount);
+        // Create edgesDY
+        edgesDY = new int[edgesCount];
+        for(int i = 0; i < edgesCount; i++) {
+            int dy = edgesY[getNext(i)] - edgesY[i];
+            edgesDY[i] = dy;
+        }
+
+        // Create edgesExt
+        edgesExt = new boolean[edgesCount];
+        int prev = -1;
+        int i = 0;
+        int pos = 0;
+        while(i < edgesCount) {
+
+            TOP: {
+                do {
+                    if (edgesDY[i] > 0) {
+                        break TOP;
+                    }
+                    i = getNext(i);
+                } while (i != pos);
+                i = pos = getNextShape(i);
+                continue;
+            }
+
+            BOTTOM: {
+                do {
+                    if (edgesDY[i] < 0) {
+                        break BOTTOM;
+                    }
+                    if (edgesDY[i] > 0) {
+                        prev = i;
+                    }
+                    i = getNext(i);
+                } while (i != pos);
+                i = pos = getNextShape(i);
+                continue;
+            }
+
+            if (prev != -1) {
+                edgesExt[prev] = true;
+            }
+            edgesExt[i] = true;
+        }
+
+        // Sort edgesY and edgesN
+        sort(edgesYS, edgesN, edgesCount);
+
+        edgeCur = 0;
+        activeCount = 0;
+        activeX = new float[edgesCount];
+        activeYEnd = new int[edgesCount];
+        activeXStep = new float[edgesCount];
+        activeDY = new int[edgesCount];
+        activeExt = new boolean[edgesCount];
+
+        crossX = new int[edgesCount];
+        crossDY = new int[edgesCount];
+    }
+
+    /**
+     * Marks edge as active
+     */
+    void addActiveEdge(int levelY, int start, int end, boolean back) {
+        int dy = back ? -edgesDY[end] : edgesDY[start];
+        if (dy <= 0) {
+            return;
+        }
+        int x1 = edgesX[start];
+        int dx = edgesX[end] - x1;
+        activeX[activeCount] = x1;
+        activeYEnd[activeCount] = edgesY[end];
+        activeXStep[activeCount] = dx / (float)dy;
+        activeDY[activeCount] = back ? -dy : dy;
+        activeExt[activeCount] = back ? edgesExt[end] : edgesExt[start];
+        activeCount++;
+    }
+
+    /**
+     * Find new active edges
+     */
+    int findActiveEdges(int levelY) {
+
+        int edgeActive = edgeCur;
+        while (edgeActive < edgesCount && edgesYS[edgeActive] == levelY) {
+            edgeActive++;
+        }
+
+        int activeNext = edgeActive;
+
+        while (edgeActive > edgeCur) {
+            edgeActive--;
+            int num = edgesN[edgeActive] & 0xFFFF;
+            addActiveEdge(levelY, num, getPrev(edgeActive), true);
+            addActiveEdge(levelY, num, getNext(edgeActive), false);
+        }
+
+        edgeCur = activeNext;
+
+        if (activeNext == edgesCount) {
+            return edgesY[edgesCount - 1];
+        }
+        return edgesYS[activeNext];
+    }
+
+    /**
+     * Rasterizes shape with particular flatness
+     * @param shape - the souze Shape to be rasterized
+     * @param flatness - the rasterization flatness
+     * @return a MultiRectArea of rasterized shape
+     */
+    public MultiRectArea rasterize(Shape shape, double flatness) {
+
+        PathIterator path = shape.getPathIterator(null, flatness);
+
+        // Shape is empty
+        if (path.isDone()) {
+            return new MultiRectArea();
+        }
+
+        makeBuffer(path, flatness);
+
+        init();
+
+        int y = edgesYS[0];
+        int nextY = y;
+        int crossCount;
+
+        MultiRectArea.LineCash rect = new MultiRectArea.LineCash(edgesCount);
+        rect.setLine(y);
+
+        while(y <= nextY) {
+
+            crossCount = 0;
+
+            if (y == nextY) {
+
+                int i = activeCount;
+                while(i > 0) {
+                    i--;
+                    if (activeYEnd[i] == y) {
+
+                        activeCount--;
+                        int length = activeCount - i;
+                        if (length != 0) {
+                            int pos = i + 1;
+                            System.arraycopy(activeX, pos, activeX, i, length);
+                            System.arraycopy(activeYEnd, pos, activeYEnd, i, length);
+                            System.arraycopy(activeXStep, pos, activeXStep, i, length);
+                            System.arraycopy(activeDY, pos, activeDY, i, length);
+                            System.arraycopy(activeExt, pos, activeExt, i, length);
+                        }
+                    }
+                }
+
+                nextY = findActiveEdges(y);
+            }
+
+            // Get X crossings
+            for(int i = 0; i < activeCount; i++) {
+                crossX[crossCount] = (int)Math.ceil(activeX[i]);
+                crossDY[crossCount] = activeDY[i];
+                crossCount++;
+            }
+
+            if (crossCount == 0) {
+                rect.skipLine();
+            } else {
+                // Sort X crossings
+                sort(crossX, crossDY, crossCount);
+                filler.add(rect, crossX, crossDY, crossCount, y);
+            }
+
+            for(int i = 0; i < activeCount; i++) {
+                activeX[i] += activeXStep[i];
+            }
+
+            y++;
+        }
+
+        return rect;
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaTextRenderer.java b/awt/org/apache/harmony/awt/gl/render/JavaTextRenderer.java
new file mode 100644
index 0000000..322ba57
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaTextRenderer.java
@@ -0,0 +1,263 @@
+/*
+ *  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.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.*;
+import java.awt.image.*;
+
+
+import java.awt.font.GlyphMetrics;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+
+import org.apache.harmony.awt.gl.TextRenderer;
+import org.apache.harmony.awt.gl.font.CommonGlyphVector;
+import org.apache.harmony.awt.gl.font.FontPeerImpl;
+import org.apache.harmony.awt.gl.font.Glyph;
+import org.apache.harmony.awt.gl.image.BufferedImageGraphics2D;
+
+public class JavaTextRenderer extends TextRenderer {
+
+    public static final JavaTextRenderer inst = new JavaTextRenderer();
+
+    @Override
+    public void drawGlyphVector(Graphics2D g, GlyphVector glyphVector,
+            float x, float y) {
+
+        AffineTransform at = g.getTransform();
+        Rectangle c = g.getClipBounds();
+        if (at != null){
+            int atType = at.getType();
+            if (atType == AffineTransform.TYPE_TRANSLATION) {
+                c.translate((int)Math.round(at.getTranslateX()), (int)Math.round(at.getTranslateY()));
+            }
+        }
+
+        WritableRaster wr = ((BufferedImageGraphics2D)g).getWritableRaster();
+        ColorModel cm = ((BufferedImageGraphics2D)g).getColorModel();
+
+        Rectangle rBounds = wr.getBounds();
+
+        Object color = cm.getDataElements(g.getColor().getRGB(), null);
+
+        drawClipGlyphVector(wr, color, glyphVector, (int)Math.round(x + at.getTranslateX()), (int)Math.round(y + at.getTranslateY()),
+        Math.max(c.x,rBounds.x),
+        Math.max(c.y,rBounds.y),
+        Math.min((int)Math.round(c.getMaxX()), (int)Math.round(rBounds.getMaxX())),
+        Math.min((int)Math.round(c.getMaxY()), (int)Math.round(rBounds.getMaxY())));
+
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void drawString(Graphics2D g, String str, float x, float y) {
+        AffineTransform at = g.getTransform();
+        Rectangle c = g.getClipBounds();
+        if (at != null){
+            int atType = at.getType();
+            if (atType == AffineTransform.TYPE_TRANSLATION) {
+                c.translate((int)Math.round(at.getTranslateX()), (int)Math.round(at.getTranslateY()));
+            }
+        }
+        WritableRaster wr = ((BufferedImageGraphics2D)g).getWritableRaster();
+        ColorModel cm = ((BufferedImageGraphics2D)g).getColorModel();
+        Rectangle rBounds = wr.getBounds();
+
+        Object color = cm.getDataElements(g.getColor().getRGB(), null);
+
+        drawClipString(wr, color, str, (FontPeerImpl) (g.getFont().getPeer()),
+                (int)Math.round(x + at.getTranslateX()), (int)Math.round(y + at.getTranslateY()),
+                Math.max(c.x,rBounds.x),
+                Math.max(c.y,rBounds.y),
+                Math.min((int)Math.round(c.getMaxX()), (int)Math.round(rBounds.getMaxX())),
+                Math.min((int)Math.round(c.getMaxY()), (int)Math.round(rBounds.getMaxY())));
+
+    }
+
+    /**
+     * 
+     * Draws string on specified raster at desired position.
+     *  
+     * @param raster specified WritableRaster to draw at
+     * @param color color of the text
+     * @param glyphVector GlyphVector object to draw
+     * @param x start X position to draw
+     * @param y start Y position to draw
+     * @param cMinX minimum x of the raster area to draw
+     * @param cMinY minimum y of the raster area to draw
+     * @param cMaxX maximum x of the raster area to draw
+     * @param cMaxY maximum y of the raster area to draw
+     */
+    public void drawClipGlyphVector(WritableRaster raster, Object color,
+            GlyphVector glyphVector, int x, int y,
+            int cMinX, int cMinY, int cMaxX, int cMaxY) {
+        // TODO: implement complex clipping
+
+        int xSrcSurf, ySrcSurf; // Start point in String rectangle
+        int xDstSurf, yDstSurf; // Start point in Surface rectangle
+        int clWidth, clHeight;
+
+        for (int i = 0; i < glyphVector.getNumGlyphs(); i++) {
+            Glyph gl = ((CommonGlyphVector) glyphVector).vector[i];
+
+            if (gl.getPointWidth() == 0) {
+                continue;
+            }
+
+            byte[] data = gl.getBitmap();
+            if (data != null) {
+                Point2D pos = glyphVector.getGlyphPosition(i);
+
+                xSrcSurf = 0;//gl.bmp_left;
+                ySrcSurf = 0;//gl.bmp_rows - gl.bmp_top;
+
+                xDstSurf = x + (int)pos.getX() + (int) gl.getGlyphPointMetrics().getLSB();// + gl.bmp_left;
+                yDstSurf = y - gl.bmp_top/*getPointHeight()*/  + (int) pos.getY();// - (gl.bmp_rows-gl.bmp_top);
+
+                int textWidth = gl.bmp_width;
+                int textHeight = gl.getPointHeight();
+
+                // if Regions don't intersect
+                if ((xDstSurf > cMaxX) || (yDstSurf > cMaxY) || (xDstSurf + textWidth < cMinX)
+                        || (yDstSurf + textHeight < cMinY)) {
+                    // Nothing to do
+                } else {
+                    if (xDstSurf >= cMinX) {
+                        clWidth = Math.min(textWidth, cMaxX - xDstSurf);
+                    } else {
+                        xSrcSurf += cMinX - xDstSurf;
+                        clWidth = Math.min(cMaxX - cMinX, textWidth - (cMinX - xDstSurf));
+                        xDstSurf = cMinX;
+                    }
+                    if (yDstSurf >= cMinY) {
+                        clHeight = Math.min(textHeight, cMaxY - yDstSurf);
+                    } else {
+                        ySrcSurf += cMinY - yDstSurf;
+                        clHeight = Math.min(cMaxY - cMinY, textHeight - (cMinY - yDstSurf));
+                        yDstSurf = cMinY;
+                    }
+                    //     Drawing on the Raster
+                    for (int h=0; h<clHeight; h++){
+                        for (int w=0; w < clWidth ; w++) {
+                            byte currByte = data[(ySrcSurf + h)*gl.bmp_pitch + (xSrcSurf+w)/8];
+                            boolean emptyByte = ((currByte & (1 << (7 - ((xSrcSurf+w) % 8)))) != 0);
+                            if (emptyByte) {
+                                raster.setDataElements(xDstSurf+w, yDstSurf+h, color);
+                            } else {
+                                // Nothing to do
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Draws string on specified raster at desired position.
+     *  
+     * @param raster specified WritableRaster to draw at
+     * @param color color of the text
+     * @param str text to draw
+     * @param font font peer to use for drawing text
+     * @param x start X position to draw
+     * @param y start Y position to draw
+     * @param cMinX minimum x of the raster area to draw
+     * @param cMinY minimum y of the raster area to draw
+     * @param cMaxX maximum x of the raster area to draw
+     * @param cMaxY maximum y of the raster area to draw
+     */    
+    public void drawClipString(WritableRaster raster, Object color, String str,
+            FontPeerImpl font, int x, int y, int cMinX, int cMinY, int cMaxX,
+            int cMaxY) {
+        // TODO: implement complex clipping
+
+        int xSrcSurf, ySrcSurf; // Start point in String rectangle
+        int xDstSurf, yDstSurf; // Start point in Surface rectangle
+        int clWidth, clHeight;
+
+        char[] chars = str.toCharArray();
+
+        int xBaseLine = x;
+        int yBaseLine = y;
+
+        for (char element : chars) {
+            Glyph gl = font.getGlyph(element);
+            GlyphMetrics pointMetrics = gl.getGlyphPointMetrics();
+            if (gl.getWidth() == 0) {
+                xBaseLine += pointMetrics.getAdvanceX();
+                continue;
+            }
+
+            byte[] data = gl.getBitmap();
+            if (data == null) {
+                xBaseLine += pointMetrics.getAdvanceX();
+            } else {
+
+                xSrcSurf = 0;
+                ySrcSurf = 0;
+
+                xDstSurf = Math.round(xBaseLine + gl.getGlyphPointMetrics().getLSB());
+                yDstSurf = yBaseLine - gl.bmp_top;
+
+                int textWidth = gl.bmp_width;
+                int textHeight = gl.getPointHeight();
+
+                // if Regions don't intersect
+                if ((xDstSurf > cMaxX) || (yDstSurf > cMaxY) || (xDstSurf + textWidth < cMinX)
+                        || (yDstSurf + textHeight < cMinY)) {
+                    // Nothing to do
+                } else {
+                    if (xDstSurf >= cMinX) {
+                        clWidth = Math.min(textWidth, cMaxX - xDstSurf);
+                    } else {
+                        xSrcSurf += cMinX - xDstSurf;
+                        clWidth = Math.min(cMaxX - cMinX, textWidth - (cMinX - xDstSurf));
+                        xDstSurf = cMinX;
+                    }
+                    if (yDstSurf >= cMinY) {
+                        clHeight = Math.min(textHeight, cMaxY - yDstSurf);
+                    } else {
+                        ySrcSurf += cMinY - yDstSurf;
+                        clHeight = Math.min(cMaxY - cMinY, textHeight - (cMinY - yDstSurf));
+                        yDstSurf = cMinY;
+                    }
+
+                    // Drawing on the Raster
+                    for (int h=0; h<clHeight; h++){
+                        for (int w=0; w < clWidth ; w++) {
+                            byte currByte = data[(ySrcSurf + h)*gl.bmp_pitch + (xSrcSurf+w)/8];
+                            boolean emptyByte = ((currByte & (1 << (7 - ((xSrcSurf+w) % 8)))) != 0);
+                            if (emptyByte) {
+                                raster.setDataElements(xDstSurf+w, yDstSurf+h, color);
+                            } else {
+                                // Nothing to do
+                            }
+                        }
+                    }
+                }
+                xBaseLine += pointMetrics.getAdvanceX();
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/render/NativeImageBlitter.java b/awt/org/apache/harmony/awt/gl/render/NativeImageBlitter.java
new file mode 100644
index 0000000..b0ebc97
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/NativeImageBlitter.java
@@ -0,0 +1,218 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 26.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.XORComposite;
+
+/**
+ * This kind of blitters is intended for drawing one image on the buffered
+ * or volatile image. For the moment we can blit natively Buffered Images which 
+ * have sRGB, Linear_RGB, Linear_Gray Color Space and type different 
+ * from BufferedImage.TYPE_CUSTOM, Volatile Images and Images which received 
+ * using Toolkit and Component classes.
+ */
+public class NativeImageBlitter implements Blitter {
+
+
+    final static NativeImageBlitter inst = new NativeImageBlitter();
+
+    public static NativeImageBlitter getInstance(){
+        return inst;
+    }
+
+    public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, AffineTransform sysxform,
+            AffineTransform xform, Composite comp, Color bgcolor,
+            MultiRectArea clip) {
+
+        if(!srcSurf.isNativeDrawable()){
+            JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+                    sysxform, xform, comp, bgcolor, clip);
+        }else{
+            if(xform == null){
+                blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+                        sysxform, comp, bgcolor, clip);
+            }else{
+                double scaleX = xform.getScaleX();
+                double scaleY = xform.getScaleY();
+                double scaledX = dstX / scaleX;
+                double scaledY = dstY / scaleY;
+                AffineTransform at = new AffineTransform();
+                at.setToTranslation(scaledX, scaledY);
+                xform.concatenate(at);
+                sysxform.concatenate(xform);
+                blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height,
+                        sysxform, comp, bgcolor, clip);
+            }
+        }
+    }
+
+    public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, AffineTransform sysxform,
+            Composite comp, Color bgcolor, MultiRectArea clip) {
+
+        if(!srcSurf.isNativeDrawable()){
+            JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+                    sysxform, comp, bgcolor, clip);
+        }else{
+            int type = sysxform.getType();
+            switch(type){
+                case AffineTransform.TYPE_TRANSLATION:
+                    dstX += sysxform.getTranslateX();
+                    dstY += sysxform.getTranslateY();
+                case AffineTransform.TYPE_IDENTITY:
+                    blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf,
+                            width, height, comp, bgcolor, clip);
+                    break;
+                default:
+                    // TODO Need to realize Affine Transformation
+                    if(srcSurf instanceof ImageSurface){
+                        JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY, 
+                                dstSurf, width, height,
+                                sysxform, comp, bgcolor, clip);
+                    }else{
+                        int w = srcSurf.getWidth();
+                        int h = srcSurf.getHeight();
+                        BufferedImage tmp = new BufferedImage(w, h, 
+                                BufferedImage.TYPE_INT_RGB);
+                        Surface tmpSurf = Surface.getImageSurface(tmp);
+                        blit(0, 0, srcSurf, 0, 0, tmpSurf,
+                                w, h, AlphaComposite.SrcOver, null, null);
+                        JavaBlitter.inst.blit(srcX, srcY, tmpSurf, dstX, dstY, 
+                                dstSurf, width, height,
+                                sysxform, comp, bgcolor, clip);
+                    }
+            }
+        }
+    }
+
+    public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, Composite comp,
+            Color bgcolor, MultiRectArea clip) {
+
+        if(!srcSurf.isNativeDrawable()){
+            JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+                    comp, bgcolor, clip);
+        }else{
+            long dstSurfStruct = dstSurf.getSurfaceDataPtr();
+            Object dstData = dstSurf.getData();
+            int clipRects[];
+            if(clip != null){
+                clipRects = clip.rect;
+            }else{
+                clipRects = new int[]{5, 0, 0, dstSurf.getWidth(),
+                        dstSurf.getHeight()};
+            }
+
+            if(!(srcSurf instanceof ImageSurface)){
+                srcSurf = srcSurf.getImageSurface();
+                if(bgcolor != null){
+                    bgcolor = null;
+                }
+            }
+
+            long srcSurfStruct = srcSurf.getSurfaceDataPtr();
+            Object srcData = srcSurf.getData();
+            if(comp instanceof AlphaComposite){
+                AlphaComposite ac = (AlphaComposite) comp;
+                int compType = ac.getRule();
+                float alpha = ac.getAlpha();
+                if(bgcolor != null){
+                    bltBG(srcX, srcY, srcSurfStruct, srcData,
+                            dstX, dstY, dstSurfStruct, dstData,
+                            width, height, bgcolor.getRGB(),
+                            compType, alpha, clipRects, srcSurf.invalidated());
+                    dstSurf.invalidate();
+                    srcSurf.validate();
+                }else{
+                    blt(srcX, srcY, srcSurfStruct, srcData,
+                            dstX, dstY, dstSurfStruct, dstData,
+                            width, height, compType, alpha,
+                            clipRects, srcSurf.invalidated());
+                    dstSurf.invalidate();
+                    srcSurf.validate();
+                }
+            }else if(comp instanceof XORComposite){
+                XORComposite xcomp = (XORComposite) comp;
+                xor(srcX, srcY, srcSurfStruct, srcData,
+                        dstX, dstY, dstSurfStruct, dstData,
+                        width, height, xcomp.getXORColor().getRGB(),
+                        clipRects, srcSurf.invalidated());
+                dstSurf.invalidate();
+                srcSurf.validate();
+            }else{
+                if(srcSurf instanceof ImageSurface){
+                    JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY, 
+                            dstSurf, width, height,
+                            comp, bgcolor, clip);
+                }else{
+                    int w = srcSurf.getWidth();
+                    int h = srcSurf.getHeight();
+                    BufferedImage tmp = new BufferedImage(w, h, 
+                            BufferedImage.TYPE_INT_RGB);
+                    Surface tmpSurf = Surface.getImageSurface(tmp);
+                    long tmpSurfStruct = tmpSurf.getSurfaceDataPtr();
+                    Object tmpData = tmpSurf.getData();
+                    int tmpClip[] = new int[]{5, 0, 0, srcSurf.getWidth(),
+                            srcSurf.getHeight()};
+                    
+                    blt(0, 0, srcSurfStruct, srcData, 0, 0,
+                            tmpSurfStruct, tmpData, w, h, 
+                            AlphaComposite.SRC_OVER,
+                            1.0f, tmpClip, srcSurf.invalidated());
+                    srcSurf.validate();
+                    JavaBlitter.inst.blit(srcX, srcY, tmpSurf, dstX, dstY, 
+                            dstSurf, width, height,
+                            comp, bgcolor, clip);
+                }
+            }
+        }
+
+    }
+
+    private native void bltBG(int srcX, int srcY, long srsSurfDataPtr,
+            Object srcData, int dstX, int dstY, long dstSurfDataPtr,
+            Object dstData, int width, int height, int bgcolor,
+            int compType, float alpha, int clip[], boolean invalidated);
+
+    private native void blt(int srcX, int srcY, long srsSurfDataPtr,
+            Object srcData, int dstX, int dstY, long dstSurfDataPtr,
+            Object dstData, int width, int height, int compType,
+            float alpha, int clip[], boolean invalidated);
+
+    private native void xor(int srcX, int srcY, long srsSurfDataPtr,
+            Object srcData, int dstX, int dstY, long dstSurfDataPtr,
+            Object dstData, int width, int height, int xorcolor,
+            int clip[], boolean invalidated);
+
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/NullBlitter.java b/awt/org/apache/harmony/awt/gl/render/NullBlitter.java
new file mode 100644
index 0000000..9032e4e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/NullBlitter.java
@@ -0,0 +1,56 @@
+/*
+ *  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.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 07.12.2005
+ *
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.geom.AffineTransform;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+
+
+public class NullBlitter implements Blitter {
+
+    static Blitter inst = new NullBlitter();
+    public static Blitter getInstance(){
+        return inst;
+    }
+
+    public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, AffineTransform sysxform,
+            AffineTransform xform, Composite comp, Color bgcolor,
+            MultiRectArea clip) {
+    }
+
+    public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, AffineTransform sysxform,
+            Composite comp, Color bgcolor, MultiRectArea clip) {
+    }
+
+    public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+            Surface dstSurf, int width, int height, Composite comp,
+            Color bgcolor, MultiRectArea clip) {
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/im/InputMethodContext.java b/awt/org/apache/harmony/awt/im/InputMethodContext.java
new file mode 100644
index 0000000..45ed11f
--- /dev/null
+++ b/awt/org/apache/harmony/awt/im/InputMethodContext.java
@@ -0,0 +1,563 @@
+/*
+ *  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.
+ */
+/** 
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.im;
+
+//???AWT
+import java.awt.AWTEvent;
+import java.awt.Component;
+//import java.awt.KeyboardFocusManager;
+import java.awt.Rectangle;
+//import java.awt.Window;
+import java.awt.event.FocusEvent;
+import java.awt.event.InputMethodEvent;
+import java.awt.event.KeyEvent;
+import java.awt.font.TextHitInfo;
+import java.awt.im.InputContext;
+import java.awt.im.InputMethodRequests;
+import java.awt.im.spi.InputMethod;
+import java.awt.im.spi.InputMethodDescriptor;
+import java.lang.Character.Subset;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+//???AWT
+//import javax.swing.JFrame;
+
+import org.apache.harmony.awt.wtk.NativeIM;
+
+/**
+ * Implementation of InputMethodContext
+ * interface, also provides all useful
+ * functionality of InputContext
+ * 
+ */
+public class InputMethodContext extends InputContext implements
+        java.awt.im.spi.InputMethodContext {    
+
+    //???AWT
+    private InputMethod inputMethod; // current IM
+    private Component client; // current "active" client component
+    //???AWT: private CompositionWindow composeWindow; // composition Window    
+    private final Map<InputMethodDescriptor, InputMethod> imInstances; // Map<InputMethodDescriptor, InputMethod>
+    private final Map<Locale, InputMethod> localeIM; // Map<Locale, InputMethod> last user-selected IM for locale
+    private final Set<InputMethod> notifyIM; // set of IMs to notify of client window bounds changes
+    
+    /**
+     * a flag indicating that IM should be notified of client window
+     * position/visibility changes as soon as it is activated(new client
+     * appears)
+     */    
+    private boolean pendingClientNotify;
+    private Component nextComp; // component to gain focus after endComposition()
+    //???AWT: private final Set<Window> imWindows; // set of all IM windows created by this instance
+    private final NativeIM nativeIM;
+    
+
+ 
+    public InputMethodContext() {
+        notifyIM = new HashSet<InputMethod>();
+//???AWT:        imWindows = new HashSet<Window>();
+        imInstances = new HashMap<InputMethodDescriptor, InputMethod>();
+        localeIM = new HashMap<Locale, InputMethod>();
+        selectInputMethod(Locale.US); // not default?
+        nativeIM = (NativeIM) inputMethod;
+    }
+
+    //???AWT
+    /*
+    @Override
+    public void dispatchEvent(AWTEvent event) {
+        int id = event.getID(); 
+        if ((id >= FocusEvent.FOCUS_FIRST) && (id <=FocusEvent.FOCUS_LAST)) {
+            dispatchFocusEvent((FocusEvent) event);
+        } else {
+            // handle special KEY_PRESSED
+            // event to show IM selection menu
+            if (id == KeyEvent.KEY_PRESSED) {
+                KeyEvent ke = (KeyEvent) event;
+                IMManager.selectIM(ke, this, 
+                                   IMManager.getWindow(ke.getComponent()));
+            }
+            // dispatch all input events to the current IM:
+            if (inputMethod != null) {
+                inputMethod.dispatchEvent(event);
+            }
+        }
+    }
+    
+    private void dispatchFocusEvent(FocusEvent fe) {
+        switch (fe.getID()) {
+        case FocusEvent.FOCUS_LOST:            
+            if (inputMethod != null) {
+                inputMethod.deactivate(fe.isTemporary());                
+            }
+            break;
+        case FocusEvent.FOCUS_GAINED:
+            
+            Component comp = fe.getComponent();
+            if (imWindows.contains(comp)) {
+                // prevent activating when IM windows
+                // attached to this context gain focus                
+                return;
+            }
+            InputMethodContext lastActive = IMManager.getLastActiveIMC();
+            if ((lastActive != this) && (lastActive != null)) {
+                lastActive.hideWindows();
+            }
+            if (inputMethod != null) {
+                activateIM(inputMethod);
+                if (!getCompositionWindow().isEmpty()) {
+                    IMManager.showCompositionWindow(composeWindow);
+                }
+                if (client == comp) {
+                    if (nextComp != null) {
+                        // temporarily got focus to
+                        // end composition
+                        endComposition();
+
+                        // transfer focus to new client
+                        client = nextComp;
+                        nextComp = null;
+                        client.requestFocusInWindow();
+                    }
+                } else if ((client != null) && getCompositionWindow().isVisible()) {
+                    // temporarily return focus back
+                    // to previous client to be able
+                    // to end composition
+                    nextComp = comp;
+                    client.requestFocusInWindow();
+                } else {
+                    client = comp;
+                }
+            }
+            if (pendingClientNotify) {
+                notifyClientWindowChange(IMManager.getWindow(comp).getBounds());
+            }
+            break;
+        }
+
+    }
+
+    private void activateIM(InputMethod im) {
+        im.activate();
+        if ((nativeIM != null) && (im != nativeIM)) {
+            // when Java IM is active
+            // native input method editor must be
+            // explicitly disabled
+            nativeIM.disableIME();
+        }
+        IMManager.setLastActiveIMC(this);
+    }
+
+    @SuppressWarnings("deprecation")
+    private void hideWindows() {
+        if (inputMethod != null) {
+            inputMethod.hideWindows();
+        }
+        if (composeWindow != null) {
+            composeWindow.hide();
+        }
+    }
+
+    private void createCompositionWindow() {
+        composeWindow = new CompositionWindow(client);        
+    }
+    
+    private CompositionWindow getCompositionWindow() {
+        if (composeWindow == null) {
+            createCompositionWindow();
+        }
+        composeWindow.setClient(client);
+        return composeWindow;        
+    }
+    */
+    
+    /**
+     * Gets input method requests for the current client
+     * irrespective of input style.
+     * @return input method requests of composition window if
+     * client is passive,
+     * otherwise input method requests of client
+     */
+    private InputMethodRequests getIMRequests() {
+        InputMethodRequests imRequests = null;
+    
+        if (client != null) {
+            imRequests = client.getInputMethodRequests();
+            //???AWT
+            /*
+            if (imRequests == null) {                
+                imRequests = getCompositionWindow().getInputMethodRequests();
+            }
+            */
+        }
+        
+        return imRequests;
+    }
+    
+    /**
+     * Gets input method requests for the current client & input style.
+     * @return input method requests of composition window if
+     * input style is "below-the-spot"(or client is passive),
+     * otherwise client input method requests
+     */
+    private InputMethodRequests getStyleIMRequests() {
+        //???AWT
+        /*
+        if (IMManager.belowTheSpot()) {
+            return getCompositionWindow().getInputMethodRequests();
+        }
+        */
+        return getIMRequests();
+    }
+    
+    @Override
+    public void dispose() {
+        if (inputMethod != null) {
+            closeIM(inputMethod);
+            inputMethod.dispose();
+        }
+        notifyIM.clear();
+        super.dispose();
+    }
+
+    @Override
+    public void endComposition() {
+        if (inputMethod != null) {
+            inputMethod.endComposition();
+        }
+        super.endComposition();
+    }
+
+    @Override
+    public Object getInputMethodControlObject() {
+        if (inputMethod != null) {
+            return inputMethod.getControlObject();
+        }
+        return super.getInputMethodControlObject();
+    }
+
+    @Override
+    public Locale getLocale() {
+        if (inputMethod != null) {
+            return inputMethod.getLocale();
+        }
+        return super.getLocale();
+    }
+
+    @Override
+    public boolean isCompositionEnabled() {
+        if (inputMethod != null) {
+            return inputMethod.isCompositionEnabled();
+        }
+        return super.isCompositionEnabled();
+    }
+
+    @Override
+    public void reconvert() {
+        if (inputMethod != null) {
+            inputMethod.reconvert();
+        }
+        super.reconvert();
+    }
+
+    //???AWT
+    /*
+    @Override
+    public void removeNotify(Component client) {
+        if ((inputMethod != null) && (client == this.client)) {
+            inputMethod.removeNotify();
+            client = null;
+            // set flag indicating that IM should be notified
+            // as soon as it is activated(new client appears)
+            pendingClientNotify = true;
+        }
+        
+        super.removeNotify(client);
+    }
+    */
+
+    @Override
+    public boolean selectInputMethod(Locale locale) {        
+        
+        if ((inputMethod != null) && inputMethod.setLocale(locale)) {
+            return true;
+        }
+        // first
+        // take last user-selected IM for locale            
+        InputMethod newIM = localeIM.get(locale);
+        
+        // if not found search through IM descriptors
+        // and take already created instance if exists
+        // or create, store new IM instance in descriptor->instance map
+        //???AWT
+        /*
+        if (newIM == null) {
+            try {
+                newIM = getIMInstance(IMManager.getIMDescriptors().iterator(),
+                                      locale);
+            } catch (Exception e) {
+                // ignore exceptions - just return false
+            }
+        }
+        */
+        
+        return switchToIM(locale, newIM);
+    }
+
+    private boolean switchToIM(Locale locale, InputMethod newIM) {
+        //???AWT
+        /*
+        if (newIM != null) {
+            closeIM(inputMethod);
+            client = KeyboardFocusManager.
+            getCurrentKeyboardFocusManager().getFocusOwner();
+            initIM(newIM, locale);
+            inputMethod = newIM;
+            
+            return true;
+        }
+        */
+        return false;
+    }
+    
+    /**
+     * Is called when IM is selected from UI
+     */
+    void selectIM(InputMethodDescriptor imd, Locale locale) {
+        try {
+            switchToIM(locale, getIMInstance(imd));            
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Gets input method instance for the given
+     * locale from the given list of descriptors
+     * @param descriptors iterator of the list of IM descriptors
+     * @param locale the locale to be supported by the IM
+     * @return input method instance
+     * @throws Exception
+     */
+    private InputMethod getIMInstance(Iterator<InputMethodDescriptor> descriptors,
+                                      Locale locale) throws Exception {
+        while (descriptors.hasNext()) {
+            InputMethodDescriptor desc = descriptors.next();
+            Locale[] locs = desc.getAvailableLocales();
+            for (Locale element : locs) {
+                if (locale.equals(element)) {
+                    return getIMInstance(desc);
+                }
+            }
+        }
+        return null;
+    }
+
+    private InputMethod getIMInstance(InputMethodDescriptor imd) throws Exception {
+        InputMethod im = imInstances.get(imd);
+        if (im == null) {
+            im = imd.createInputMethod();
+            im.setInputMethodContext(this);
+            imInstances.put(imd, im);
+        }
+        return im;
+    }
+    
+    private void initIM(InputMethod im, Locale locale) {
+        if (im == null) {
+            return;
+        }
+        im.setLocale(locale);
+        im.setCharacterSubsets(null);
+        //???AWT: activateIM(im);
+        try {
+            im.setCompositionEnabled(inputMethod != null ? 
+                                     inputMethod.isCompositionEnabled() : true);
+        } catch (UnsupportedOperationException uoe) {
+
+        }
+        
+    }
+
+    private void closeIM(InputMethod im) {
+        if (im == null) {
+            return;
+        }
+        if (im.isCompositionEnabled()) {
+            im.endComposition();
+        }
+        
+        im.deactivate(true);
+        im.hideWindows();
+        
+    }
+    
+    @Override
+    public void setCharacterSubsets(Subset[] subsets) {
+        if (inputMethod != null) {
+            inputMethod.setCharacterSubsets(subsets);
+        }
+        super.setCharacterSubsets(subsets);
+    }
+
+    @Override
+    public void setCompositionEnabled(boolean enable) {
+        if (inputMethod != null) {
+            inputMethod.setCompositionEnabled(enable);
+        }
+        super.setCompositionEnabled(enable);
+    }
+
+    //???AWT
+    /*
+    public JFrame createInputMethodJFrame(String title,
+                                          boolean attachToInputContext) {
+        JFrame jf = new IMJFrame(title, attachToInputContext ? this : null);
+        imWindows.add(jf);
+        return jf;
+    }
+
+    public Window createInputMethodWindow(String title,
+                                          boolean attachToInputContext) {
+        Window w = new IMWindow(title, attachToInputContext ? this : null);
+        imWindows.add(w);
+        return w;
+    }
+    */
+    
+    @SuppressWarnings("deprecation")
+    public void dispatchInputMethodEvent(int id,
+                                         AttributedCharacterIterator text,
+                                         int committedCharacterCount,
+                                         TextHitInfo caret,
+                                         TextHitInfo visiblePosition) {
+        if (client == null) {
+            return;
+        }
+        //???AWT
+        /*
+        InputMethodEvent ime = new InputMethodEvent(client, id, text,
+                                                    committedCharacterCount,
+                                                    caret, visiblePosition);
+        
+
+        if ((client.getInputMethodRequests() != null) &&
+            !IMManager.belowTheSpot()) {
+            
+            client.dispatchEvent(ime);
+        } else {
+            
+            // show/hide composition window if necessary
+            if (committedCharacterCount < text.getEndIndex()) {
+                IMManager.showCompositionWindow(getCompositionWindow());
+            } else {
+                getCompositionWindow().hide();
+            }
+            composeWindow.getActiveClient().dispatchEvent(ime);
+        }
+        */
+        
+    }
+
+    public void enableClientWindowNotification(InputMethod inputMethod,
+                                               boolean enable) {
+        if (enable) {
+            notifyIM.add(inputMethod);
+            //???AWT
+            /*
+            if (client != null) {
+                notifyClientWindowChange(IMManager.getWindow(client).getBounds());
+            } else {
+                pendingClientNotify = true;
+            }
+            */
+        } else {
+            notifyIM.remove(inputMethod);
+        }
+        
+    }
+
+    public AttributedCharacterIterator cancelLatestCommittedText(
+                                                                 Attribute[] attributes) {
+        return getIMRequests().cancelLatestCommittedText(attributes);
+    }
+
+    public AttributedCharacterIterator getCommittedText(int beginIndex,
+                                                        int endIndex,
+                                                        Attribute[] attributes) {
+        return getIMRequests().getCommittedText(beginIndex, endIndex,
+                                                attributes);
+    }
+
+    public int getCommittedTextLength() {
+        return getIMRequests().getCommittedTextLength();
+    }
+
+    public int getInsertPositionOffset() {
+        return getIMRequests().getInsertPositionOffset();
+    }
+
+    public TextHitInfo getLocationOffset(int x, int y) {
+        InputMethodRequests imr = getStyleIMRequests();
+        if (imr != null) {
+            return imr.getLocationOffset(x, y);
+        }
+        return null;
+    }
+
+    public AttributedCharacterIterator getSelectedText(Attribute[] attributes) {
+        return getIMRequests().getSelectedText(attributes);
+    }
+
+    public Rectangle getTextLocation(TextHitInfo offset) {        
+        return getStyleIMRequests().getTextLocation(offset);
+    }
+    
+    /**
+     * To be called by AWT when client Window's bounds/visibility/state
+     * change
+     */
+    public void notifyClientWindowChange(Rectangle bounds) {
+        if (notifyIM.contains(inputMethod)) {
+            inputMethod.notifyClientWindowChange(bounds);
+        }
+        pendingClientNotify = false;
+    }
+
+    public final InputMethod getInputMethod() {
+        return inputMethod;
+    }
+
+    public final Component getClient() {
+        return client;
+    }
+
+    public final NativeIM getNativeIM() {
+        return nativeIM;
+    }
+}
diff --git a/awt/org/apache/harmony/awt/internal/nls/Messages.java b/awt/org/apache/harmony/awt/internal/nls/Messages.java
new file mode 100644
index 0000000..c340358
--- /dev/null
+++ b/awt/org/apache/harmony/awt/internal/nls/Messages.java
@@ -0,0 +1,151 @@
+/* 
+ * 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.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten 
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+package org.apache.harmony.awt.internal.nls;
+
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+// BEGIN android-deleted
+/*
+ * For Android, this module is a separate library and not part of the
+ * boot classpath, so its resources won't be found on the boot classpath
+ * as is assumed by MsgHelp.getString(). We instead use a local MsgHelp
+ * which bottoms out in a call to the useful part of its lower-level
+ * namesake.
+ */
+//import org.apache.harmony.kernel.vm.VM;
+//import org.apache.harmony.luni.util.MsgHelp;
+// END android-deleted
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ *    org.apache.harmony.awt.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ * 
+ */
+public class Messages {
+
+    // BEGIN android-deleted
+    //private static final String sResource =
+    //    "org.apache.harmony.awt.internal.nls.messages";
+    // END android-deleted
+
+    /**
+     * Retrieves a message which has no arguments.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg) {
+        // BEGIN android-changed
+        return MsgHelp.getString(msg);
+        // END android-changed
+    }
+
+    /**
+     * Retrieves a message which takes 1 argument.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg
+     *            Object the object to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, Object arg) {
+        return getString(msg, new Object[] { arg });
+    }
+
+    /**
+     * Retrieves a message which takes 1 integer argument.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg
+     *            int the integer to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, int arg) {
+        return getString(msg, new Object[] { Integer.toString(arg) });
+    }
+
+    /**
+     * Retrieves a message which takes 1 character argument.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg
+     *            char the character to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, char arg) {
+        return getString(msg, new Object[] { String.valueOf(arg) });
+    }
+
+    /**
+     * Retrieves a message which takes 2 arguments.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg1
+     *            Object an object to insert in the formatted output.
+     * @param arg2
+     *            Object another object to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, Object arg1, Object arg2) {
+        return getString(msg, new Object[] { arg1, arg2 });
+    }
+
+    /**
+     * Retrieves a message which takes several arguments.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param args
+     *            Object[] the objects to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, Object[] args) {
+        // BEGIN android-changed
+        return MsgHelp.getString(msg, args);
+        // END android-changed
+    }
+
+    // BEGIN android-note
+    // Duplicate code was dropped in favor of using MsgHelp.
+    // END android-note
+}
diff --git a/awt/org/apache/harmony/awt/internal/nls/MsgHelp.java b/awt/org/apache/harmony/awt/internal/nls/MsgHelp.java
new file mode 100644
index 0000000..b57fe11
--- /dev/null
+++ b/awt/org/apache/harmony/awt/internal/nls/MsgHelp.java
@@ -0,0 +1,86 @@
+/*
+ *  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.
+ */
+
+/*
+ * This implementation is based on the class of the same name in
+ * org.apache.harmony.luni.util.
+ */
+
+package org.apache.harmony.awt.internal.nls;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.logging.Logger;
+import java.util.Locale;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+import java.util.MissingResourceException;
+
+/**
+ * This class contains helper methods for loading resource bundles and
+ * formatting external message strings.
+ */
+public final class MsgHelp {
+    /** name of the resource for this class */
+    private static final String RESOURCE_NAME =
+        "/org/apache/harmony/awt/internal/nls/messages.properties";
+
+    /** the resource bundle for this class */
+    private static final ResourceBundle THE_BUNDLE;
+
+    static {
+        ResourceBundle rb = null;
+
+        try {
+            InputStream in = MsgHelp.class.getResourceAsStream(
+                    RESOURCE_NAME);
+            rb = new PropertyResourceBundle(in);
+        } catch (IOException ex) {
+            Logger.global.warning("Couldn't read resource bundle: " +
+                    ex);
+        } catch (RuntimeException ex) {
+            // Shouldn't happen, but deal at least somewhat gracefully.
+            Logger.global.warning("Couldn't find resource bundle: " +
+                    ex);
+        }
+
+        THE_BUNDLE = rb;
+    }
+    
+    public static String getString(String msg) {
+        if (THE_BUNDLE == null) {
+            return msg;
+        }
+        try {
+            return THE_BUNDLE.getString(msg);
+        } catch (MissingResourceException e) {
+            return "Missing message: " + msg;
+        }
+    }
+    
+    static public String getString(String msg, Object[] args) {
+        String format = msg;
+        if (THE_BUNDLE != null) {
+            try {
+                format = THE_BUNDLE.getString(msg);
+            } catch (MissingResourceException e) {
+            }
+        }
+
+        return org.apache.harmony.luni.util.MsgHelp.format(format, args);
+    }
+}
diff --git a/awt/org/apache/harmony/awt/state/MenuItemState.java b/awt/org/apache/harmony/awt/state/MenuItemState.java
new file mode 100644
index 0000000..b13e50b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/state/MenuItemState.java
@@ -0,0 +1,51 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.state;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+
+/**
+ * State of menu item
+ */
+
+public interface MenuItemState {
+
+    String getText();
+    Rectangle getTextBounds();
+    void setTextBounds(int x, int y, int w, int h);
+
+    String getShortcut();
+    Rectangle getShortcutBounds();
+    void setShortcutBounds(int x, int y, int w, int h);
+
+    Rectangle getItemBounds();
+    void setItemBounds(int x, int y, int w, int h);
+
+    boolean isMenu();
+    boolean isChecked();
+    boolean isEnabled();
+
+    boolean isCheckBox();
+    boolean isSeparator();
+
+    Dimension getMenuSize();
+}
diff --git a/awt/org/apache/harmony/awt/state/MenuState.java b/awt/org/apache/harmony/awt/state/MenuState.java
new file mode 100644
index 0000000..564a49a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/state/MenuState.java
@@ -0,0 +1,46 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.state;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Point;
+
+/**
+ * State of pop-up or drop-down menu
+ */
+
+public interface MenuState {
+    int getWidth();
+    int getHeight();
+    Point getLocation();
+
+    void setSize(int w, int h);
+
+    Font getFont();
+    boolean isFontSet();
+    FontMetrics getFontMetrics(Font f);
+
+    int getItemCount();
+    int getSelectedItemIndex();
+
+    MenuItemState getItem(int index);
+}
diff --git a/awt/org/apache/harmony/awt/state/State.java b/awt/org/apache/harmony/awt/state/State.java
new file mode 100644
index 0000000..4b8706d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/state/State.java
@@ -0,0 +1,55 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.state;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Rectangle;
+
+/**
+ * State of the component
+ */
+public interface State {
+
+    boolean isEnabled();
+    boolean isVisible();
+    boolean isFocused();
+
+    Font getFont();
+    boolean isFontSet();
+    FontMetrics getFontMetrics();
+
+    Color getBackground();
+    boolean isBackgroundSet();
+
+    Color getTextColor();
+    boolean isTextColorSet();
+
+    Rectangle getBounds();
+    Dimension getSize();
+
+    Dimension getDefaultMinimumSize();
+    void setDefaultMinimumSize(Dimension size);
+
+    long getWindowId();
+}
diff --git a/awt/org/apache/harmony/awt/wtk/CreationParams.java b/awt/org/apache/harmony/awt/wtk/CreationParams.java
new file mode 100644
index 0000000..63c581d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/CreationParams.java
@@ -0,0 +1,133 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+/**
+ * This class describes cross-platform NativeWindow creation params
+ * See also WindowFactory.createWindow
+ */
+public class CreationParams {
+    /**
+     * Initial state is maximized verticaly
+     */
+    public final long MAXIMIZED_VERT = 1;
+    /**
+     * Initial state is maximized horizontaly
+     */
+    public final long MAXIMIZED_HORIZ = 2;
+    /**
+     * Initial state is maximized both
+     * horizontaly and verticaly
+     */
+    public final long MAXIMIZED = 3;
+
+    /**
+     * The top-level window that has all possible decorations,
+     * has no owner and is displayed in taskbar
+     */
+    public final static int DECOR_TYPE_FRAME = 1;
+    /**
+     * The dialog window
+     */
+    public final static int DECOR_TYPE_DIALOG = 2;
+    /**
+     * The transient undecorated pop-up window
+     */
+    public final static int DECOR_TYPE_POPUP = 3;
+    /**
+     * The undecoraded pop-up window
+     */
+    public final static int DECOR_TYPE_UNDECOR = 4;
+    /**
+     * Non-MDI child window
+     */
+    public final static int DECOR_TYPE_NONE = 0;
+
+    /**
+     * Initial x.
+     */
+    public int x = 0;
+    /**
+     * Initial y.
+     */
+    public int y = 0;
+    /**
+     * Initial width.
+     */
+    public int w = 1;
+    /**
+     * Initial height.
+     */
+    public int h = 1;
+    /**
+     * The decoration type of the top-level window. The possible values are:
+     * DECOR_TYPE_FRAME, DECOR_TYPE_DIALOG, DECOR_TYPE_POPUP and DECOR_TYPE_UNDECOR
+     */
+    public int decorType = DECOR_TYPE_NONE;
+    /**
+     * Window is child of parent, otherwise it's
+     * toplevel(child of desktop) window owned by parent.
+     */
+    public boolean child = false;
+    /**
+     * Window is resizable
+     */
+    public boolean resizable = true;
+    /**
+     * The window has no decorations
+     */
+    public boolean undecorated = false;
+    /**
+     * Initial visibility state.
+     */
+    public boolean visible = false;
+    /**
+     * Window is ALWAYS topmost in Z order.
+     */
+    public boolean topmost = false;
+    /**
+     * Window is disabled.
+     */
+    public boolean disabled = false;
+    /**
+     * Window initially iconified.
+     */
+    public boolean iconified = false;
+    /**
+     * Bitwise OR of MAXIMIZED_* constants.
+     * Means if window is initially maximized.
+     */
+    public int maximizedState = 0;
+    /**
+     * Tells that window position should be determined by native windowing system 
+     */
+    public boolean locationByPlatform = false;
+    /**
+     * Id of parent or owner window, see child field
+     * For non-child window without owner equals 0.
+     */
+    public long parentId = 0;
+    /**
+     * Name wich is displayed on titlebar, taskbar and visible
+     * for system requests.
+     */
+    public String name = null;
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/wtk/CursorFactory.java b/awt/org/apache/harmony/awt/wtk/CursorFactory.java
new file mode 100644
index 0000000..35e7d33
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/CursorFactory.java
@@ -0,0 +1,85 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Dimension;
+import java.awt.Image;
+
+/**
+ * Provides factory for NativeCursor
+ */
+public abstract class CursorFactory {
+    protected NativeCursor[] systemCursors = {
+            null, null, null, null,
+            null, null, null, null,
+            null, null, null, null,
+            null, null,
+    };
+    /**
+     * Creates and returns NativeCursor for predefined
+     * Java Cursor
+     *
+     * @param type - type of predefined Java Cursor
+     * @return created cursor
+     */
+    public abstract NativeCursor createCursor(int type);
+
+    /**
+     * Gets a cached instance of system(predefined) native cursor
+     * or creates a new one. This is a platform-independent method.
+     *
+     * @param type - type of predefined Java Cursor
+     * @return created cursor
+     */
+    public NativeCursor getCursor(int type) {
+        if (type >= 0 && type < systemCursors.length) {
+            NativeCursor cursor = systemCursors[type];
+            if (cursor == null) {
+                cursor = createCursor(type);
+                systemCursors[type] = cursor;
+            }
+            return cursor;
+        }
+        return null;
+    }
+    /**
+     * Creates and returns custom NativeCursor from image
+     *
+     * @param img - image(source) to create cursor from
+     * @param xHotSpot - x coordinate of the hotspot relative to the source's origin
+     * @param yHotSpot - y coordinate of the hotspot relative to the source's origin
+     * @return created cursor
+     */
+    public abstract NativeCursor createCustomCursor(Image img, int xHotSpot, int yHotSpot);
+
+    /**
+     * Query native system for the best cursor size closest to specified dimensions
+     * @param prefWidth - preferred width
+     * @param prefHeight - preferred height
+     * @return closest supported dimensions to ones specified
+     */
+    public abstract Dimension getBestCursorSize(int prefWidth, int prefHeight);
+
+    /**
+     * @return maximum number of colors supported by custom cursors
+     */
+    public abstract int getMaximumCursorColors();
+}
diff --git a/awt/org/apache/harmony/awt/wtk/GraphicsFactory.java b/awt/org/apache/harmony/awt/wtk/GraphicsFactory.java
new file mode 100644
index 0000000..0d7c84f
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/GraphicsFactory.java
@@ -0,0 +1,82 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov, Alexey A. Petrenko, Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.peer.FontPeer;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.font.FontManager;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+
+/**
+ * GraphicsFactory interface defines methods for Graphics2D 
+ * and font stuff instances factories.
+ */
+public interface GraphicsFactory {
+    static final FontMetrics cacheFM[] =  new FontMetrics[10];
+    
+    /**
+     * This method creates Graphics2D instance for specified native window.
+     *  
+     * @param win Native window to draw
+     * @param translateX Translation along X axis
+     * @param translateY Translation along Y axis
+     * @param clip Clipping area for a new Graphics2D instance
+     * @return New Graphics2D instance for specified native window
+     * @deprecated
+     */
+    @Deprecated
+    Graphics2D getGraphics2D(NativeWindow win, int translateX, int translateY, MultiRectArea clip);
+
+    /**
+     * This method creates Graphics2D instance for specified native window.
+     *  
+     * @param win Native window to draw
+     * @param translateX Translation along X axis
+     * @param translateY Translation along Y axis
+     * @param width Width of drawing area
+     * @param height Height of drawing area
+     * @return New Graphics2D instance for specified native window
+     */
+    Graphics2D getGraphics2D(NativeWindow win, int translateX, int translateY, int width, int height);
+    // ???AWT: not standard harmony
+    Graphics2D getGraphics2D(Canvas c, Paint p);
+    
+    /**
+     * Creates instance of GraphicsEnvironment for specified WindowFactory
+     *  
+     * @param wf WindowFactory
+     * @return New instance of GraphicsEnvironment
+     */
+    GraphicsEnvironment createGraphicsEnvironment(WindowFactory wf);
+    
+    // Font methods
+    FontMetrics getFontMetrics(Font font);
+    FontManager getFontManager();
+    FontPeer getFontPeer(Font font);
+    Font embedFont(String fontFilePath);
+}
diff --git a/awt/org/apache/harmony/awt/wtk/KeyInfo.java b/awt/org/apache/harmony/awt/wtk/KeyInfo.java
new file mode 100644
index 0000000..1f8a29a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/KeyInfo.java
@@ -0,0 +1,53 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.event.KeyEvent;
+
+/**
+ * Keystroke information
+ */
+
+public final class KeyInfo {
+
+    public int vKey;
+    public int keyLocation;
+    public final StringBuffer keyChars;
+
+    public static final int DEFAULT_VKEY = KeyEvent.VK_UNDEFINED;
+    public static final int DEFAULT_LOCATION = KeyEvent.KEY_LOCATION_STANDARD;
+
+    public KeyInfo() {
+        vKey = DEFAULT_VKEY;
+        keyLocation = DEFAULT_LOCATION;
+        keyChars = new StringBuffer();
+    }
+
+    public void setKeyChars(char ch) {
+        keyChars.setLength(0);
+        keyChars.append(ch);
+    }
+
+    public void setKeyChars(StringBuffer sb) {
+        keyChars.setLength(0);
+        keyChars.append(sb);
+    }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeCursor.java b/awt/org/apache/harmony/awt/wtk/NativeCursor.java
new file mode 100644
index 0000000..2c6eb1e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeCursor.java
@@ -0,0 +1,45 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+/**
+ * The interface provides access to platform dependent functionality
+ * for the class java.awt.Cursor.
+ */
+public interface NativeCursor {
+    /**
+     * Sets the current cursor shape
+     * to this cursor when a pointer is inside
+     * @param winID - window(currently used only on X11)
+     */
+    void setCursor(long winID);
+    /**
+     * Destroys the native resource associated with
+     * this cursor
+     */
+    void destroyCursor();
+
+    /**
+     * @return Native handle associated with this cursor
+     */
+    long getId();
+
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeEvent.java b/awt/org/apache/harmony/awt/wtk/NativeEvent.java
new file mode 100644
index 0000000..1471c1a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeEvent.java
@@ -0,0 +1,268 @@
+/*
+ *  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.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.awt.event.KeyEvent;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+
+
+/**
+ * The interface describing cross-platform translation of system
+ * messages.
+ *
+ * <p/>Some messages can appear only on specific platform,
+ * but they still can have cross-platform interpretation if the
+ * application should be aware of them and can react using
+ * cross-platform API.
+ *
+ */
+public abstract class NativeEvent {
+
+    /**
+     * Message has no common cross-platform
+     * interpretation and should be skipped.
+     */
+    public static final int ID_PLATFORM = 0;
+
+    /**
+     * Window bounds have changed.
+     */
+    public static final int ID_BOUNDS_CHANGED = -1;
+
+    /**
+     * Window decoration size has changed.
+     */
+    public static final int ID_INSETS_CHANGED = -2;
+
+    /**
+     * Window was just created (WM_CREATE on Windows)
+     */
+    public static final int ID_CREATED = -3;
+
+    /**
+     * Mouse grab was canceled by the native system
+     */
+    public static final int ID_MOUSE_GRAB_CANCELED = -4;
+
+    /**
+     * System color scheme or visual theme was changed
+     */
+    public static final int ID_THEME_CHANGED = -5;
+
+    protected long windowId;
+    protected int eventId;
+    protected long otherWindowId;
+
+    protected Point screenPos;
+    protected Point localPos;
+    protected Rectangle windowRect;
+
+    protected int modifiers;
+    protected int mouseButton;
+    protected int wheelRotation;
+
+    protected KeyInfo keyInfo = new KeyInfo();
+
+    protected int windowState = -1;
+    protected long time;
+
+    /**
+     * Returns the system window id of the event recipient.
+     * @return HWND on Windows, xwindnow on X
+     */
+    public long getWindowId() {
+        return windowId;
+    }
+
+    /**
+     * Returns cross-platform event id
+     * should be one of ID_* constants or
+     * id constants from java.awt.AWTEvent subclasess
+     * @return cross-platform event id
+     */
+    public int getEventId() {
+        return eventId;
+    }
+
+    /**
+     * Returns the position of cursor when event occured relative to
+     * top-left corner of recipient window
+     * @return position of cursor in local coordinates
+     */
+    public Point getLocalPos() {
+        return localPos;
+    }
+
+    /**
+     * Returns the position of cursor when event occured
+     * in screen coordinates.
+     * @return position of cursor in screen coordinates
+     */
+    public Point getScreenPos() {
+        return screenPos;
+    }
+
+    /**
+     * The recipient window bounds when the event occured
+     * @return window bounds
+     */
+    public Rectangle getWindowRect() {
+        return windowRect;
+    }
+
+    /**
+     * Returns the state of keyboard and mouse buttons when the event
+     * occured if event from mouse or keyboard, for other events can
+     * return junk values. The value is bitwise OR of
+     * java.awt.event.InputEvent *_DOWN constants.
+     *
+     * Method is aware of system mouse button swap for left-hand
+     * mouse and return swapped values.
+     * @return bitwise OR of java.awt.event.InputEvent *_DOWN constants
+     */
+    public int getInputModifiers() {
+        return modifiers;
+    }
+
+    /**
+     * Returns the iconified/maximized state of recipient window if
+     * event is state related, for other events can junk values.
+     * The value has the same meaning as Frame.getExtendedState
+     * It's bitwise OR of ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT
+     * @return bitwise OR of ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT
+     */
+    public int getWindowState() {
+        return windowState;
+    }
+
+    /**
+     * The same meaning as java.awt.event.getKeyCode
+     * @return java.awt.event VK_* constant
+     */
+    public int getVKey() {
+        return (keyInfo != null) ? keyInfo.vKey : KeyInfo.DEFAULT_VKEY;
+    }
+
+    /**
+     * The same meaning as java.awt.event.getKeyLocation
+     * @return java.awt.event KEY_LOCATION_* constant
+     */
+    public int getKeyLocation() {
+        return (keyInfo != null) ? keyInfo.keyLocation : KeyInfo.DEFAULT_LOCATION;
+    }
+
+    /**
+     * Return the string of characters associated with the event
+     * Has meaning only for KEY_PRESSED as should be translated to
+     * serie of KEY_TYPED events. For dead keys and input methods
+     * one key press can generate multiple key chars.
+     * @return string of characters
+     */
+    public StringBuffer getKeyChars() {
+        if (keyInfo == null) {
+            return null;
+        }
+        if (keyInfo.vKey == KeyEvent.VK_ENTER) {
+            keyInfo.keyChars.setLength(0);
+            keyInfo.setKeyChars('\n');
+        }
+        return keyInfo.keyChars;
+    }
+
+    public char getLastChar() {
+        if (keyInfo == null || keyInfo.keyChars.length() == 0) {
+            return KeyEvent.CHAR_UNDEFINED;
+        }
+        return keyInfo.keyChars.charAt(keyInfo.keyChars.length()-1);
+    }
+
+    /**
+     * Returns the number of mouse button which changed it's state,
+     * otherwise 0.
+     * Left button is 1, middle button is 2, right button is 3.
+     *
+     * Method is aware of system mouse button swap for left-hand
+     * mouse and return swapped values.
+     * @return mouse button number
+     */
+    public int getMouseButton() {
+        return mouseButton;
+    }
+
+    /**
+     * Returns time when the message was received
+     * @return time in milliseconds
+     */
+    public long getTime() {
+        return time;
+    }
+
+    /**
+     * For the focus event contains the oposite window.
+     * This means it lost focus if recipient gains it,
+     * or will gain focus if recipient looses it.
+     * @return HWND on Windows, xwindnow on X
+     */
+    public long getOtherWindowId() {
+        return otherWindowId;
+    }
+
+    /**
+     * Returns the "dirty" area of the window as set of non-intersecting
+     * rectangles. This area is to be painted.
+     * @return non-empty array of null if empty
+     */
+    public abstract MultiRectArea getClipRects();
+
+    /**
+     * Returns the "dirty" area of the window as one rectangle.
+     * This area is to be painted.
+     * @return non-null Rectangle
+     */
+    public abstract Rectangle getClipBounds();
+
+    /**
+     * Returns the window insets. Insets is area which belongs to
+     * window somehow but is outside of it's client area,
+     * it usually contains system provided border and titlebar.
+     * @return non-null java.awt.Insets
+     */
+    public abstract Insets getInsets();
+
+    /**
+     * Returns true if event is popup menu trigger.
+     * @return boolean flag
+     */
+    public abstract boolean getTrigger();
+
+    /**
+     * Returns the number of "clicks" the mouse wheel was rotated.
+     * @return negative values if the mouse wheel was rotated up/away from the user,
+     * and positive values if the mouse wheel was rotated down/ towards the user
+     */
+    public int getWheelRotation() {
+        return wheelRotation;
+    }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeEventQueue.java b/awt/org/apache/harmony/awt/wtk/NativeEventQueue.java
new file mode 100644
index 0000000..0738cd1
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeEventQueue.java
@@ -0,0 +1,117 @@
+/*
+ *  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.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.util.LinkedList;
+
+
+/**
+ * Describes the cross-platform native event queue interface
+ *
+ * <p/> The implementation constructor should remember thread it was
+ * created. All other methods would be called obly from this thread,
+ * except awake().
+ */
+public abstract class NativeEventQueue {
+    
+    private ShutdownWatchdog shutdownWatchdog;
+    private class EventMonitor {}
+    private final Object eventMonitor = new EventMonitor();
+    private final LinkedList<NativeEvent> eventQueue = new LinkedList<NativeEvent>();
+
+    public static abstract class Task {
+        public volatile Object returnValue;
+
+        public abstract void perform();
+    }
+    
+    /**
+     * Blocks current thread until native event queue is not empty
+     * or awaken from other thread by awake().
+     *
+     * <p/>Should be called only on tread which
+     * will process native events.
+     *
+     * @return if event loop should be stopped
+     */
+    public abstract boolean waitEvent();
+
+    /**
+     * Determines whether or not the native event queue is empty.
+     * An queue is empty if it contains no messages waiting.
+     *
+     * @return true if the queue is empty; false otherwise
+     */
+    public boolean isEmpty() {
+        synchronized(eventQueue) {
+            return eventQueue.isEmpty();
+        }
+    }
+
+    public NativeEvent getNextEvent() {
+        synchronized (eventQueue) {
+            if (eventQueue.isEmpty()) {
+                shutdownWatchdog.setNativeQueueEmpty(true);
+                return null;
+            }
+            return eventQueue.remove(0);
+        }
+    }
+    
+    protected void addEvent(NativeEvent event) {
+        synchronized (eventQueue) {
+            eventQueue.add(event);
+            shutdownWatchdog.setNativeQueueEmpty(false);
+        }
+        synchronized (eventMonitor) {
+            eventMonitor.notify();
+        }
+    }
+
+    public final Object getEventMonitor() {
+        return eventMonitor;
+    }
+
+    public abstract void awake();
+
+    /**
+     * Gets AWT system window ID.
+     *
+     * @return AWT system window ID
+     */
+    public abstract long getJavaWindow();
+
+    /**
+     * Add NativeEvent to the queue
+     */
+    public abstract void dispatchEvent();
+
+    public abstract void performTask(Task task);
+
+    public abstract void performLater(Task task);
+    
+    public final void setShutdownWatchdog(ShutdownWatchdog watchdog) {
+        synchronized (eventQueue) {
+            shutdownWatchdog = watchdog;
+        }
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeEventThread.java b/awt/org/apache/harmony/awt/wtk/NativeEventThread.java
new file mode 100644
index 0000000..d50add4
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeEventThread.java
@@ -0,0 +1,78 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+
+/**
+ * NativeEventThread
+ */
+public class NativeEventThread extends Thread {
+    
+    public interface Init {
+        WTK init();
+    }
+    
+    NativeEventQueue nativeQueue;
+    Init init;
+    
+    private WTK wtk;
+    
+    public NativeEventThread() {
+        super("AWT-NativeEventThread"); //$NON-NLS-1$
+        setDaemon(true);
+    }
+
+    @Override
+    public void run() {
+        synchronized (this) {
+            try {
+                wtk = init.init();
+                nativeQueue = wtk.getNativeEventQueue();
+            } finally {
+                notifyAll();
+            }
+        }
+        
+        runModalLoop();
+    }
+
+    void runModalLoop() {
+        while (nativeQueue.waitEvent()) {
+            nativeQueue.dispatchEvent();
+        }
+    }
+    
+    public void start(Init init) {
+        synchronized (this) {
+            this.init = init;
+            super.start();
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+    
+    public WTK getWTK() {
+        return wtk;
+    }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeIM.java b/awt/org/apache/harmony/awt/wtk/NativeIM.java
new file mode 100644
index 0000000..1626f4a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeIM.java
@@ -0,0 +1,130 @@
+/*
+ *  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.
+ */
+/** 
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.AWTEvent;
+import java.awt.AWTException;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.im.spi.InputMethod;
+import java.awt.im.spi.InputMethodContext;
+import java.awt.im.spi.InputMethodDescriptor;
+import java.lang.Character.Subset;
+import java.util.Locale;
+
+/**
+ * A cross-platform interface for native input
+ * method sub-system functionality.
+ */
+public abstract class NativeIM implements InputMethod, InputMethodDescriptor {
+    protected InputMethodContext imc;
+
+    public void activate() {
+
+    }
+
+    public void deactivate(boolean isTemporary) {
+
+    }
+
+    public void dispatchEvent(AWTEvent event) {
+
+    }
+
+    public void dispose() {
+
+    }
+
+    public void endComposition() {
+
+    }
+
+    public Object getControlObject() {
+        return null;
+    }
+
+    public Locale getLocale() {
+        return null;
+    }
+
+    public void hideWindows() {
+
+    }
+
+    public boolean isCompositionEnabled() {
+        return false;
+    }
+
+    public void notifyClientWindowChange(Rectangle bounds) {
+
+    }
+
+    public void reconvert() {
+
+    }
+
+    public void removeNotify() {
+
+    }
+
+    public void setCharacterSubsets(Subset[] subsets) {
+
+    }
+    
+    public void setCompositionEnabled(boolean enable) {
+
+    }
+
+    public void setInputMethodContext(InputMethodContext context) {
+        imc = context;
+    }
+
+    public boolean setLocale(Locale locale) {
+        return false;
+    }
+
+    public Locale[] getAvailableLocales() throws AWTException {
+    	return new Locale[]{Locale.getDefault(), Locale.ENGLISH};
+        //return new Locale[]{Locale.getDefault(), Locale.US};
+    }
+
+    public InputMethod createInputMethod() throws Exception {        
+        return this;
+    }
+
+    public String getInputMethodDisplayName(Locale inputLocale,
+                                            Locale displayLanguage) {
+        return "System input methods"; //$NON-NLS-1$
+    }
+
+    public Image getInputMethodIcon(Locale inputLocale) {
+        return null;
+    }
+
+    public boolean hasDynamicLocaleList() {
+        return false;
+    }
+    
+    public abstract void disableIME();
+    
+//    public abstract void disableIME(long id);
+
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeMouseInfo.java b/awt/org/apache/harmony/awt/wtk/NativeMouseInfo.java
new file mode 100644
index 0000000..0696975
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeMouseInfo.java
@@ -0,0 +1,42 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Point;
+
+/**
+ * The interface provides access to platform dependent functionality
+ * for classes java.awt.PointerInfo & java.awt.MouseInfo.
+ */
+public interface NativeMouseInfo {
+
+    /**
+     * Returns the Point that represents
+     * the coordinates of the pointer on the screen.
+     */
+    Point getLocation();
+
+    /**
+     * Returns the number of buttons on the mouse.
+     * If no mouse is installed returns -1.
+     */
+    int getNumberOfButtons();
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeRobot.java b/awt/org/apache/harmony/awt/wtk/NativeRobot.java
new file mode 100644
index 0000000..0b354d0
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeRobot.java
@@ -0,0 +1,75 @@
+/*
+ *  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.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+
+/**
+ * A cross-platform interface for java.awt.Robot implementation
+ */
+public interface NativeRobot {
+
+    /**
+     * @see java.awt.Robot#createScreenCapture(Rectangle)
+     * @param screenRect rectangle to capture in screen coordinates
+     * @return the captured image or null if
+     * capture failed.
+     */
+    BufferedImage createScreenCapture(Rectangle screenRect);
+
+    /**
+     * @see java.awt.Robot#getPixelColor(int, int)
+     */
+    Color getPixel(int x, int y);
+
+    /**
+     * Generate a native system keyboard input event.
+     * @param keycode A Java virtual key code
+     * @param press A key is pressed if true, released otherwise
+     * @see java.awt.Robot#keyPress(int)
+     * @throws IllegalArgumentException if keycode is invalid in the native system
+     */
+    void keyEvent(int keycode, boolean press);
+
+    /**
+     * Generate a native system mouse button(s) press or release event.
+     * @param buttons A mask of Java mouse button flags
+     * @param press buttons are pressed if true, released otherwise
+     * @see java.awt.Robot#mousePress(int)
+     */
+    void mouseButton(int buttons, boolean press);
+
+    /**
+     * Generate a native system mouse motion event.
+     *
+     * @see java.awt.Robot#mouseMove(int, int)
+     */
+    void mouseMove(int x, int y);
+
+    /**
+     * Generate a native system mouse wheel event.
+     *
+     * @see java.awt.Robot#mouseWheel(int)
+     */
+    void mouseWheel(int wheelAmt);
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeWindow.java b/awt/org/apache/harmony/awt/wtk/NativeWindow.java
new file mode 100644
index 0000000..73fd6c0
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeWindow.java
@@ -0,0 +1,220 @@
+/*
+ *  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.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+
+
+/**
+ * Provides cross-platform way to manipulate native window.
+ *
+ * Results of methods are reported through native messages.
+ */
+public interface NativeWindow {
+    /**
+     * Returns system id of the associated window
+     * @return HWND on Windows, xwindow on X
+     */
+    long getId();
+
+    /**
+     * Shows/hides window
+     * @param v - new visibility
+     */
+    void setVisible(boolean v);
+
+    /**
+     * Means only size should be changed
+     */
+    static final int BOUNDS_NOMOVE = 1;
+
+    /**
+     * Means only position should be changed
+     */
+    static final int BOUNDS_NOSIZE = 2;
+
+    /**
+     * Tries to set desired window bounds. It's not gurantied the
+     * property will have the desired value. The value change
+     * should be reported by system event (as for other properties).
+     *
+     * <p/>  If child, position is relative to parent window.
+     * @param x - desired x
+     * @param y - desired y
+     * @param w - desired width
+     * @param h - desired height
+     * @param boundsMask - bitwise OR of BOUNDS_* constants.
+     * Governs the new bounds interpretation.
+     */
+    void setBounds(int x, int y, int w, int h, int boundsMask);
+
+    /**
+     * Returns last notified window bounds. This means the last bounds
+     * reported by system event.
+     *
+     * <p/>  If child, position is relative to parent window.
+     * @return last notified window bounds
+     */
+    Rectangle getBounds();
+
+    /**
+     * Returns last notified insets. This means the last insets
+     * reported by system event. Insets are margins around client area
+     * ocupied by system provided decor, ususally border and titlebar.
+     * @return last notified insets
+     */
+    Insets getInsets();
+
+    /**
+     * Enables/disables processing of input (key, mouse) event
+     * by window. If disabled input events are ignored.
+     * @param value - if enabled
+     */
+    void setEnabled(boolean value);
+
+    /**
+     * Sets the "focusable" window state.
+     * @param value - if true makes window focusable
+     */
+    void setFocusable(boolean value);
+
+    /**
+     *
+     * @return current focusable window state
+     */
+    boolean isFocusable();
+
+    /**
+     * Tries to set application input focus to the window or clear
+     * current focus from focused window.
+     *
+     * <p/> For toplevel windows it's not gurantied focus will land in
+     * desired window even if function returns true. Focus traversal should be tracked
+     * by processing system events.
+     *
+     * @param focus  - if true sets focus, else clears focus
+     * @return if success
+     */
+    boolean setFocus(boolean focus);
+
+    /**
+     * Destroys the asscoiated window.
+     * Attempts to use it thereafter can result in
+     * unpredictable bechavior.
+     */
+    void dispose();
+
+    /**
+     * Changes window Z-order to place this window under, If w is null
+     * places places this window on the top. Z-order is per parent.
+     * Toplevels a children of desktop in terms of Z-order.
+     * @param w - window to place under.
+     */
+    void placeAfter(NativeWindow w);
+
+    /**
+     * Places window on top of Z-order
+     */
+    void toFront();
+
+    /**
+     * Places window on bottom of Z-order
+     */
+    void toBack();
+
+    /**
+     * Makes the window resizable/not resizable by user
+     * @param value - if resizable
+     */
+    void setResizable(boolean value);
+
+    /**
+     * Sets the window caption
+     * @param title - caption text
+     */
+    void setTitle(String title);
+
+    /**
+     * Activate the mouse event capturing
+     */
+    void grabMouse();
+
+    /**
+     * Deactivate mouse event capturing
+     */
+    void ungrabMouse();
+
+    /**
+     * Set extended state for top-level window.
+     *
+     * @param state - new state, bitmask of ICONIFIED, MAXIMIZED_BOTH, etc.
+     */
+    void setState(int state);
+
+    /**
+     * Set the image to be displayed in the minimized icon for
+     * top-level [decorated] window.
+     * @param image the icon image to be displayed
+     */
+    void setIconImage(Image image);
+
+    /**
+     * Makes window top-most if value is true,
+     * non-topmost(normal) otherwise.
+     */
+    void setAlwaysOnTop(boolean value);
+
+    /**
+     * Set desired [top-level] window bounds when being in maximized state.
+     * Fields set to Integer.MAX_VALUE are ignored[system-supplied values are
+     * used instead]
+     */
+    void setMaximizedBounds(Rectangle bounds);
+
+    /**
+     * Get absolute position on the screen
+     */
+    Point getScreenPos();
+
+    /**
+     * Set a window "packed" flag:
+     * the flag indicates that if insets change
+     * client area shouldn't be resized, but frame
+     * must be resized instead
+     */
+    void setPacked(boolean packed);
+    
+    /**
+     * Make window an "input method window" by setting
+     * special window style, e. g. small title bar, no
+     * close, minimize/maximize buttons. For internal
+     * use by input method framework.
+     *
+     */
+    void setIMStyle();
+
+    MultiRectArea getObscuredRegion(Rectangle part);
+}
diff --git a/awt/org/apache/harmony/awt/wtk/ShutdownThread.java b/awt/org/apache/harmony/awt/wtk/ShutdownThread.java
new file mode 100644
index 0000000..701eb46
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/ShutdownThread.java
@@ -0,0 +1,83 @@
+/*
+ *  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.
+ */
+/**
+ * @author Michael Danilov, Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public final class ShutdownThread extends Thread {
+    
+    public static final class Watchdog {
+    }
+
+    public ShutdownThread() {
+        setName("AWT-Shutdown"); //$NON-NLS-1$
+        setDaemon(false);
+    }
+    
+    private boolean shouldStop = false;
+
+    @Override
+    public void run() {
+        synchronized (this) {
+            notifyAll(); // synchronize the startup
+
+            while (true) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+
+                if (shouldStop) {
+                    notifyAll(); // synchronize the shutdown
+                    return;
+                }
+            }
+        }
+    }
+
+    @Override
+    public void start() {
+        synchronized (this) {
+            super.start();
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                // awt.26=Shutdown thread was interrupted while starting
+                throw new RuntimeException(
+                        Messages.getString("awt.26")); //$NON-NLS-1$
+            }
+        }
+    }
+
+    public void shutdown() {
+        synchronized (this) {
+            shouldStop = true;
+            notifyAll();
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                // awt.27=Shutdown thread was interrupted while stopping
+                throw new RuntimeException(
+                        Messages.getString("awt.27")); //$NON-NLS-1$
+            }
+        }
+    }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/ShutdownWatchdog.java b/awt/org/apache/harmony/awt/wtk/ShutdownWatchdog.java
new file mode 100644
index 0000000..6efa519
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/ShutdownWatchdog.java
@@ -0,0 +1,86 @@
+/*
+ *  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.
+ */
+/** 
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+/**
+ * Shutdown Watchdog
+ */
+public final class ShutdownWatchdog {
+    
+    private boolean nativeQueueEmpty = true;
+    private boolean awtQueueEmpty = true;
+    private boolean windowListEmpty = true;
+
+    private boolean forcedShutdown = false;
+    
+    private ShutdownThread thread;
+
+    public synchronized void setNativeQueueEmpty(boolean empty) {
+        nativeQueueEmpty = empty;
+        checkShutdown();
+    }
+
+    public synchronized void setAwtQueueEmpty(boolean empty) {
+        awtQueueEmpty = empty;
+        checkShutdown();
+    }
+
+    public synchronized void setWindowListEmpty(boolean empty) {
+        windowListEmpty = empty;
+        checkShutdown();
+    }
+    
+    public synchronized void forceShutdown() {
+        forcedShutdown = true;
+        shutdown();
+    }
+    
+    public synchronized void start() {
+        keepAlive();
+    }
+
+    private void checkShutdown() {
+        if (canShutdown()) {
+            shutdown();
+        } else {
+            keepAlive();
+        }
+    }
+
+    private boolean canShutdown() {
+        return (nativeQueueEmpty && awtQueueEmpty && windowListEmpty) ||
+                forcedShutdown;
+    }
+
+    private void keepAlive() {
+        if (thread == null) {
+            thread = new ShutdownThread();
+            thread.start();
+        }
+    }
+
+    private void shutdown() {
+        if (thread != null) {
+            thread.shutdown();
+            thread = null;
+        }
+    }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/Synchronizer.java b/awt/org/apache/harmony/awt/wtk/Synchronizer.java
new file mode 100644
index 0000000..3eeaa0b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/Synchronizer.java
@@ -0,0 +1,200 @@
+/*
+ *  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.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.util.Hashtable;
+import java.util.LinkedList;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * Class synchronizer is to protect AWT state integrity in multithreading environment.
+ * It is supposed to have a child class per native platform.
+ * The only instance is created on the first use of one of the core AWT classes.
+ * Registers WTK on the dispatch thread startup.
+ * It is just a special kind of mutex.
+ *
+ */
+
+public class Synchronizer {
+    //TODO: think about java.util.concurrent use for faster blocking/awaking operations
+    //TODO: think about all synchronized methods. Is there need to synchronize everything?
+
+    /**
+     * This field holds the counter of lock operation.
+     * To free synchronizer unlock method must be called $acquestCounter times.
+     * Equals to 0 when synchronizer is free.
+     */
+    protected int acquestCounter;
+
+    /**
+     * This field holds the owner of synchronizer.
+     * Owner of synchronizer is a last thread that successfully locked synchronizer and
+     * still havn't freed it. Equals to null when synchronizer is free.
+     */
+    protected Thread owner;
+
+    /**
+     * This field holds the wait queue.
+     * Wait queue is a queue where thread wait for synchronizer access.
+     * Empty when synchronizer is free.
+     */
+    protected final LinkedList<Thread> waitQueue = new LinkedList<Thread>();
+
+    /**
+     * The event dispatch thread
+     */
+    protected Thread dispatchThread;
+
+    private final Hashtable<Thread, Integer> storedStates = new Hashtable<Thread, Integer>();
+
+    /**
+     * Acquire the lock for this synchronizer. Nested lock is supported.
+     * If the mutex is already locked by another thread, the current thread will be put
+     * into wait queue until the lock becomes available.
+     * All user threads are served in FIFO order. Dispatch thread has higher priority.
+     * Supposed to be used in Toolkit.lockAWT() only.
+     */
+    public void lock() {
+        synchronized (this) {
+            Thread curThread = Thread.currentThread();
+
+            if (acquestCounter == 0) {
+                acquestCounter = 1;
+                owner = curThread;
+            } else {
+                if (owner == curThread) {
+                    acquestCounter++;
+                } else {
+                    if (curThread == dispatchThread) {
+                        waitQueue.addFirst(curThread);
+                    } else {
+                        waitQueue.addLast(curThread);
+                    }
+                    try {
+                        wait();
+                    } catch (InterruptedException e) {
+                        if (owner != curThread) {
+                            waitQueue.remove(curThread);
+                            // awt.1F=Waiting for resource access thread interrupted not from unlock method.
+                            throw new RuntimeException(Messages
+                                    .getString("awt.1F")); //$NON-NLS-1$
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Release the lock for this synchronizer.
+     * If wait queue is not empty the first waiting thread acquires the lock.
+     * Supposed to be used in Toolkit.unlockAWT() only.
+     */
+    public void unlock() {
+        synchronized (this) {
+            if (acquestCounter == 0) {
+                // awt.20=Can't unlock not locked resource.
+                throw new RuntimeException(Messages.getString("awt.20")); //$NON-NLS-1$
+            }
+            if (owner != Thread.currentThread()) {
+                // awt.21=Not owner can't unlock resource.
+                throw new RuntimeException(Messages.getString("awt.21")); //$NON-NLS-1$
+            }
+
+            acquestCounter--;
+            if (acquestCounter == 0) {
+                if (waitQueue.size() > 0) {
+                    acquestCounter = 1;
+                    owner = waitQueue.removeFirst();
+                    owner.interrupt();
+                } else {
+                    owner = null;
+                }
+            }
+        }
+    }
+
+    /**
+     * Stores state of this synchronizer and frees it.
+     * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with
+     * lockAndRestoreState().
+     * Do not call it directly.
+     */
+    public void storeStateAndFree() {
+        synchronized (this) {
+            Thread curThread = Thread.currentThread();
+
+            if (owner != curThread) {
+                // awt.22=Not owner can't free resource.
+                throw new RuntimeException(Messages.getString("awt.22")); //$NON-NLS-1$
+            }
+            if (storedStates.containsKey(curThread)) {
+                // awt.23=One thread can't store state several times in a row.
+                throw new RuntimeException(Messages.getString("awt.23")); //$NON-NLS-1$
+            }
+
+            storedStates.put(curThread, new Integer(acquestCounter));
+            acquestCounter = 1;
+            unlock();
+        }
+    }
+
+    /**
+     * Locks this synchronizer and restores it's state.
+     * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with
+     * storeStateAndFree().
+     * Do not call it directly.
+     */
+    public void lockAndRestoreState() {
+        synchronized (this) {
+            Thread curThread = Thread.currentThread();
+
+            if (owner == curThread) {
+                // awt.24=Owner can't overwrite resource state. Lock operations may be lost.
+                throw new RuntimeException(
+                        Messages.getString("awt.24")); //$NON-NLS-1$
+            }
+            if (!storedStates.containsKey(curThread)) {
+                // awt.25=No state stored for current thread.
+                throw new RuntimeException(Messages.getString("awt.25")); //$NON-NLS-1$
+            }
+
+            lock();
+            acquestCounter = storedStates.get(curThread).intValue();
+            storedStates.remove(curThread);
+        }
+    }
+
+    /**
+     * Sets references to WTK and event dispatch thread.
+     * Called on toolkit startup.
+     *
+     * @param wtk - reference to WTK instance
+     * @param dispatchThread - reference to event dispatch thread
+     */
+    public void setEnvironment(WTK wtk, Thread dispatchThread) {
+        synchronized (this) {
+            this.dispatchThread = dispatchThread;
+        }
+    }
+
+}
diff --git a/awt/org/apache/harmony/awt/wtk/SystemProperties.java b/awt/org/apache/harmony/awt/wtk/SystemProperties.java
new file mode 100644
index 0000000..6b59f0e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/SystemProperties.java
@@ -0,0 +1,59 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Font;
+import java.awt.font.TextAttribute;
+import java.awt.im.InputMethodHighlight;
+import java.util.Map;
+
+/**
+ * NativeProperties
+ */
+
+public interface SystemProperties {
+
+    /**
+     * Get current value of a system color
+     * @param index - one of java.awt.SystemColor constants
+     * @return ARGB value of requested system color
+     */
+    int getSystemColorARGB(int index);
+
+    /**
+     * Get default font for GUI elements such as menus and buttons
+     * @return the font object
+     */
+    Font getDefaultFont();
+    
+    /**
+     * Fill the given Map with system properties
+     */
+    void init(Map<String, ?> desktopProperties);
+
+    /**
+     * Fills the given map with system-dependent visual text
+     * attributes for the abstract description 
+     * of the given input method highlight
+     * @see java.awt.Toolkit.mapInputMethodHighlight()
+     */
+    void mapInputMethodHighlight(InputMethodHighlight highlight, Map<TextAttribute, ?> map);
+}
diff --git a/awt/org/apache/harmony/awt/wtk/WTK.java b/awt/org/apache/harmony/awt/wtk/WTK.java
new file mode 100644
index 0000000..4162fbd
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/WTK.java
@@ -0,0 +1,61 @@
+/*
+ *  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.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.GraphicsDevice;
+
+
+public abstract class WTK {
+
+    public abstract GraphicsFactory getGraphicsFactory();
+    public abstract NativeEventQueue getNativeEventQueue();
+    public abstract WindowFactory getWindowFactory();
+
+    /**
+     * Returns platform specific implementation of the interface
+     * org.apache.harmony.awt.wtk.CursorFactory.
+     * @return implementation of CursorFactory
+     */
+    public abstract CursorFactory getCursorFactory();
+
+    /**
+     * Returns platform specific implementation of the interface
+     * org.apache.harmony.awt.wtk.NativeMouseInfo.
+     * @return implementation of NativeMouseInfo
+     */
+    public abstract NativeMouseInfo getNativeMouseInfo();
+
+    public abstract SystemProperties getSystemProperties();
+
+    /**
+     * Returns platform specific implementation of the interface
+     * org.apache.harmony.awt.wtk.NativeRobot.
+     * @return implementation of NativeRobot
+     */
+    public abstract NativeRobot getNativeRobot(GraphicsDevice screen);
+    
+    /**
+     * Returns platform specific implementation of the abstract
+     * class org.apache.harmony.awt.wtk.NativeIM.
+     * @return implementation of NativeIM
+     */
+    public abstract NativeIM getNativeIM();
+}
diff --git a/awt/org/apache/harmony/awt/wtk/WindowFactory.java b/awt/org/apache/harmony/awt/wtk/WindowFactory.java
new file mode 100644
index 0000000..23604da
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/WindowFactory.java
@@ -0,0 +1,85 @@
+/*
+ *  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.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Dimension;
+import java.awt.Point;
+
+/**
+ * Provides factory for NativeWindow
+ */
+public interface WindowFactory {
+    /**
+     * Creates and returns NativeWindow with desired
+     * creation params
+     *
+     * @param p - initial window properties
+     * @return created window
+     */
+    NativeWindow createWindow(CreationParams p);
+    /**
+     * Create NativeWindow instance connected to existing native resource
+     * @param nativeWindowId - id of existing window
+     * @return created NativeWindow instance
+     */
+    NativeWindow attachWindow(long nativeWindowId);
+    /**
+     * Returns NativeWindow instance if created by this instance of
+     * WindowFactory, otherwise null
+     *
+     * @param id - HWND on Windows xwindow on X
+     * @return NativeWindow or null if unknown
+     */
+    NativeWindow getWindowById(long id);
+    /**
+     * Returns NativeWindow instance of the top-level window
+     * that contains a specified point and was
+     * created by this instance of WindowFactory
+     * @param p - Point to check
+     * @return NativeWindow or null if the point is
+     * not within a window created by this WindowFactory
+     */
+    NativeWindow getWindowFromPoint(Point p);
+
+    /**
+     * Returns whether native system supports the state for windows.
+     * This method tells whether the UI concept of, say, maximization or iconification is supported.
+     * It will always return false for "compound" states like Frame.ICONIFIED|Frame.MAXIMIZED_VERT.
+     * In other words, the rule of thumb is that only queries with a single frame state
+     * constant as an argument are meaningful.
+     *
+     * @param state - one of named frame state constants.
+     * @return true is this frame state is supported by this Toolkit implementation, false otherwise.
+     */
+    boolean isWindowStateSupported(int state);
+
+    /**
+     * @see org.apache.harmony.awt.ComponentInternals
+     */
+    void setCaretPosition(int x, int y);
+
+    /**
+     * Request size of arbitrary native window
+     * @param id - window ID
+     * @return window size
+     */
+    Dimension getWindowSizeById(long id);
+}
\ No newline at end of file
diff --git a/awt/org/apache/harmony/beans/internal/nls/Messages.java b/awt/org/apache/harmony/beans/internal/nls/Messages.java
new file mode 100644
index 0000000..51e8168
--- /dev/null
+++ b/awt/org/apache/harmony/beans/internal/nls/Messages.java
@@ -0,0 +1,151 @@
+/* 
+ * 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.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten 
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+package org.apache.harmony.beans.internal.nls;
+
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+// BEGIN android-deleted
+/*
+ * For Android, this module is a separate library and not part of the
+ * boot classpath, so its resources won't be found on the boot classpath
+ * as is assumed by MsgHelp.getString(). We instead use a local MsgHelp
+ * which bottoms out in a call to the useful part of its lower-level
+ * namesake.
+ */
+//import org.apache.harmony.kernel.vm.VM;
+//import org.apache.harmony.luni.util.MsgHelp;
+// END android-deleted
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ *    org.apache.harmony.beans.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ * 
+ */
+public class Messages {
+
+    // BEGIN android-deleted
+    // private static final String sResource =
+    //     "org.apache.harmony.beans.internal.nls.messages"; //$NON-NLS-1$
+    // END android-deleted
+
+    /**
+     * Retrieves a message which has no arguments.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg) {
+        // BEGIN android-changed
+        return MsgHelp.getString(msg);
+        // END android-changed
+    }
+
+    /**
+     * Retrieves a message which takes 1 argument.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg
+     *            Object the object to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, Object arg) {
+        return getString(msg, new Object[] { arg });
+    }
+
+    /**
+     * Retrieves a message which takes 1 integer argument.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg
+     *            int the integer to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, int arg) {
+        return getString(msg, new Object[] { Integer.toString(arg) });
+    }
+
+    /**
+     * Retrieves a message which takes 1 character argument.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg
+     *            char the character to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, char arg) {
+        return getString(msg, new Object[] { String.valueOf(arg) });
+    }
+
+    /**
+     * Retrieves a message which takes 2 arguments.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg1
+     *            Object an object to insert in the formatted output.
+     * @param arg2
+     *            Object another object to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, Object arg1, Object arg2) {
+        return getString(msg, new Object[] { arg1, arg2 });
+    }
+
+    /**
+     * Retrieves a message which takes several arguments.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param args
+     *            Object[] the objects to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, Object[] args) {
+        // BEGIN android-changed
+        return MsgHelp.getString(msg, args);
+        // END android-changed
+    }
+
+    // BEGIN android-note
+    // Duplicate code was dropped in favor of using MsgHelp.
+    // END android-note
+}
diff --git a/awt/org/apache/harmony/beans/internal/nls/MsgHelp.java b/awt/org/apache/harmony/beans/internal/nls/MsgHelp.java
new file mode 100644
index 0000000..68faabf
--- /dev/null
+++ b/awt/org/apache/harmony/beans/internal/nls/MsgHelp.java
@@ -0,0 +1,86 @@
+/*
+ *  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.
+ */
+
+/*
+ * This implementation is based on the class of the same name in
+ * org.apache.harmony.luni.util.
+ */
+
+package org.apache.harmony.beans.internal.nls;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.logging.Logger;
+import java.util.Locale;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+import java.util.MissingResourceException;
+
+/**
+ * This class contains helper methods for loading resource bundles and
+ * formatting external message strings.
+ */
+public final class MsgHelp {
+    /** name of the resource for this class */
+    private static final String RESOURCE_NAME =
+        "/org/apache/harmony/beans/internal/nls/messages.properties";
+
+    /** the resource bundle for this class */
+    private static final ResourceBundle THE_BUNDLE;
+
+    static {
+        ResourceBundle rb = null;
+
+        try {
+            InputStream in = MsgHelp.class.getResourceAsStream(
+                    RESOURCE_NAME);
+            rb = new PropertyResourceBundle(in);
+        } catch (IOException ex) {
+            Logger.global.warning("Couldn't read resource bundle: " +
+                    ex);
+        } catch (RuntimeException ex) {
+            // Shouldn't happen, but deal at least somewhat gracefully.
+            Logger.global.warning("Couldn't find resource bundle: " +
+                    ex);
+        }
+
+        THE_BUNDLE = rb;
+    }
+    
+    public static String getString(String msg) {
+        if (THE_BUNDLE == null) {
+            return msg;
+        }
+        try {
+            return THE_BUNDLE.getString(msg);
+        } catch (MissingResourceException e) {
+            return "Missing message: " + msg;
+        }
+    }
+    
+    static public String getString(String msg, Object[] args) {
+        String format = msg;
+        if (THE_BUNDLE != null) {
+            try {
+                format = THE_BUNDLE.getString(msg);
+            } catch (MissingResourceException e) {
+            }
+        }
+
+        return org.apache.harmony.luni.util.MsgHelp.format(format, args);
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/internal/nls/Messages.java b/awt/org/apache/harmony/x/imageio/internal/nls/Messages.java
new file mode 100644
index 0000000..498e1bb
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/internal/nls/Messages.java
@@ -0,0 +1,124 @@
+/* 
+ * 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.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten 
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+package org.apache.harmony.x.imageio.internal.nls;
+
+import org.apache.harmony.luni.util.MsgHelp;
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ *    org.apache.harmony.x.imageio.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ * 
+ */
+public class Messages {
+
+    private static final String sResource =
+        "org.apache.harmony.x.imageio.internal.nls.messages"; //$NON-NLS-1$
+
+    /**
+     * Retrieves a message which has no arguments.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg) {
+        return MsgHelp.getString(sResource, msg);
+    }
+
+    /**
+     * Retrieves a message which takes 1 argument.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg
+     *            Object the object to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, Object arg) {
+        return getString(msg, new Object[] { arg });
+    }
+
+    /**
+     * Retrieves a message which takes 1 integer argument.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg
+     *            int the integer to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, int arg) {
+        return getString(msg, new Object[] { Integer.toString(arg) });
+    }
+
+    /**
+     * Retrieves a message which takes 1 character argument.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg
+     *            char the character to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, char arg) {
+        return getString(msg, new Object[] { String.valueOf(arg) });
+    }
+
+    /**
+     * Retrieves a message which takes 2 arguments.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg1
+     *            Object an object to insert in the formatted output.
+     * @param arg2
+     *            Object another object to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, Object arg1, Object arg2) {
+        return getString(msg, new Object[] { arg1, arg2 });
+    }
+
+    /**
+     * Retrieves a message which takes several arguments.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param args
+     *            Object[] the objects to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, Object[] args) {
+        return MsgHelp.getString(sResource, msg, args);
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/internal/nls/messages.properties b/awt/org/apache/harmony/x/imageio/internal/nls/messages.properties
new file mode 100644
index 0000000..8a49dd8
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/internal/nls/messages.properties
@@ -0,0 +1,18 @@
+# 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.
+# 
+
+# messages for EN locale
+imageio.1=Wrong bitDepth-numBands composition
\ No newline at end of file
diff --git a/awt/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java b/awt/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java
new file mode 100644
index 0000000..caeefdd
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java
@@ -0,0 +1,94 @@
+/*
+ *  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.
+ */
+
+
+package org.apache.harmony.x.imageio.metadata;
+
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import javax.imageio.metadata.IIOMetadataFormat;
+import javax.imageio.metadata.IIOMetadataFormatImpl;
+
+public class IIOMetadataUtils {
+    private IIOMetadataUtils() {} 
+
+    public static IIOMetadataFormat instantiateMetadataFormat(
+            String formatName, boolean standardFormatSupported,
+            String nativeMetadataFormatName, String nativeMetadataFormatClassName,
+            String [] extraMetadataFormatNames, String [] extraMetadataFormatClassNames
+    ) {
+        if (formatName == null) {
+            throw new IllegalArgumentException("formatName == null!");
+        }
+        if (formatName.equals(IIOMetadataFormatImpl.standardMetadataFormatName)) {
+            if (standardFormatSupported) {
+                return IIOMetadataFormatImpl.getStandardFormatInstance();
+            }
+        }
+
+        String className = null;
+
+        if (formatName.equals(nativeMetadataFormatName)) {
+            className = nativeMetadataFormatClassName;
+        } else if (extraMetadataFormatNames != null) {
+            for (int i = 0; i < extraMetadataFormatNames.length; i++) {
+                if (formatName.equals(extraMetadataFormatNames[i])) {
+                    className = extraMetadataFormatClassNames[i];
+                    break;
+                }
+            }
+        }
+
+        if (className == null) {
+            throw new IllegalArgumentException("Unsupported format name");
+        }
+
+        // Get the context class loader and try to use it first
+        ClassLoader contextClassloader = AccessController.doPrivileged(
+                new PrivilegedAction<ClassLoader>() {
+                    public ClassLoader run() {
+                        return Thread.currentThread().getContextClassLoader();
+                    }
+        });
+
+        Class cls;
+
+        try {
+            cls = Class.forName(className, true, contextClassloader);
+        } catch (ClassNotFoundException e) {
+            try {
+                // Use current class loader
+                cls = Class.forName(className);
+            } catch (ClassNotFoundException e1) {
+                throw new IllegalStateException ("Can't obtain format");
+            }
+        }
+
+        try {
+            //???AWT:
+            //Method getInstance = cls.getMethod("getInstance");
+            //return (IIOMetadataFormat) getInstance.invoke(null);
+            return null;
+        } catch (Exception e) {
+            IllegalStateException e1 = new IllegalStateException("Can't obtain format");
+            e1.initCause(e); // Add some details to the message
+            throw e1;
+        }
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java
new file mode 100644
index 0000000..051f906
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java
@@ -0,0 +1,115 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+import javax.imageio.stream.ImageInputStream;
+
+import org.apache.harmony.awt.gl.image.DecodingImageSource;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This allows usage of the java2d jpegdecoder with ImageInputStream in
+ * the JPEGImageReader. Temporary, only to make JPEGImageReader#read(..)
+ * working.
+ *
+ */
+public class IISDecodingImageSource extends DecodingImageSource {
+
+    private final InputStream is;
+
+    public IISDecodingImageSource(ImageInputStream iis) {
+        is = new IISToInputStreamWrapper(iis);
+    }
+
+    @Override
+    protected boolean checkConnection() {
+        return true;
+    }
+
+    @Override
+    protected InputStream getInputStream() {
+        return is;
+    }
+
+    static class IISToInputStreamWrapper extends InputStream {
+
+        private ImageInputStream input;
+
+        public IISToInputStreamWrapper(ImageInputStream input) {
+            this.input=input;
+        }
+
+        @Override
+        public int read() throws IOException {
+            return input.read();
+        }
+
+        @Override
+        public int read(byte[] b) throws IOException {
+            return input.read(b);
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            return input.read(b, off, len);
+        }
+
+        @Override
+        public long skip(long n) throws IOException {
+            return input.skipBytes(n);
+        }
+
+        @Override
+        public boolean markSupported() {
+        	return true;  // This is orig
+        	
+            // ???AWT: FIXME
+        	// This is an error in Harmony. Not all input streams
+        	// have mark support and it is not ok to just return true. 
+        	// There should be an input.markSupported(). However, if 
+        	// this call returns false, nothing works anymore.
+        	
+        	// The backside is that BitmapFactory uses a call to markSupport()
+        	// to find out if it needs to warp the stream in a
+        	// BufferedInputStream to get mark support, and this fails!
+        	
+        	// Currently, the hack is in BitmapFactory, where we always
+        	// wrap the stream in a BufferedInputStream.
+        }
+
+        @Override
+        public void mark(int readlimit) {
+            input.mark();
+        }
+
+        @Override
+        public void reset() throws IOException {
+            input.reset();
+        }
+
+        @Override
+        public void close() throws IOException {
+            input.close();
+        }
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java
new file mode 100644
index 0000000..067a825
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java
@@ -0,0 +1,44 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+public class JPEGConsts {
+
+    private JPEGConsts() {}
+
+    public static final int SOI = 0xD8;
+
+    //-- IJG (Independed JPEG Group) color spaces
+    public static final int JCS_UNKNOW = 0;
+    public static final int JCS_GRAYSCALE = 1;
+    public static final int JCS_RGB = 2;
+    public static final int JCS_YCbCr = 3;
+    public static final int JCS_CMYK = 4;
+    public static final int JCS_YCC = 5;
+    public static final int JCS_RGBA = 6;
+    public static final int JCS_YCbCrA = 7;
+    public static final int JCS_YCCA = 10;
+    public static final int JCS_YCCK = 11;
+
+    public static int[][] BAND_OFFSETS = {{}, {0}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3}};
+
+    public static final float DEFAULT_JPEG_COMPRESSION_QUALITY = 0.75f;
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java
new file mode 100644
index 0000000..110ed23
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java
@@ -0,0 +1,126 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.4 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+
+import javax.imageio.ImageReader;
+import javax.imageio.ImageReadParam;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.plugins.jpeg.JPEGImageReadParam;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.spi.ImageReaderSpi;
+
+import org.apache.harmony.awt.gl.image.DecodingImageSource;
+import org.apache.harmony.awt.gl.image.OffscreenImage;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.awt.image.BufferedImage;
+
+/**
+ * This implementation uses org.apache.harmony.awt.gl.image.JpegDecoder to read
+ * an image. The only implemented method is read(..);
+ *
+ * TODO: Implements generic decoder to be used by javad2 and imageio
+ *
+ * @see org.apache.harmony.awt.gl.image.JpegDecoder
+ * @see org.apache.harmony.x.imageio.plugins.jpeg.IISDecodingImageSource
+ */
+public class JPEGImageReader extends ImageReader {
+
+    ImageInputStream iis;
+
+    public JPEGImageReader(ImageReaderSpi imageReaderSpi) {
+        super(imageReaderSpi);
+    }
+
+    @Override
+    public int getHeight(int i) throws IOException {
+        //-- TODO imlement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    @Override
+    public int getWidth(int i) throws IOException {
+        //-- TODO imlement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    @Override
+    public int getNumImages(boolean b) throws IOException {
+        //-- TODO imlement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    @Override
+    public Iterator<ImageTypeSpecifier> getImageTypes(int i) throws IOException {
+        //-- TODO imlement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    @Override
+    public IIOMetadata getStreamMetadata() throws IOException {
+        //-- TODO imlement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    @Override
+    public IIOMetadata getImageMetadata(int i) throws IOException {
+        //-- TODO imlement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    @Override
+    public BufferedImage read(int i, ImageReadParam imageReadParam) throws IOException {
+        if (iis == null) {
+            throw new IllegalArgumentException("input stream == null");
+        }
+
+        DecodingImageSource source = new IISDecodingImageSource(iis);
+        OffscreenImage image = new OffscreenImage(source);
+        source.addConsumer(image);
+        source.load();
+        // The interrupted flag should be cleared because ImageDecoder interrupts
+        // current thread while decoding. The same technique is used in
+        // ImageLoader#run(). Another solution can be to create
+        // a separate decoding thread. However, decoder keeps its own pool
+        // of threads so creating a new thread will be just a waste of resources.
+        Thread.interrupted();
+        return image.getBufferedImage();
+    }
+
+    @Override
+    public BufferedImage read(int i) throws IOException {
+        return read(i, null);
+    }
+
+    @Override
+    public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
+        super.setInput(input, seekForwardOnly, ignoreMetadata);
+        iis = (ImageInputStream) input;
+    }
+
+    @Override
+    public ImageReadParam getDefaultReadParam() {
+        return new JPEGImageReadParam();
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java
new file mode 100644
index 0000000..c719ce7
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java
@@ -0,0 +1,86 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+import java.io.IOException;
+import java.util.Locale;
+import javax.imageio.ImageReader;
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.spi.ServiceRegistry;
+import javax.imageio.stream.ImageInputStream;
+
+public class JPEGImageReaderSpi extends ImageReaderSpi {
+
+    public JPEGImageReaderSpi() {
+        super(JPEGSpiConsts.vendorName, JPEGSpiConsts.version,
+                JPEGSpiConsts.names, JPEGSpiConsts.suffixes,
+                JPEGSpiConsts.MIMETypes, JPEGSpiConsts.readerClassName,
+                STANDARD_INPUT_TYPE, JPEGSpiConsts.writerSpiNames,
+                JPEGSpiConsts.supportsStandardStreamMetadataFormat,
+                JPEGSpiConsts.nativeStreamMetadataFormatName,
+                JPEGSpiConsts.nativeStreamMetadataFormatClassName,
+                JPEGSpiConsts.extraStreamMetadataFormatNames,
+                JPEGSpiConsts.extraStreamMetadataFormatClassNames,
+                JPEGSpiConsts.supportsStandardImageMetadataFormat,
+                JPEGSpiConsts.nativeImageMetadataFormatName,
+                JPEGSpiConsts.nativeImageMetadataFormatClassName,
+                JPEGSpiConsts.extraImageMetadataFormatNames,
+                JPEGSpiConsts.extraImageMetadataFormatClassNames);
+    }
+
+
+    @Override
+    public boolean canDecodeInput(Object source) throws IOException {
+        ImageInputStream markable = (ImageInputStream) source;
+        try {
+            markable.mark();
+
+            byte[] signature = new byte[3];
+            markable.seek(0);
+            markable.read(signature, 0, 3);
+            markable.reset();
+
+            if ((signature[0] & 0xFF) == 0xFF &&
+                    (signature[1] & 0xFF) == JPEGConsts.SOI &&
+                    (signature[2] & 0xFF) == 0xFF) { // JPEG
+                return true;
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    @Override
+    public ImageReader createReaderInstance(Object extension) throws IOException {
+        return new JPEGImageReader(this);
+    }
+
+    @Override
+    public String getDescription(Locale locale) {
+        return "DRL JPEG decoder";
+    }
+
+    @Override
+    public void onRegistration(ServiceRegistry registry, Class<?> category) {
+        // super.onRegistration(registry, category);
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java
new file mode 100644
index 0000000..ae3e876
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java
@@ -0,0 +1,402 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+import com.android.internal.awt.ImageOutputStreamWrapper;
+
+import javax.imageio.ImageWriter;
+import javax.imageio.IIOImage;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.metadata.IIOMetadata;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap.CompressFormat;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.awt.image.*;
+import java.awt.*;
+import java.awt.color.ColorSpace;
+
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+public class JPEGImageWriter extends ImageWriter {
+
+    // /* ???AWT: Debugging
+    private static final boolean DEBUG = false;
+    private static Bitmap bm;
+    public static Bitmap getBitmap() {
+        return bm;
+    }
+    private static BufferedImage bufImg;
+    public static BufferedImage getBufImage() {
+        return bufImg;
+    }
+    static private RenderedImage renImg;
+    static public RenderedImage getRenImage() {
+        return renImg;
+    }
+    // */
+    
+    private long cinfo;
+    private RenderedImage image;
+    private Raster sourceRaster;
+    private WritableRaster scanRaster;
+    private int srcXOff = 0;
+    private int srcYOff = 0;
+    private int srcWidth;
+    private int srcHeight;
+
+    //-- y step for image subsampling
+    private int deltaY = 1;
+    //-- x step for image subsampling
+    private int deltaX = 1;
+
+    private ImageOutputStream ios;
+
+    public JPEGImageWriter(ImageWriterSpi imageWriterSpi) {
+        super(imageWriterSpi);
+        //???AWT: cinfo = initCompressionObj();
+        cinfo = System.currentTimeMillis();
+    }
+
+    static {
+        //???AWT
+        /*
+        System.loadLibrary("jpegencoder");
+        initWriterIds(ImageOutputStream.class);
+        */
+    }
+
+    @Override
+    public void write(IIOMetadata iioMetadata, IIOImage iioImage, ImageWriteParam param)
+            throws IOException {
+
+        if (ios == null) {
+            throw new IllegalArgumentException("ios == null");
+        }
+        if (iioImage == null) {
+            throw new IllegalArgumentException("Image equals null");
+        }
+
+        RenderedImage img = null;
+        if (!iioImage.hasRaster()) {
+            img = iioImage.getRenderedImage();
+            if (img instanceof BufferedImage) {
+                sourceRaster = ((BufferedImage) img).getRaster();
+            } else {
+                sourceRaster = img.getData();
+            }
+        } else {
+            sourceRaster = iioImage.getRaster();
+        }
+        
+        // AWT???: Debugging
+        if (DEBUG) {
+            if( img==null ) {
+                System.out.println("****J: Image is NULL");
+            } else {
+                renImg = img;
+                bufImg = (BufferedImage)img;
+            }
+        }
+
+        int numBands = sourceRaster.getNumBands();
+        int sourceIJGCs = img == null ? JPEGConsts.JCS_UNKNOW : getSourceCSType(img);
+
+        srcWidth = sourceRaster.getWidth();
+        srcHeight = sourceRaster.getHeight();
+
+        int destWidth = srcWidth;
+        int destHeight = srcHeight;
+
+        boolean progressive = false;
+         
+        if (param != null) {
+            Rectangle reg = param.getSourceRegion();
+            if (reg != null) {
+                srcXOff = reg.x;
+                srcYOff = reg.y;
+
+                srcWidth = reg.width + srcXOff > srcWidth
+                        ? srcWidth - srcXOff
+                        : reg.width;
+                srcHeight = reg.height + srcYOff > srcHeight
+                        ? srcHeight - srcYOff
+                        : reg.height;
+            }
+
+            //-- TODO uncomment when JPEGImageWriteParam be implemented
+            //-- Only default progressive mode yet
+            // progressive = param.getProgressiveMode() ==  ImageWriteParam.MODE_DEFAULT;
+
+            //-- def is 1
+            deltaX = param.getSourceXSubsampling();
+            deltaY = param.getSourceYSubsampling();
+
+            //-- def is 0
+            int offsetX = param.getSubsamplingXOffset();
+            int offsetY = param.getSubsamplingYOffset();
+
+            srcXOff += offsetX;
+            srcYOff += offsetY;
+            srcWidth -= offsetX;
+            srcHeight -= offsetY;
+
+            destWidth = (srcWidth + deltaX - 1) / deltaX;
+            destHeight = (srcHeight + deltaY - 1) / deltaY;
+        }
+
+        //-- default DQTs (see JPEGQTable java doc and JPEG spec K1 & K2 tables)
+        //-- at http://www.w3.org/Graphics/JPEG/itu-t81.pdf
+        //-- Only figuring out how to set DQT in IJG library for future metadata
+        //-- support. IJG def tables are the same.
+        //JPEGQTable[] dqt = new JPEGQTable[2];
+//        int[][] dqt = null;
+//        int[][] dqt = new int[2][];
+//        dqt[0] = JPEGQTable.K1Div2Luminance.getTable();
+//        dqt[1] = JPEGQTable.K2Div2Chrominance.getTable();
+        
+        //???AWT: I think we don't need this amymore
+        /*
+        //-- using default color space
+        //-- TODO: Take destination cs from param or use default if there is no cs
+        int destIJGCs = img == null ? JPEGConsts.JCS_UNKNOW : getDestinationCSType(img);
+
+        DataBufferByte dbuffer = new DataBufferByte(numBands * srcWidth);
+
+        scanRaster = Raster.createInterleavedRaster(dbuffer, srcWidth, 1,
+                numBands * srcWidth, numBands, JPEGConsts.BAND_OFFSETS[numBands], null);
+
+        encode(dbuffer.getData(), srcWidth, destWidth, destHeight, deltaX,
+                sourceIJGCs, destIJGCs, numBands, progressive,
+                null, cinfo);
+        */
+        
+        SampleModel model = sourceRaster.getSampleModel();
+        
+        if (model instanceof SinglePixelPackedSampleModel) {
+            DataBufferInt ibuf = (DataBufferInt)sourceRaster.getDataBuffer();
+            int[] pixels = ibuf.getData();
+            
+            // Create a bitmap with the pixel
+            bm = Bitmap.createBitmap(pixels, srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
+            
+            // Use Bitmap.compress() to write the image
+            ImageOutputStreamWrapper iosw = new ImageOutputStreamWrapper(ios);
+            bm.compress(CompressFormat.JPEG, 100, iosw);
+        } else {
+            // ???AWT: Add support for other color models
+            throw new RuntimeException("Color model not supported yet");
+        }
+
+    }
+
+    @Override
+    public void dispose() {
+        super.dispose();
+        if (cinfo != 0) {
+            //???AWT: dispose(cinfo);
+            cinfo = 0;
+            ios = null;
+        }
+    }
+
+
+    public IIOMetadata getDefaultStreamMetadata(ImageWriteParam imageWriteParam) {
+        throw new UnsupportedOperationException("not supported yet");
+    }
+
+    public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam) {
+        throw new UnsupportedOperationException("not supported yet");
+    }
+
+    @Override
+    public IIOMetadata convertStreamMetadata(IIOMetadata iioMetadata, ImageWriteParam imageWriteParam) {
+        throw new UnsupportedOperationException("not supported yet");
+    }
+
+    @Override
+    public IIOMetadata convertImageMetadata(IIOMetadata iioMetadata, ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam) {
+        throw new UnsupportedOperationException("not supported yet");
+    }
+
+    @Override
+    public void setOutput(Object output) {
+        super.setOutput(output);
+        ios = (ImageOutputStream) output;
+        //???AWT: setIOS(ios, cinfo);
+        sourceRaster = null;
+        scanRaster = null;
+        srcXOff = 0;
+        srcYOff = 0;
+        srcWidth = 0;
+        srcHeight = 0;
+        deltaY = 1;
+    }
+
+    /**
+     * Frees resources
+     * @param structPointer
+     */
+    //???AWT: private native void dispose(long structPointer);
+
+    /**
+     * Inits methods Ids for native to java callbacks
+     * @param iosClass
+     */
+    //???AWT: private native static void initWriterIds(Class<ImageOutputStream> iosClass);
+
+    /**
+     * Inits compression objects
+     * @return pointer to the native structure
+     */
+    //???AWT: private native long initCompressionObj();
+
+    /**
+     * Sets image output stream in IJG layer
+     * @param stream
+     */
+    //???AWT: private native void setIOS(ImageOutputStream stream, long structPointer);
+
+    /**
+     * Runs encoding process.
+     *
+     * @param data image data buffer to encode
+     * @param srcWidth - source width
+     * @param width - destination width
+     * @param height destination height
+     * @param deltaX - x subsampling step
+     * @param inColorSpace - original color space
+     * @param outColorSpace - destination color space
+     * @param numBands - number of bands
+     * @param cinfo - native handler
+     * @return
+     */
+    //???AWT:
+    /*
+    private native boolean encode(byte[] data, int srcWidth,
+                                  int width, int height, int deltaX,
+                                  int inColorSpace, int outColorSpace,
+                                  int numBands, boolean progressive,
+                                  int[][] dqt,
+                                  long cinfo);
+    */
+
+    /**
+     * Callback for getting a next scanline
+     * @param scanline scan line number
+     */
+    @SuppressWarnings("unused")
+    private void getScanLine(int scanline) {
+        //-- TODO: processImageProgress in ImageWriter
+        Raster child = sourceRaster.createChild(srcXOff,
+                srcYOff + scanline * deltaY, srcWidth, 1, 0, 0, null);
+
+        scanRaster.setRect(child);
+    }
+
+    /**
+     * Maps color space types to IJG color spaces
+     * @param image
+     * @return
+     */
+    private int getSourceCSType(RenderedImage image) {
+        int type = JPEGConsts.JCS_UNKNOW;
+        ColorModel cm = image.getColorModel();
+
+        if (null == cm) {
+            return type;
+        }
+
+        if (cm instanceof IndexColorModel) {
+            throw new UnsupportedOperationException("IndexColorModel is not supported yet");
+        }
+
+        boolean hasAlpha = cm.hasAlpha();
+        ColorSpace cs = cm.getColorSpace();
+        switch(cs.getType()) {
+            case ColorSpace.TYPE_GRAY:
+                type = JPEGConsts.JCS_GRAYSCALE;
+                break;
+           case ColorSpace.TYPE_RGB:
+                type = hasAlpha ? JPEGConsts.JCS_RGBA : JPEGConsts.JCS_RGB;
+                break;
+           case ColorSpace.TYPE_YCbCr:
+                type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr;
+                break;
+           case ColorSpace.TYPE_3CLR:
+                 type = hasAlpha ? JPEGConsts.JCS_YCCA : JPEGConsts.JCS_YCC;
+                 break;
+           case ColorSpace.TYPE_CMYK:
+                  type = JPEGConsts.JCS_CMYK;
+                  break;
+        }
+        return type;
+    }
+
+    /**
+     * Returns destination color space.
+     * (YCbCr[A] for RGB)
+     *
+     * @param image
+     * @return
+     */
+    private int getDestinationCSType(RenderedImage image) {
+        int type = JPEGConsts.JCS_UNKNOW;
+        ColorModel cm = image.getColorModel();
+        if (null != cm) {
+            boolean hasAlpha = cm.hasAlpha();
+            ColorSpace cs = cm.getColorSpace();
+
+            switch(cs.getType()) {
+                case ColorSpace.TYPE_GRAY:
+                    type = JPEGConsts.JCS_GRAYSCALE;
+                    break;
+               case ColorSpace.TYPE_RGB:
+                    type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr;
+                    break;
+               case ColorSpace.TYPE_YCbCr:
+                    type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr;
+                    break;
+               case ColorSpace.TYPE_3CLR:
+                     type = hasAlpha ? JPEGConsts.JCS_YCCA : JPEGConsts.JCS_YCC;
+                     break;
+               case ColorSpace.TYPE_CMYK:
+                      type = JPEGConsts.JCS_CMYK;
+                      break;
+            }
+        }
+        return type;
+    }
+
+    public ImageWriteParam getDefaultWriteParam() {
+        return new JPEGImageWriteParam(getLocale());
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java
new file mode 100644
index 0000000..b7990e0
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java
@@ -0,0 +1,56 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.ImageWriter;
+import javax.imageio.ImageTypeSpecifier;
+import java.io.IOException;
+import java.util.Locale;
+
+public class JPEGImageWriterSpi extends ImageWriterSpi {
+
+    public JPEGImageWriterSpi() {
+        super(JPEGSpiConsts.vendorName, JPEGSpiConsts.version,
+                JPEGSpiConsts.names, JPEGSpiConsts.suffixes, JPEGSpiConsts.MIMETypes,
+                JPEGSpiConsts.writerClassName, STANDARD_OUTPUT_TYPE,
+                JPEGSpiConsts.readerSpiNames, JPEGSpiConsts.supportsStandardStreamMetadataFormat /*TODO: support st. metadata format*/,
+                JPEGSpiConsts.nativeStreamMetadataFormatName, JPEGSpiConsts.nativeStreamMetadataFormatClassName,
+                JPEGSpiConsts.extraStreamMetadataFormatNames, JPEGSpiConsts.extraStreamMetadataFormatClassNames,
+                JPEGSpiConsts.supportsStandardImageMetadataFormat, JPEGSpiConsts.nativeImageMetadataFormatName, JPEGSpiConsts.nativeImageMetadataFormatClassName,
+                JPEGSpiConsts.extraImageMetadataFormatNames, JPEGSpiConsts.extraImageMetadataFormatClassNames);
+    }
+
+    @Override
+    public boolean canEncodeImage(ImageTypeSpecifier imageTypeSpecifier) {
+        return true;
+    }
+
+    @Override
+    public ImageWriter createWriterInstance(Object o) throws IOException {
+        return new JPEGImageWriter(this);
+    }
+
+    @Override
+    public String getDescription(Locale locale) {
+        return "DRL JPEG Encoder";
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java
new file mode 100644
index 0000000..c3b4a50
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java
@@ -0,0 +1,57 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+public class JPEGSpiConsts {
+    private JPEGSpiConsts() {}
+
+    public static final String vendorName = "Intel Corporation";
+    public static final String version = "0.1 beta";
+
+    static final String readerClassName = "org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageReader";
+    static final String writerClassName = "org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageWriter";
+
+    static final String[] names = {"jpeg", "jpg", "JPEG", "JPG"};
+    static final String[] suffixes = {"jpeg", "jpg"};
+    static final String[] MIMETypes = {"image/jpeg"};
+
+    static final String[] writerSpiNames = {"org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageWriterSpi"};
+    static final String[] readerSpiNames = {"org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageReaderSpi"};
+
+    //-- TODO fill this stuff with correct data
+    static final boolean supportsStandardStreamMetadataFormat = false;
+    static final String nativeStreamMetadataFormatName = null;
+    static final String nativeStreamMetadataFormatClassName = null;
+    static final String[] extraStreamMetadataFormatNames = null;
+    static final String[] extraStreamMetadataFormatClassNames = null;
+    static final boolean supportsStandardImageMetadataFormat = false;
+    static final String nativeImageMetadataFormatName =
+            "org.apache.harmony.x.imageio.plugins.jpeg.MyFormatMetadata_1.0";
+    static final String nativeImageMetadataFormatClassName =
+            "org.apache.harmony.x.imageio.plugins.jpeg.MyFormatMetadata";
+    static final String[] extraImageMetadataFormatNames = null;
+    static final String[] extraImageMetadataFormatClassNames = null;
+
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java
new file mode 100644
index 0000000..480041c
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java
@@ -0,0 +1,106 @@
+/*
+ *  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.
+ */
+
+
+package org.apache.harmony.x.imageio.plugins.png;
+
+import org.apache.harmony.awt.gl.image.DecodingImageSource;
+import org.apache.harmony.awt.gl.image.OffscreenImage;
+import org.apache.harmony.x.imageio.plugins.jpeg.IISDecodingImageSource;
+
+import javax.imageio.ImageReader;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageReadParam;
+import javax.imageio.plugins.jpeg.JPEGImageReadParam;
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.metadata.IIOMetadata;
+import java.io.IOException;
+import java.util.Iterator;
+import java.awt.image.BufferedImage;
+
+public class PNGImageReader  extends ImageReader {
+    ImageInputStream iis;
+
+    public PNGImageReader(ImageReaderSpi imageReaderSpi) {
+        super(imageReaderSpi);
+    }
+
+    public int getNumImages(boolean allowSearch) throws IOException {
+        //-- TODO imlement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    public int getWidth(int imageIndex) throws IOException {
+        //-- TODO imlement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    public int getHeight(int imageIndex) throws IOException {
+        //-- TODO imlement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
+        //-- TODO imlement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    @Override
+    public IIOMetadata getStreamMetadata() throws IOException {
+        //-- TODO imlement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    @Override
+    public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
+        //-- TODO imlement
+        throw new UnsupportedOperationException("not implemented yet");
+    }
+
+    @Override
+    public BufferedImage read(int i, ImageReadParam imageReadParam) throws IOException {
+        if (iis == null) {
+            throw new IllegalArgumentException("input stream == null");
+        }
+
+        DecodingImageSource source = new IISDecodingImageSource(iis);
+        OffscreenImage image = new OffscreenImage(source);
+        source.addConsumer(image);
+        source.load();
+        // The interrupted flag should be cleared because ImageDecoder interrupts
+        // current thread while decoding (due its architecture).
+        Thread.interrupted();
+        return image.getBufferedImage();
+    }
+
+    @Override
+    public BufferedImage read(int i) throws IOException {
+        return read(i, null);
+    }
+
+    @Override
+    public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
+        super.setInput(input, seekForwardOnly, ignoreMetadata);
+        iis = (ImageInputStream) input;
+    }
+
+    @Override
+    public ImageReadParam getDefaultReadParam() {
+        return new ImageReadParam();
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java
new file mode 100644
index 0000000..50f8b10
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java
@@ -0,0 +1,88 @@
+/*
+ *  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.
+ */
+
+
+package org.apache.harmony.x.imageio.plugins.png;
+
+import org.apache.harmony.x.imageio.plugins.jpeg.JPEGSpiConsts;
+
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.spi.ServiceRegistry;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+import java.io.IOException;
+import java.util.Locale;
+
+public class PNGImageReaderSpi extends ImageReaderSpi {
+    static final String PNG_NAMES[] = new String[] {"png", "PNG"};
+    static final String PNG_SUFFIXES[] = new String[] {"png"};
+    static final String PNG_MIME_TYPES[] = new String[] {"image/png"};
+    static final String PNG_READER_CLASS_NAME = "org.apache.harmony.x.imageio.plugins.png.PNGImageReader";
+    static final String PNG_READER_SPI_NAMES[] = {"org.apache.harmony.x.imageio.plugins.png.PNGImageReaderSpi"};
+
+    public PNGImageReaderSpi() {
+        super(
+                JPEGSpiConsts.vendorName, JPEGSpiConsts.version,
+                PNG_NAMES, PNG_SUFFIXES,
+                PNG_MIME_TYPES, PNG_READER_CLASS_NAME,
+                STANDARD_INPUT_TYPE, null,
+                false, null,
+                null, null,
+                null, false, 
+                null, null,
+                null, null
+        );
+    }
+
+    @Override
+    public boolean canDecodeInput(Object source) throws IOException {
+        ImageInputStream markable = (ImageInputStream) source;
+        markable.mark();
+
+        byte[] signature = new byte[8];
+        markable.seek(0);
+
+        int nBytes = markable.read(signature, 0, 8);
+        if(nBytes != 8) markable.read(signature, nBytes, 8-nBytes);
+        markable.reset();
+
+        // PNG signature: 137 80 78 71 13 10 26 10
+        return  (signature[0] & 0xFF) == 137 &&
+                (signature[1] & 0xFF) == 80 &&
+                (signature[2] & 0xFF) == 78 &&
+                (signature[3] & 0xFF) == 71 &&
+                (signature[4] & 0xFF) == 13 &&
+                (signature[5] & 0xFF) == 10 &&
+                (signature[6] & 0xFF) == 26 &&
+                (signature[7] & 0xFF) == 10;
+    }
+
+    @Override
+    public ImageReader createReaderInstance(Object extension) throws IOException {
+        return new PNGImageReader(this);
+    }
+
+    @Override
+    public String getDescription(Locale locale) {
+        return "DRL PNG decoder";
+    }
+
+    @Override
+    public void onRegistration(ServiceRegistry registry, Class<?> category) {
+        super.onRegistration(registry, category);
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java
new file mode 100644
index 0000000..e2a8d7d
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java
@@ -0,0 +1,247 @@
+/*
+ *  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.
+ */
+/**
+ * @author Viskov Nikolay
+ * @version $Revision$
+ */
+package org.apache.harmony.x.imageio.plugins.png;
+
+import com.android.internal.awt.ImageOutputStreamWrapper;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.awt.image.IndexColorModel;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+
+import javax.imageio.IIOImage;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.stream.ImageOutputStream;
+
+import org.apache.harmony.x.imageio.internal.nls.Messages;
+
+import org.apache.harmony.luni.util.NotImplementedException;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+
+public class PNGImageWriter extends ImageWriter {
+    
+    // /* ???AWT: Debugging
+    private static final boolean DEBUG = false;
+    private static Bitmap bm;
+    public static Bitmap getBitmap() {
+        return bm;
+    }
+    // */
+    
+    private static int[][] BAND_OFFSETS = {
+            {}, {
+                0 }, {
+                    0, 1 }, {
+                    0, 1, 2 }, {
+                    0, 1, 2, 3 } };
+
+    // Each pixel is a grayscale sample.
+    private static final int PNG_COLOR_TYPE_GRAY = 0;
+    // Each pixel is an R,G,B triple.
+    private static final int PNG_COLOR_TYPE_RGB = 2;
+    // Each pixel is a palette index, a PLTE chunk must appear.
+    private static final int PNG_COLOR_TYPE_PLTE = 3;
+    // Each pixel is a grayscale sample, followed by an alpha sample.
+    private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4;
+    // Each pixel is an R,G,B triple, followed by an alpha sample.
+    private static final int PNG_COLOR_TYPE_RGBA = 6;
+    
+    //???AWT: private static native void initIDs(Class<ImageOutputStream> iosClass);
+
+    static {
+        //???AWT
+        /*
+        System.loadLibrary("pngencoder"); //$NON-NLS-1$
+        initIDs(ImageOutputStream.class);
+        */
+    }
+    
+    /*
+    private native int encode(byte[] input, int bytesInBuffer, int bytePixelSize, Object ios, int imageWidth,
+            int imageHeight, int bitDepth, int colorType, int[] palette, int i, boolean b);
+    */
+    
+    protected PNGImageWriter(ImageWriterSpi iwSpi) {
+        super(iwSpi);
+    }
+
+    @Override
+    public IIOMetadata convertStreamMetadata(IIOMetadata arg0, ImageWriteParam arg1) {
+        throw new NotImplementedException();
+    }
+
+    @Override
+    public IIOMetadata convertImageMetadata(IIOMetadata arg0, ImageTypeSpecifier arg1, ImageWriteParam arg2) {
+        throw new NotImplementedException();
+    }
+
+    @Override
+    public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier arg0, ImageWriteParam arg1) {
+        throw new NotImplementedException();
+    }
+
+    @Override
+    public IIOMetadata getDefaultStreamMetadata(ImageWriteParam arg0) {
+        throw new NotImplementedException();
+    }
+
+    @Override
+    public void write(IIOMetadata streamMetadata, IIOImage iioImage, ImageWriteParam param) throws IOException {
+        if (output == null) {
+            throw new IllegalStateException("Output not been set");
+        }
+        if (iioImage == null) {
+            throw new IllegalArgumentException("Image equals null");
+        }
+        // AWT???: I think this is not needed anymore
+        // if (iioImage.hasRaster() && !canWriteRasters()) {
+        //    throw new UnsupportedOperationException("Can't write raster");
+        //}// ImageOutputStreamImpl
+        
+        Raster sourceRaster;
+        RenderedImage img = null;
+        if (!iioImage.hasRaster()) {
+            img = iioImage.getRenderedImage();
+            if (img instanceof BufferedImage) {
+                sourceRaster = ((BufferedImage) img).getRaster();
+            } else {
+                sourceRaster = img.getData();
+            }
+        } else {
+            sourceRaster = iioImage.getRaster();
+        }
+
+        SampleModel model = sourceRaster.getSampleModel();
+        int srcWidth = sourceRaster.getWidth();
+        int srcHeight = sourceRaster.getHeight();
+        int numBands = model.getNumBands();
+        
+        ColorModel colorModel = img.getColorModel();
+        int pixelSize = colorModel.getPixelSize();
+        int bytePixelSize = pixelSize / 8;
+        int bitDepth = pixelSize / numBands;
+        
+        // byte per band
+        int bpb = bitDepth > 8 ? 2 : 1;
+        
+        boolean isInterlace = true;
+        if (param instanceof PNGImageWriterParam) {
+            isInterlace = ((PNGImageWriterParam) param).getInterlace();
+        }
+        
+        int colorType = PNG_COLOR_TYPE_GRAY;
+        int[] palette = null;
+        
+        if (colorModel instanceof IndexColorModel) {
+            if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8) {
+//              Wrong bitDepth-numBands composition
+                throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$
+            }
+            if (numBands != 1) {
+//              Wrong bitDepth-numBands composition
+                throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$
+            }
+
+            IndexColorModel icm = (IndexColorModel) colorModel;
+            palette = new int[icm.getMapSize()];
+            icm.getRGBs(palette);
+            colorType = PNG_COLOR_TYPE_PLTE;
+        }
+        else if (numBands == 1) {
+            if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8 && bitDepth != 16) {
+//              Wrong bitDepth-numBands composition
+                throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$
+            }
+            colorType = PNG_COLOR_TYPE_GRAY;
+        }
+        else if (numBands == 2) {
+            if (bitDepth != 8 && bitDepth != 16) {
+//              Wrong bitDepth-numBands composition
+                throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$
+            }
+            colorType = PNG_COLOR_TYPE_GRAY_ALPHA;
+        }
+        else if (numBands == 3) {
+            if (bitDepth != 8 && bitDepth != 16) {
+//              Wrong bitDepth-numBands composition
+                throw new IllegalArgumentException(Messages.getString("imageio.1")); //$NON-NLS-1$
+            }
+            colorType = PNG_COLOR_TYPE_RGB;
+        }
+        else if (numBands == 4) {
+            if (bitDepth != 8 && bitDepth != 16) {
+                //Wrong bitDepth-numBands composition
+                throw new IllegalArgumentException(Messages.getString("imageio.1")); //$NON-NLS-1$
+            }
+            colorType = PNG_COLOR_TYPE_RGBA;
+        }
+        
+        /* ???AWT: I think this is not needed anymore
+        int dbufferLenght = bytePixelSize * imageHeight * imageWidth;
+        DataBufferByte dbuffer = new DataBufferByte(dbufferLenght);
+
+        WritableRaster scanRaster = Raster.createInterleavedRaster(dbuffer, imageWidth, imageHeight, bpb * numBands
+                * imageWidth, bpb * numBands, BAND_OFFSETS[numBands], null);
+
+        scanRaster.setRect(((BufferedImage) image).getRaster()// image.getData()
+                .createChild(0, 0, imageWidth, imageHeight, 0, 0, null));
+        */
+
+        if (DEBUG) {
+            System.out.println("**** raster:" + sourceRaster);        
+            System.out.println("**** model:" + model);
+            System.out.println("**** type:" + colorType);
+        }
+        
+        if (model instanceof SinglePixelPackedSampleModel) {
+            DataBufferInt ibuf = (DataBufferInt)sourceRaster.getDataBuffer();
+            int[] pixels = ibuf.getData();
+            
+            // Create a bitmap with the pixel
+            bm = Bitmap.createBitmap(pixels, srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
+            
+            // Use Bitmap.compress() to write the image
+            ImageOutputStream ios = (ImageOutputStream) getOutput();
+            ImageOutputStreamWrapper iosw = new ImageOutputStreamWrapper(ios);
+            bm.compress(CompressFormat.PNG, 100, iosw);
+        } else {
+            // ???AWT: Add support for other color models
+            throw new RuntimeException("Color model not supported yet");
+        }
+    }
+
+    public ImageWriteParam getDefaultWriteParam() {
+        return new PNGImageWriterParam();
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java
new file mode 100644
index 0000000..bf3a000
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java
@@ -0,0 +1,41 @@
+/*
+ *  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.
+ */
+/**
+ * @author Viskov Nikolay
+ * @version $Revision$
+ */
+package org.apache.harmony.x.imageio.plugins.png;
+
+import javax.imageio.ImageWriteParam;
+
+public class PNGImageWriterParam extends ImageWriteParam {
+
+    private boolean isInterlace = true;
+
+    public PNGImageWriterParam() {
+        super();
+    }
+
+    public boolean getInterlace() {
+        return isInterlace;
+    }
+
+    public void setInterlace(boolean b) {
+        isInterlace = b;
+    }
+
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java
new file mode 100644
index 0000000..6eed14d
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java
@@ -0,0 +1,113 @@
+/*
+ *  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.
+ */
+/**
+ * @author Viskov Nikolay
+ * @version $Revision$
+ */
+package org.apache.harmony.x.imageio.plugins.png;
+
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferByte;
+import java.awt.image.IndexColorModel;
+import java.io.IOException;
+import java.util.Locale;
+
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriter;
+import javax.imageio.spi.ImageWriterSpi;
+
+public class PNGImageWriterSpi extends ImageWriterSpi {
+
+    public PNGImageWriterSpi() {
+        super("Intel Corporation",// vendorName
+                "1.0",// version
+                new String[] {
+                        "png", "PNG" },// names
+                new String[] {
+                        "png", "PNG" },// suffixes
+                new String[] {
+                    "image/png" },// MIMETypes
+                "org.apache.harmony.x.imageio.plugins.png.PNGImageWriter",// writerClassName
+                STANDARD_OUTPUT_TYPE,// outputTypes
+                new String[] {
+                    "org.apache.harmony.x.imageio.plugins.png.PNGImageWriterSpi" },// readerSpiNames
+                false,// supportsStandardStreamMetadataFormat
+                null,// nativeStreamMetadataFormatName
+                null,// nativeStreamMetadataFormatClassName
+                null,// extraStreamMetadataFormatNames
+                null,// extraStreamMetadataFormatClassNames
+                false,// supportsStandardImageMetadataFormat
+                null,// nativeImageMetadataFormatName
+                null,// nativeImageMetadataFormatClassName
+                null,// extraImageMetadataFormatNames
+                null// extraImageMetadataFormatClassNames
+        );
+    }
+
+    @Override
+    public boolean canEncodeImage(ImageTypeSpecifier type) {
+        boolean canEncode = true;
+
+        int numBands = type.getSampleModel().getNumBands();
+
+        ColorModel colorModel = type.getColorModel();
+
+        int bitDepth = colorModel.getPixelSize() / numBands;
+
+        if (colorModel instanceof IndexColorModel) {
+            if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8) {
+                canEncode = false;
+            }
+            if (numBands != 1) {
+                canEncode = false;
+            }
+        }
+        else if (numBands == 1) {
+            if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8 && bitDepth != 16) {
+                canEncode = false;
+            }
+        }
+        else if (numBands == 2) {
+            if (bitDepth != 8 && bitDepth != 16) {
+                canEncode = false;
+            }
+        }
+        else if (numBands == 3) {
+            if (bitDepth != 8 && bitDepth != 16) {
+                canEncode = false;
+            }
+        }
+        else if (numBands == 4) {
+            if (bitDepth != 8 && bitDepth != 16) {
+                canEncode = false;
+            }
+        }
+
+        return canEncode;
+    }
+
+    @Override
+    public ImageWriter createWriterInstance(Object arg0) throws IOException {
+        return new PNGImageWriter(this);
+    }
+
+    @Override
+    public String getDescription(Locale arg0) {
+        return "DRL PNG encoder";
+    }
+
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/FileIISSpi.java b/awt/org/apache/harmony/x/imageio/spi/FileIISSpi.java
new file mode 100644
index 0000000..d4fdd76
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/FileIISSpi.java
@@ -0,0 +1,53 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageInputStreamSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.FileImageOutputStream;
+import javax.imageio.stream.FileImageInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Locale;
+
+public class FileIISSpi extends ImageInputStreamSpi {
+    private static final String vendor = "Apache";
+
+    private static final String ver = "0.1";
+
+    public FileIISSpi() {
+        super(vendor, ver, File.class);
+    }
+
+    @Override
+    public ImageInputStream createInputStreamInstance(Object input, boolean useCache,
+            File cacheDir) throws IOException {
+        if (File.class.isInstance(input)) {
+            return new FileImageInputStream((File) input);
+        }
+        throw new IllegalArgumentException("input is not an instance of java.io.File");
+    }
+
+    @Override
+    public String getDescription(Locale locale) {
+        return "File IIS Spi";
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/FileIOSSpi.java b/awt/org/apache/harmony/x/imageio/spi/FileIOSSpi.java
new file mode 100644
index 0000000..acda6a1
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/FileIOSSpi.java
@@ -0,0 +1,52 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageOutputStreamSpi;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.stream.FileImageOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Locale;
+
+public class FileIOSSpi extends ImageOutputStreamSpi {
+    private static final String vendor = "Apache";
+
+    private static final String ver = "0.1";
+
+    public FileIOSSpi() {
+        super(vendor, ver, File.class);
+    }
+
+    @Override
+    public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache,
+            File cacheDir) throws IOException {
+        if (output instanceof File) {
+            return new FileImageOutputStream((File) output);
+        }
+        throw new IllegalArgumentException("output is not instance of File");
+    }
+
+    @Override
+    public String getDescription(Locale locale) {
+        return "File IOS Spi";
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java b/awt/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java
new file mode 100644
index 0000000..ed2fef0
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java
@@ -0,0 +1,59 @@
+/*
+ *  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.
+ */
+
+
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageInputStreamSpi;
+import javax.imageio.stream.*;
+import java.io.OutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+
+public class InputStreamIISSpi extends ImageInputStreamSpi {
+    private static final String vendor = "Apache";
+
+    private static final String ver = "0.1";
+
+    public InputStreamIISSpi() {
+        super(vendor, ver, InputStream.class);
+    }
+
+    @Override
+    public String getDescription(Locale locale) {
+        return "Output Stream IOS Spi";
+    }
+
+    @Override
+    public boolean canUseCacheFile() {
+        return true;
+    }
+
+    @Override
+    public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) throws IOException {
+        if (input instanceof InputStream) {
+            if (useCache) {
+                return new FileCacheImageInputStream((InputStream) input, cacheDir);
+            } else {
+                return new MemoryCacheImageInputStream((InputStream) input);
+            }
+        }
+        throw new IllegalArgumentException("Output is not an instance of InputStream");
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java b/awt/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java
new file mode 100644
index 0000000..dd1e88d
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java
@@ -0,0 +1,60 @@
+/*
+ *  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.
+ */
+
+
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageOutputStreamSpi;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.stream.FileCacheImageOutputStream;
+import javax.imageio.stream.MemoryCacheImageOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Locale;
+
+public class OutputStreamIOSSpi extends ImageOutputStreamSpi {
+    private static final String vendor = "Apache";
+
+    private static final String ver = "0.1";
+
+    public OutputStreamIOSSpi() {
+        super(vendor, ver, OutputStream.class);
+    }
+
+    @Override
+    public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) throws IOException {
+        if (output instanceof OutputStream) {
+            if (useCache) {
+                return new FileCacheImageOutputStream((OutputStream) output, cacheDir);
+            } else {
+                return new MemoryCacheImageOutputStream((OutputStream) output);
+            }
+        }
+        throw new IllegalArgumentException("Output is not an instance of OutputStream");
+    }
+
+    @Override
+    public String getDescription(Locale locale) {
+        return "Output Stream IOS Spi";
+    }
+
+    @Override
+    public boolean canUseCacheFile() {
+        return true;
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/RAFIISSpi.java b/awt/org/apache/harmony/x/imageio/spi/RAFIISSpi.java
new file mode 100644
index 0000000..f97eb87
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/RAFIISSpi.java
@@ -0,0 +1,54 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageInputStreamSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.FileImageInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Locale;
+
+public class RAFIISSpi extends ImageInputStreamSpi {
+    private static final String vendor = "Apache";
+
+    private static final String ver = "0.1";
+
+    public RAFIISSpi() {
+        super(vendor, ver, RandomAccessFile.class);
+    }
+
+    @Override
+    public ImageInputStream createInputStreamInstance(Object input, boolean useCache,
+            File cacheDir) throws IOException {
+        if (RandomAccessFile.class.isInstance(input)) {
+            return new FileImageInputStream((RandomAccessFile) input);
+        }
+        throw new IllegalArgumentException(
+                "input is not an instance of java.io.RandomAccessFile");
+    }
+
+    @Override
+    public String getDescription(Locale locale) {
+        return "RandomAccessFile IIS Spi";
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java b/awt/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java
new file mode 100644
index 0000000..a9d3649
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java
@@ -0,0 +1,53 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageOutputStreamSpi;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.stream.FileImageOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Locale;
+
+public class RAFIOSSpi extends ImageOutputStreamSpi {
+    private static final String vendor = "Apache";
+
+    private static final String ver = "0.1";
+
+    public RAFIOSSpi() {
+        super(vendor, ver, RandomAccessFile.class);
+    }
+
+    @Override
+    public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache,
+            File cacheDir) throws IOException {
+        if (output instanceof RandomAccessFile) {
+            return new FileImageOutputStream((RandomAccessFile) output);
+        }
+        throw new IllegalArgumentException("output is not instance of java.io.RandomAccessFile");
+    }
+
+    @Override
+    public String getDescription(Locale locale) {
+        return "RandomAccessFile IOS Spi";
+    }
+}
diff --git a/awt/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java b/awt/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java
new file mode 100644
index 0000000..64f7b2a
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java
@@ -0,0 +1,226 @@
+/*
+ *  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.
+ */
+
+
+package org.apache.harmony.x.imageio.stream;
+
+import java.util.ArrayList;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public final class RandomAccessMemoryCache {
+    private static final int BLOCK_SHIFT = 9;
+    private static final int BLOCK_SIZE = 1 << BLOCK_SHIFT;
+    private static final int BLOCK_MASK = BLOCK_SIZE - 1;
+    
+    private long length;
+
+    private int firstUndisposed = 0;
+
+    private ArrayList<byte[]> blocks = new ArrayList<byte[]>();
+
+    public RandomAccessMemoryCache() {
+    }
+
+    public long length() {
+        return length;
+    }
+
+    public void close() {
+        blocks.clear();
+        length = 0;
+    }
+
+    private void grow(long pos) {
+        int blocksNeeded = (int)(pos >> BLOCK_SHIFT) - blocks.size() + 1;
+        for (int i=0; i < blocksNeeded; i++) {
+            blocks.add(new byte[BLOCK_SIZE]);
+        }
+
+        length = pos + 1;
+    }
+
+    public void putData(int oneByte, long pos) {
+        if (pos >= length) {
+            grow(pos);
+        }
+
+        byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT));
+        block[(int)(pos & BLOCK_MASK)] = (byte) oneByte;
+    }
+
+    public void putData(byte[] buffer, int offset, int count, long pos) {
+        if (count > buffer.length - offset || count < 0 || offset < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        if (count == 0){
+            return;
+        }
+
+        long lastPos = pos + count - 1;
+        if (lastPos >= length) {
+            grow(lastPos);
+        }
+
+        while (count > 0) {
+            byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT));
+            int blockOffset = (int)(pos & BLOCK_MASK);
+            int toCopy = Math.min(BLOCK_SIZE - blockOffset, count);
+            System.arraycopy(buffer, offset, block, blockOffset, toCopy);
+            pos += toCopy;
+            count -= toCopy;
+            offset += toCopy;
+        }
+    }
+
+    public int getData(long pos) {
+        if (pos >= length) {
+            return -1;
+        }
+
+        byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT));
+        return block[(int)(pos & BLOCK_MASK)] & 0xFF;
+    }
+
+    public int getData(byte[] buffer, int offset, int count, long pos) {
+        if (count > buffer.length - offset || count < 0 || offset < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        if (count == 0) {
+            return 0;
+        }
+        if (pos >= length) {
+            return -1;
+        }
+
+        if (count + pos > length) {
+            count = (int) (length - pos);
+        }
+
+        byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT));
+        int nbytes = Math.min(count, BLOCK_SIZE - (int)(pos & BLOCK_MASK));
+        System.arraycopy(block, (int)(pos & BLOCK_MASK), buffer, offset, nbytes);
+
+        return nbytes;
+    }
+    /*
+    public void seek(long pos) throws IOException {
+        if (pos < 0) {
+            throw new IOException("seek position is negative");
+        }
+        this.pos = pos; 
+    }
+
+    public void readFully(byte[] buffer) throws IOException {
+        readFully(buffer, 0, buffer.length);
+    }
+
+    public void readFully(byte[] buffer, int offset, int count) throws IOException {
+        if (0 <= offset && offset <= buffer.length && 0 <= count && count <= buffer.length - offset) {
+            while (count > 0) {
+                int result = read(buffer, offset, count);
+                if (result >= 0) {
+                    offset += result;
+                    count -= result;
+                } else {
+                    throw new EOFException();
+                }
+            }
+        } else {
+            throw new IndexOutOfBoundsException();
+        }
+    }
+
+    public long getFilePointer() {
+        return pos;
+    }
+*/
+
+    public void freeBefore(long pos) {
+        int blockIdx = (int)(pos >> BLOCK_SHIFT);
+        if (blockIdx <= firstUndisposed) { // Nothing to do
+            return;
+        }
+
+        for (int i = firstUndisposed; i < blockIdx; i++) {
+            blocks.set(i, null);
+        }
+
+        firstUndisposed = blockIdx;
+    }
+
+    public int appendData(InputStream is, int count) throws IOException {
+        if (count <= 0) {
+            return 0;
+        }
+
+        long startPos = length;
+        long lastPos = length + count - 1;
+        grow(lastPos); // Changes length
+
+        int blockIdx = (int)(startPos >> BLOCK_SHIFT);
+        int offset = (int) (startPos & BLOCK_MASK);
+
+        int bytesAppended = 0;
+
+        while (count > 0) {
+            byte[] block = blocks.get(blockIdx);
+            int toCopy = Math.min(BLOCK_SIZE - offset, count);
+            count -= toCopy;
+
+            while (toCopy > 0) {
+                int bytesRead = is.read(block, offset, toCopy);
+
+                if (bytesRead < 0) {
+                    length -= (count - bytesAppended);
+                    return bytesAppended;
+                }
+
+                toCopy -= bytesRead;
+                offset += bytesRead;
+            }
+
+            blockIdx++;
+            offset = 0;
+        }
+
+        return count;
+    }
+
+    public void getData(OutputStream os, int count, long pos) throws IOException {
+        if (pos + count > length) {
+            throw new IndexOutOfBoundsException("Argument out of cache");
+        }
+
+        int blockIdx = (int)(pos >> BLOCK_SHIFT);
+        int offset = (int) (pos & BLOCK_MASK);
+        if (blockIdx < firstUndisposed) {
+            throw new IndexOutOfBoundsException("The requested data are already disposed");
+        }
+
+        while (count > 0) {
+            byte[] block = blocks.get(blockIdx);
+            int toWrite = Math.min(BLOCK_SIZE - offset, count);
+            os.write(block, offset, toWrite);
+
+            blockIdx++;
+            offset = 0;
+            count -= toWrite;
+        }
+    }
+}
diff --git a/awt/resources/org/apache/harmony/awt/internal/nls/messages.properties b/awt/resources/org/apache/harmony/awt/internal/nls/messages.properties
new file mode 100644
index 0000000..9f647e9
--- /dev/null
+++ b/awt/resources/org/apache/harmony/awt/internal/nls/messages.properties
@@ -0,0 +1,495 @@
+# 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.
+# 
+
+# messages for EN locale
+awt.00=FontRenderContext is null
+awt.01='{0}' parameter is null
+awt.02='{0}' parameter has zero length
+awt.03='{0}' iterator parameter is null
+awt.04='{0}' iterator parameter has zero length
+awt.05=Operation cannot be null
+awt.06=Unexpected type of the internal data buffer
+awt.07=Transfer data is not available
+awt.08=xfld parse string error: {0}
+awt.09=min range bound value is greater than max range bound
+awt.0A=Cannot use SinglePixedPackedSampleModel for bpp = {0}
+awt.0B=Wrong color model created for drawable
+awt.0C=Unknown visual class
+awt.0D=Invalid transparency
+awt.0E=Dimensions of the image should be positive
+awt.0F=Cannot open display '{0}'
+awt.10=Only 32-bit format is supported for window state operations.
+awt.11=Invalid key code
+awt.12=XTest is not supported by your X server\!
+awt.13=Cannot allocate color named '{0}'
+awt.14=Transfer data is not available
+awt.15=Can not get monitor info
+awt.16=Can not create DC for device
+awt.17=Unknown Composite type : {0}
+awt.18=Transparency is not supported
+awt.19=Illegal size of volatile image
+awt.1A=Failed to register window class {0} GetLastError returned {1}
+awt.1B=Invalid key code
+awt.1C=Failure to create JavaWindow GetLastError returned {0}
+awt.1D=Cannot get data from OLE clipboard
+awt.1E=Attempt to replace WindowProc handler
+awt.1F=Waiting for resource access thread interrupted not from unlock method
+awt.20=Can't unlock not locked resource
+awt.21=Not owner can't unlock resource
+awt.22=Not owner can't free resource
+awt.23=One thread can't store state several times in a row
+awt.24=Owner can't overwrite resource state. Lock operations may be lost
+awt.25=No state stored for current thread
+awt.26=Shutdown thread was interrupted while starting
+awt.27=Shutdown thread was interrupted while stopping
+awt.28=bad index: {0}
+awt.29=Invalid range
+awt.2A=Position not represented by view
+awt.2B=No word at {0}
+awt.2C=Invalid position: {0}
+awt.2D=Invalid direction
+awt.2E={0} not in range {1},{2}
+awt.2F=No more words
+awt.30=wrong number of elements to copy: {0}, size: {1}
+awt.31=no room to copy: {0}, size: {1}
+awt.32=String: '{0}' does not fit
+awt.33=index is out of range
+awt.34=Initial offset in the destination array is wrong: {0}
+awt.35=Wrong number of elements to copy: {0}
+awt.36=Wrong segment
+awt.37=Unknown  composite type {0}
+awt.38=Property name is not defined
+awt.39=This method is not implemented for image obtained from ImageProducer
+awt.3A=Color Model is null
+awt.3B=Incorrect ImageConsumer completion status
+awt.3C=Unknown PNG color type
+awt.3D=Unknown colorspace
+awt.3E=Clone not supported
+awt.3F=Invalid baseline index
+awt.40=Wrong number of metrics\!
+awt.41=Font returned unsupported type of line metrics. This case is known, but not supported yet.
+awt.42=TextHitInfo out of range
+awt.43=glyphIndex is out of vector's limits
+awt.44=beginGlyphIndex is out of vector's range
+awt.45=numEntries is out of vector's range
+awt.46=length of setPositions array differs from the length of positions array
+awt.47=First argument should be byte or short array
+awt.48=The srcIn raster is incompatible with src ColorModel
+awt.49=The dstIn raster is incompatible with dst ColorModel
+awt.4A=The dstOut raster is incompatible with dst ColorModel
+awt.4B=Iterator out of bounds
+awt.4C=Invalid MultiRectArea in method {0}
+awt.4D=The raster is incompatible with this ColorModel
+awt.4E=Unknown native platform.
+awt.4F=Data is not available
+awt.50=Iterator is read-only
+awt.51=Component expected to be a parent
+awt.52=Time interval can't be <= 0
+awt.53=Handler can't be null
+awt.54=Key event for unfocused component
+awt.55=Double mouse enter event for component
+awt.56=Double mouse exit event for component
+awt.57=Double focus gained event for component
+awt.58=Double focus lost event for component
+awt.59=Application has run out of context thread group
+awt.5A=Default class for PrinterJob is not found
+awt.5B=No access to default class for PrinterJob
+awt.5C=Instantiation exception for PrinterJob
+awt.5D={0} is not supported
+awt.5E=pageIndex is more than book size
+awt.5F=wrong orientation
+awt.60=Width and Height mustn't be equal zero both
+awt.61=Unsupported data type: {0}
+awt.62=Wrong mask : {0}
+awt.63=Coordinates are not in bounds
+awt.64=The number of the bands in the subset is greater than the number of bands in the sample model
+awt.65=null argument
+awt.66=Invalid format
+awt.67=subclass is not derived from AWTKeyStroke
+awt.68=subclass could not be instantiated
+awt.69=columns less than zero.
+awt.6A=rows less than zero.
+awt.6B=Queue stack is empty
+awt.6C=Event queue stack is broken
+awt.6D=Point is null
+awt.6E=Color is null
+awt.6F=Index less than zero
+awt.70=MenuItem is null
+awt.71=Parent is null
+awt.72=Key event for unfocused component
+awt.73=no such item
+awt.74=Input parameters a and b should not be null
+awt.75=rows and cols cannot both be zero
+awt.76=rows and cols cannot be negative
+awt.77=default focus traversal policy cannot be null
+awt.78=invalid focus traversal key identifier
+awt.79=cannot set null focus traversal key
+awt.7A=focus traversal keys cannot map to KEY_TYPED events
+awt.7B=focus traversal keys must be unique for a Component
+awt.7C=this KeyboardFocusManager is not installed in the current thread's context
+awt.7D=Property name is null
+awt.7E=invalid hotSpot
+awt.7F=AddLayoutComponent: attempt to add null component
+awt.80=AddLayoutComponent: constraint object must be GridBagConstraints
+awt.81=AddLayoutComponent: {0}
+awt.82=RemoveLayoutComponent: attempt to remove null component
+awt.83=SetConstraints: attempt to get constraints of null component
+awt.84=SetConstraints: attempt to set null constraints
+awt.85=SetConstraints: {0}
+awt.86=MinimumLayoutSize: {0}
+awt.87=PreferredLayoutSize: {0}
+awt.88=LayoutContainer: {0}
+awt.89=LookupConstraints: attempt to get constraints of null component
+awt.8A=AdjustForGravity: attempt to use null constraints
+awt.8B=AdjustForGravity: attempt to use null rectangle
+awt.8C=AdjustForGravity: {0}
+awt.8D=REMINDER component expected after RELATIVE one
+awt.8E=component is out of grid's range
+awt.8F=Weights' overrides array is too long
+awt.90=Lengths' overrides array is too long
+awt.91=Unsupported constraints object: {0}
+awt.92=Constraints object must be String
+awt.93=cannot get component: invalid constraint: {0}
+awt.94=transform can not be null
+awt.95=Wrong start index: {0}
+awt.96=Wrong finish index: {0}
+awt.97=Wrong range length: {0}
+awt.98=Wrong count value, can not be negative: {0}
+awt.99=Wrong [start + count] is out of range: {0}
+awt.9A=Unsupported font format
+awt.9B=Can't create font - bad font data
+awt.9C=wrong value of GridBagConstraints: {0}
+awt.9D=relative grid size parameter goes after absolute grid coordinate
+awt.9E=wrong values sum of GridBagConstraints' gridwidth and gridx
+awt.9F=wrong values sum of GridBagConstraints' gridheight and gridy
+awt.100=component has RELATIVE width and height
+awt.101=position less than zero.
+awt.102=columns less than zero.
+awt.103=item is null
+awt.104=item doesn't exist in the choice menu
+awt.105=index less than zero
+awt.106=specified position is greater than the number of items
+awt.107=Color parameter outside of expected range: component {0}
+awt.108=Alpha value outside of expected range
+awt.109=Color parameter outside of expected range
+awt.10A=Priority must be a value between 0 and 1, inclusive
+awt.10B=aContainer and aComponent cannot be null
+awt.10C=aContainer is not a focus cycle root of aComponent
+awt.10D=aContainer should be focus cycle root or focus traversal policy provider
+awt.10E=focusCycleRoot cannot be null
+awt.10F=improper alignment: {0}
+awt.110=Iterator out of bounds
+awt.111=Parameter npoints is greater than array length
+awt.112=Negative number of points
+awt.113=illegal scrollbar orientation
+awt.114=Image is null
+awt.115=Anchor is null
+awt.116=Invalid value for media
+awt.117=Invalid value for orientationRequested
+awt.118=Invalid value for printerResolution
+awt.119=Invalid value for origin
+awt.11A=Invalid value for printQuality
+awt.11B=Invalid value for printerResolution[]
+awt.11C=Invalid value for color
+awt.11D=Unknown rule
+awt.11E=Wrong alpha value
+awt.11F=parent is not a component
+awt.120=origin is not a descendant of parent
+awt.121=parent must be showing on the screen
+awt.122=Does not support display mode changes
+awt.123=Unsupported display mode: {0}
+awt.124=Cannot change the modality while the dialog is visible
+awt.125=null owner window
+awt.126=Window is showing
+awt.127=Cannot change the decorations while the window is visible
+awt.128=Graphics environment is headless
+awt.129=Not a screen device
+awt.12A=illegal component position
+awt.12B=adding container to itself
+awt.12C=adding container's parent to itself
+awt.12D=adding a window to a container
+awt.12E=Unknown component event id
+awt.12F=Attempt to start nested mouse grab
+awt.130=Attempt to grab mouse in not displayable window
+awt.131=AddLayoutComponent: constraint object must be String
+awt.132=wrong parent for CardLayout
+awt.133=Negative width
+awt.134=Illegal cap
+awt.135=Illegal join
+awt.136=miterLimit less than 1.0f
+awt.137=Negative dashPhase
+awt.138=Zero dash length
+awt.139=Negative dash[{0}]
+awt.13A=All dash lengths zero
+awt.13B=offset off is out of range
+awt.13C=number of elemets len is out of range
+awt.13D=Rectangle width and height must be > 0
+awt.13E=Cannot call method from the event dispatcher thread
+awt.13F=Delay must be to 0 to 60,000ms
+awt.140=Invalid combination of button flags
+awt.141=failed to parse hotspot property for cursor: 
+awt.142=Exception: class {0} {1} occurred while loading: {2}
+awt.143=illegal cursor type
+awt.144=Can be set by scrollpane only
+awt.145=illegal file dialog mode
+awt.146=illegal scrollbar display policy
+awt.147=position greater than 0
+awt.148=child is null
+awt.149=ScrollPane controls layout
+awt.14A=Can not create VolatileImage with specified capabilities
+awt.14B=Only Canvas or Window is allowed
+awt.14C=Number of buffers must be greater than one
+awt.14D=Buffer capabilities should support flipping
+awt.14E=Component should be displayable
+awt.14F=invalid focus traversal key identifier
+awt.150=no parent
+awt.151=component must be showing on the screen to determine its location
+awt.152=Invalid number of copies
+awt.153=Invalid value for maxPage
+awt.154=Invalid value for minPage
+awt.155=Invalid value for fromPage
+awt.156=Invalid value for toPage
+awt.157=Invalid value for pageRanges
+awt.158=Invalid value for destination
+awt.159=Invalid value for dialog
+awt.15A=Invalid value for defaultSelection
+awt.15B=Invalid value for multipleDocumentHandling
+awt.15C=Invalid value for attribute sides
+awt.15D=Invalid colorspace
+awt.15E=Unknown component. Must be REDCOMPONENT, GREENCOMPONENT or BLUECOMPONENT.
+awt.15F=Profile class does not comply with ICC specification
+awt.160=Color space doesn't comply with ICC specification
+awt.161=Unable to open file {0}
+awt.162=Invalid ICC Profile Data
+awt.163=Can't open color profile
+awt.164=Not a predefined color space
+awt.165=Color space doesn't comply with ICC specification
+awt.166=TRC is not a simple gamma value
+awt.167=TRC is a gamma value, not a table
+awt.168=Invalid profile class
+awt.169=Component index out of range
+awt.16A=Invalid component index: {0}
+awt.16B=Not a predefined colorspace
+awt.16C=Can't load class: {0}
+awt.16D=Can't parse MIME type: {0}
+awt.16E=Transferable has null data
+awt.16F=Can't create reader for this representation class
+awt.170=Can't create default D&D cursor: {0}
+awt.171=Attempt to start a drag while an existing drag operation is still executing
+awt.172=Drag source is null
+awt.173=One listener is already exist
+awt.174=dgl is not current listener
+awt.175=Listener mismatch
+awt.176=DropTarget cannot be added as listener to itself
+awt.177=Invalid user action
+awt.178=Invalid source action
+awt.179=Context peer is null
+awt.17A=Trigger event is null
+awt.17B=Can't init ACTION_NONE drag
+awt.17C=Image offset is null
+awt.17D=Transferable is null
+awt.17E=Component associated with the trigger event is null
+awt.17F=DragSource for the trigger event is null
+awt.180=Source actions for the DragGestureRecognizer associated with the trigger event are equal to DnDConstants.ACTION_NONE
+awt.181=Attempt to register context as its listener
+awt.182=dsl is not current listener
+awt.183=Invalid status
+awt.184=Invalid action
+awt.185=Component is null
+awt.186=DragSource is null
+awt.187=Origin is null
+awt.188=Event list is null
+awt.189=Event list is empty
+awt.18A=Context is null
+awt.18B=Invalid button value
+awt.18C=Cannot invoke null runnable
+awt.18D=Source is null
+awt.18E=Wrong event id
+awt.18F=Text must be null for CARET_POSITION_CHANGED
+awt.190=Wrong committedCharacterCount
+awt.191=Invalid keyCode for KEY_TYPED event, must be VK_UNDEFINED
+awt.192=Invalid keyChar for KEY_TYPED event, can't be CHAR_UNDEFINED
+awt.193=Listener can't be zero
+awt.194=Unknown attribute name
+awt.195=Offset is out of bounds
+awt.196=Justification impossible, layout already justified
+awt.197=Endpoints are out of range
+awt.198=Illegal alignment argument
+awt.199=Illegal range argument value: {0}
+awt.19A=start or count arguments are out of text range
+awt.19B=count argument must be positive
+awt.19C=weight must be a positive number
+awt.19D=growLeftLimit must be a positive number
+awt.19E=growRightLimit must be a positive number
+awt.19F=incorrect value for shrinkPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value
+awt.200=incorrect value for growPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value
+awt.201=shrinkLeftLimit must be a positive number
+awt.202=shrinkRightLimit must be a positive number
+awt.203=Offset limit should be greater than current position
+awt.204=Determinant is zero
+awt.205=Invalid type of Arc: {0}
+awt.206=Flatness is less then zero
+awt.207=Limit is less then zero
+awt.208=Path is null
+awt.209=Invalid winding rule value
+awt.20A=First segment should be SEG_MOVETO type
+awt.20B=unknown input method highlight state
+awt.20C=Number of Bits equals to zero
+awt.20D=The number of bits per pixel is not a power of 2 or pixels span data element boundaries
+awt.20E=Data Bit offset is not a multiple of pixel bit stride
+awt.20F=Number of bands must be only 1
+awt.210=The component value for this ColorModel is signed
+awt.211=Pixel values for this ColorModel are not conveniently representable as a single int
+awt.212=There is more than one component in this ColorModel
+awt.213=This ComponentColorModel does not support the unnormalized form
+awt.214=This Color Model doesn't support this transferType
+awt.215=transferType is not one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE
+awt.216=The components array is not large enough to hold all the color and alpha components
+awt.217=The transfer type of this ComponentColorModel is not one of the following transfer types: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
+awt.218=The components array is not large enough to hold all the color and alpha components
+awt.219=This transferType is not supported by this color model
+awt.21A=This ComponentColorModel does not support this transferType
+awt.21B=The length of normComponents minus normOffset is less than numComponents
+awt.21C=The number of scale factors should not be zero
+awt.21D=Number of src bands ({0}) does not match number of dst bands ({1})
+awt.21E=Number of scaling constants is not equal to the number of bands
+awt.21F=Unable to transform source
+awt.220=Source should not have IndexColorModel
+awt.221=The imageType is TYPE_BYTE_BINARY and the color map has more than 16 entries
+awt.222=The imageType is not TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED
+awt.223=The imageType is not compatible with ColorModel
+awt.224=Unknown image type
+awt.225=Property name is null
+awt.226=Both tileX and tileY are not equal to 0
+awt.227=This image type can't have alpha
+awt.228=minX or minY of this raster not equal to zero
+awt.229=Number of components in the LUT does not match the number of bands
+awt.22A=Wrong type of pixels array
+awt.22B=Length of data should not be less than width*height
+awt.22C=Unknown data type {0}
+awt.22D=This transferType ( {0} ) is not supported by this color model
+awt.22E=w or h is less than or equal to zero
+awt.22F=The product of w and h is greater than Integer.MAX_VALUE
+awt.230=dataType is not one of the supported data types
+awt.231=Number of bands must be more then 0
+awt.232=Offset should be not less than zero
+awt.233=Number of components should be positive
+awt.234=Width or Height equals zero
+awt.235=Wrong Data Buffer type : {0}
+awt.236=The bits is less than 1 or greater than 32
+awt.237=Source and destinations rasters do not have the same number of bands
+awt.238=The number of arrays in the LookupTable does not meet the restrictions
+awt.239=The space is not a TYPE_RGB space
+awt.23A=The min/max normalized component values are not 0.0/1.0
+awt.23B=The mask of the {0} component is not contiguous
+awt.23C=The mask of the alpha component is not contiguous
+awt.23D=The mask of the red component is not contiguous
+awt.23E=The mask of the green component is not contiguous
+awt.23F=The mask of the blue component is not contiguous
+awt.240=The transferType not is one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT
+awt.241=Any offset between bands is greater than the Scanline stride
+awt.242=Pixel stride is less than any offset between bands
+awt.243=Product of Pixel stride and w is greater than Scanline stride
+awt.244=Width or Height of child Raster is less than or equal to zero
+awt.245=parentX disposes outside Raster
+awt.246=parentY disposes outside Raster
+awt.247=parentX + w results in integer overflow
+awt.248=parentY + h results in integer overflow
+awt.249=childMinX + w results in integer overflow
+awt.24A=childMinY + h results in integer overflow
+awt.24B=Pixel stride must be >= 0
+awt.24C=Scanline stride must be >= 0
+awt.24D=Bank Indices length must be equal Bank Offsets length
+awt.24E=Index of {0} bank must be >= 0
+awt.24F=Unable to invert transform {0}
+awt.250=Unknown interpolation type: {0}
+awt.251=Transformed width ({0}) and height ({1}) should be greater than 0
+awt.252=Source can't be same as the destination
+awt.253=Different number of bands in source and destination
+awt.254=Number of bands in the source raster ({0}) is incompatible with the matrix [{1}x{2}]
+awt.255=Number of bands in the destination raster ({0}) is incompatible with the matrix [{1}x{2}]
+awt.256=Source raster is null
+awt.257=Source raster is equal to destination
+awt.258=Number of source bands ({0}) is not equal to number of destination bands ({1})
+awt.259=Source image is null
+awt.25A=Source equals to destination
+awt.25B=Null ColorSpace passed as a parameter
+awt.25C=Null profiles passed as a parameter
+awt.25D=Source or destination color space is not defined
+awt.25E=Incorrect number of source raster bands. Should be equal to the number of color components of source colorspace.
+awt.25F=Incorrect number of destination raster bands. Should be equal to the number of color components of destination colorspace.
+awt.260=Incompatible rasters - width or height differs
+awt.261=Destination color space is undefined
+awt.262=Destionation color space should be defined
+awt.263=Incompatible images - width or height differs
+awt.264=Size of the color map is less than 1
+awt.265=The raster argument is not compatible with this IndexColorModel
+awt.266=The number of bits in a pixel is greater than 16
+awt.267=The transferType is invalid
+awt.268=The pixel is not a primitive array of type transferType
+awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT
+awt.26A=Incorrect ImageConsumer completion status
+awt.26B=The number of bits in the pixel values is less than 1
+awt.26C=bits is null
+awt.26D=The elements in bits is less than 0
+awt.26E=The sum of the number of bits in bits is less than 1
+awt.26F=The cspace is null
+awt.270=The transparency is not a valid value
+awt.271=The number of bits in bits is less than 1
+awt.272=The length of components minus offset is less than numComponents
+awt.273=The length of normComponents minus normOffset is less than numComponents
+awt.274=componentIdx is greater than the number of components or less than zero
+awt.275=This pixel representation is not suuported by tis Color Model
+awt.276=location.x + w or location.y + h results in integer overflow
+awt.277=bankIndices or bandOffsets is null
+awt.278=dataBuffer is null
+awt.279=bands is less than 1
+awt.27A=dataBuffer has more than one bank
+awt.27B=bandOffsets is null
+awt.27C=bandMasks is null
+awt.27D=bitsPerBand or bands is not greater than zero
+awt.27E=The product of bitsPerBand and bands is greater than the number of bits held by dataType
+awt.27F=SampleModel or DataBuffer is null
+awt.280=SampleModel is null
+awt.281=sampleModel, dataBuffer, aRegion or sampleModelTranslate is null
+awt.282=aRegion has width or height less than or equal to zero
+awt.283=Overflow X coordinate of Raster
+awt.284=Overflow Y coordinate of Raster
+awt.285=Width or Height of child Raster is less than or equal to zero
+awt.286=parentX disposes outside Raster
+awt.287=parentY disposes outside Raster
+awt.288=parentX + width results in integer overflow
+awt.289=parentY + height results in integer overflow
+awt.28A=childMinX + width results in integer overflow
+awt.28B=childMinY + height results in integer overflow
+awt.28C=Rect is null
+awt.28D=Length of dataArray[{0}] is less than size + offset[{1}]
+awt.28E=Length of dataArray is less than size + offset
+awt.28F=Source and destination rasters do not have the same width!
+awt.290=Source and destination rasters do not have the same height!
+awt.291=Source and destination images do not have the same width!
+awt.292=Source and destination images do not have the same height!
+awt.294=pixel is null
+awt.295=data is null
+awt.296=can't allocate memory on video card to create new display list
+awt.297=Invalid keyLocation
+awt.298=dataBuffer is too small
+
+awt.err.00=file dialog {0} error!
+awt.err.01=error: {0}
+awt.err.02=GDIPlus DrawDriverString error status = {0}
+awt.err.03=gdipDrawCompositeGlyphVector: GDIPlus DrawDriverString error status = {0}
+awt.err.04=gdipDrawCompositeGlyphVector: GDIPlus DrawDriverString error status = {0}
diff --git a/awt/resources/org/apache/harmony/beans/internals/nls/messages.properties b/awt/resources/org/apache/harmony/beans/internals/nls/messages.properties
new file mode 100644
index 0000000..72b1c8c
--- /dev/null
+++ b/awt/resources/org/apache/harmony/beans/internals/nls/messages.properties
@@ -0,0 +1,103 @@
+# 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.
+# 
+
+# messages for EN locale
+beans.00=no getter for {0} property
+beans.01=no property for name {0} is found
+beans.02=in DefaultPersistenceDelegate.mutatesTo() {0} : {1}
+beans.03=Target Bean class is null
+beans.04=bad property name
+beans.05=Modifier for setter method should be public.
+beans.06=Number of parameters in setter method is not equal to 1.
+beans.07=Parameter type in setter method does not corresponds to predefined.
+beans.08=Number of parameters in getter method is not equal to 0.
+beans.09=Parameter type in getter method does not corresponds to predefined.
+beans.0A=Modifier for getter method should be public.
+beans.0B=Exception in command execution
+beans.0C=source is null
+beans.0D=Error in expression: {0}
+beans.0E=Changes are null
+beans.0F=The new BeanContext can not be set
+beans.10=no node is found for statement with target = {0}
+beans.11=no getter for property {0} found
+beans.12=cannot access property {0} getter
+beans.13=no setter for property {0} found
+beans.14=Exception while finding property descriptor
+beans.15=The listener is null
+beans.16=The provider is null
+beans.17=The child is null
+beans.18=The requestor is null
+beans.19=The service class is null
+beans.1A=The service selector is null
+beans.1B=The service is null
+beans.1C=The event is null
+beans.1D=bean is null
+beans.1E=Illegal class name: {0}
+beans.1F=Method not found: get{0}
+beans.20=Method not found: set{0}
+beans.21=Modifier for indexed getter method should be public.
+beans.22=Number of parameters in getter method is not equal to 1.
+beans.23=Parameter in indexed getter method is not of integer type.
+beans.24=Parameter type in indexed getter method does not correspond to predefined.
+beans.25=Modifier for indexed setter method should be public.
+beans.26=Number of parameters in indexed setter method is not equal to 2.
+beans.27=First parameter type in indexed setter method should be int.
+beans.28=Second parameter type in indexed setter method does not corresponds to predefined.
+beans.29=Membership listener is null
+beans.2A=Target child can not be null
+beans.2B=Resource name can not be null
+beans.2C=The child can not be null
+beans.2D=Invalid resource
+beans.2E=PropertyVetoException was thrown while removing a child: {0}; Original error message:{1}
+beans.2F=Target child is null
+beans.30=PropertyVetoException was thrown while adding a child: {0}; Original error message:{1}
+beans.31=No valid method {0} for {1} found.
+beans.32=Cannot acquire event type from {0} listener.
+beans.33={0} does not return <void>
+beans.34={0} should have a single input parameter
+beans.35=Single parameter does not match to {0} class
+beans.36=No input params are allowed for getListenerMethod
+beans.37=Return type of getListenerMethod is not an array of listeners
+beans.38=Add and remove methods are not available
+beans.39=Cannot generate event set descriptor for name {0}.
+beans.3A=Event type with name {0} is not found.
+beans.3B=skipping expression {0}...
+beans.3C=Unknown method name for array
+beans.3D=First parameter in array getter(setter) is not of Integer type
+beans.3E=Illegal number of arguments in array getter
+beans.3F=Illegal number of arguments in array setter
+beans.40=No constructor for class {0} found
+beans.41=No method with name {0} is found
+beans.42=target is not generated: classname {0} is not found
+beans.43=Cannot convert {0} to char
+beans.44=for property {0} no getter(setter) is found
+beans.45=method name is not generated: error in getMethodName()
+beans.46=Not a valid child
+beans.47=Unable to instantiate property editor
+beans.48=Property editor is not assignable from the PropertyEditor interface
+beans.49=Child cannot implement both BeanContextChild and BeanContextProxy
+beans.4A=newInstance is null
+beans.4B=type is null
+beans.4C=encoder is null
+beans.4D=Invalid method call
+beans.4E=stopClass is not ancestor of beanClass
+beans.4F=search path is null
+beans.50=not an indexed property
+beans.51=Listener method {0} should have parameter of type {1}
+beans.52=listenerMethodName(s) is null
+beans.53=eventSetName is null
+beans.54=listenerType is null
+beans.55=Method is null
diff --git a/camera/libcameraservice/Android.mk b/camera/libcameraservice/Android.mk
new file mode 100644
index 0000000..2dfe659
--- /dev/null
+++ b/camera/libcameraservice/Android.mk
@@ -0,0 +1,59 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Set USE_CAMERA_STUB for non-emulator and non-simulator builds, if you want
+# the camera service to use the fake camera.  For emulator or simulator builds,
+# we always use the fake camera.
+
+ifeq ($(USE_CAMERA_STUB),)
+USE_CAMERA_STUB:=false
+ifneq ($(filter sooner generic sim,$(TARGET_DEVICE)),)
+USE_CAMERA_STUB:=true
+endif #libcamerastub
+endif
+
+ifeq ($(USE_CAMERA_STUB),true)
+#
+# libcamerastub
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=               \
+    CameraHardwareStub.cpp      \
+    FakeCamera.cpp
+
+LOCAL_MODULE:= libcamerastub
+
+LOCAL_SHARED_LIBRARIES:= libui
+
+include $(BUILD_STATIC_LIBRARY)
+endif # USE_CAMERA_STUB
+
+#
+# libcameraservice
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=               \
+    CameraService.cpp
+
+LOCAL_SHARED_LIBRARIES:= \
+    libui \
+    libutils \
+    libcutils
+
+LOCAL_MODULE:= libcameraservice
+
+LOCAL_CFLAGS+=-DLOG_TAG=\"CameraService\"
+
+ifeq ($(USE_CAMERA_STUB), true)
+LOCAL_STATIC_LIBRARIES += libcamerastub
+LOCAL_CFLAGS += -include CameraHardwareStub.h
+else
+LOCAL_SHARED_LIBRARIES += libcamera 
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp
new file mode 100644
index 0000000..0f1ae8e
--- /dev/null
+++ b/camera/libcameraservice/CameraHardwareStub.cpp
@@ -0,0 +1,388 @@
+/*
+**
+** Copyright 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.
+*/
+
+#define LOG_TAG "CameraHardwareStub"
+#include <utils/Log.h>
+
+#include "CameraHardwareStub.h"
+#include <utils/threads.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "CannedJpeg.h"
+
+namespace android {
+
+CameraHardwareStub::CameraHardwareStub()
+                  : mParameters(),
+                    mPreviewHeap(0),
+                    mRawHeap(0),
+                    mFakeCamera(0),
+                    mPreviewFrameSize(0),
+                    mRawPictureCallback(0),
+                    mJpegPictureCallback(0),
+                    mPictureCallbackCookie(0),
+                    mPreviewCallback(0),
+                    mPreviewCallbackCookie(0),
+                    mAutoFocusCallback(0),
+                    mAutoFocusCallbackCookie(0),
+                    mCurrentPreviewFrame(0)
+{
+    initDefaultParameters();
+}
+
+void CameraHardwareStub::initDefaultParameters()
+{
+    CameraParameters p;
+
+    p.setPreviewSize(176, 144);
+    p.setPreviewFrameRate(15);
+    p.setPreviewFormat("yuv422sp");
+
+    p.setPictureSize(kCannedJpegWidth, kCannedJpegHeight);
+    p.setPictureFormat("jpeg");
+
+    if (setParameters(p) != NO_ERROR) {
+        LOGE("Failed to set default parameters?!");
+    } 
+}
+
+void CameraHardwareStub::initHeapLocked()
+{
+    // Create raw heap.
+    int picture_width, picture_height;
+    mParameters.getPictureSize(&picture_width, &picture_height);
+    mRawHeap = new MemoryHeapBase(picture_width * 2 * picture_height);
+
+    int preview_width, preview_height;
+    mParameters.getPreviewSize(&preview_width, &preview_height);
+    LOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height);
+
+    // Note that we enforce yuv422 in setParameters().
+    int how_big = preview_width * preview_height * 2;
+
+    // If we are being reinitialized to the same size as before, no
+    // work needs to be done.
+    if (how_big == mPreviewFrameSize)
+        return;
+
+    mPreviewFrameSize = how_big;
+
+    // Make a new mmap'ed heap that can be shared across processes. 
+    // use code below to test with pmem
+    mPreviewHeap = new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
+    // Make an IMemory for each frame so that we can reuse them in callbacks.
+    for (int i = 0; i < kBufferCount; i++) {
+        mBuffers[i] = new MemoryBase(mPreviewHeap, i * mPreviewFrameSize, mPreviewFrameSize);
+    }
+    
+    // Recreate the fake camera to reflect the current size.
+    delete mFakeCamera;
+    mFakeCamera = new FakeCamera(preview_width, preview_height);
+}
+
+CameraHardwareStub::~CameraHardwareStub()
+{
+    delete mFakeCamera;
+    mFakeCamera = 0; // paranoia
+    singleton.clear();
+}
+
+sp<IMemoryHeap> CameraHardwareStub::getPreviewHeap() const
+{
+    return mPreviewHeap;
+}
+
+sp<IMemoryHeap> CameraHardwareStub::getRawHeap() const
+{
+    return mRawHeap;
+}
+
+// ---------------------------------------------------------------------------
+
+int CameraHardwareStub::previewThread()
+{
+    mLock.lock();
+        // the attributes below can change under our feet...
+
+        int previewFrameRate = mParameters.getPreviewFrameRate();
+
+        // Find the offset within the heap of the current buffer.
+        ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize;
+
+        sp<MemoryHeapBase> heap = mPreviewHeap;
+    
+        // this assumes the internal state of fake camera doesn't change
+        // (or is thread safe)
+        FakeCamera* fakeCamera = mFakeCamera;
+        
+        sp<MemoryBase> buffer = mBuffers[mCurrentPreviewFrame];
+        
+    mLock.unlock();
+
+    // TODO: here check all the conditions that could go wrong
+    if (buffer != 0) {
+        // Calculate how long to wait between frames.
+        int delay = (int)(1000000.0f / float(previewFrameRate));
+    
+        // This is always valid, even if the client died -- the memory
+        // is still mapped in our process.
+        void *base = heap->base();
+    
+        // Fill the current frame with the fake camera.
+        uint8_t *frame = ((uint8_t *)base) + offset;
+        fakeCamera->getNextFrameAsYuv422(frame);
+    
+        //LOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
+        
+        // Notify the client of a new frame.
+        mPreviewCallback(buffer, mPreviewCallbackCookie);
+    
+        // Advance the buffer pointer.
+        mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
+
+        // Wait for it...
+        usleep(delay);
+    }
+
+    return NO_ERROR;
+}
+
+status_t CameraHardwareStub::startPreview(preview_callback cb, void* user)
+{
+    Mutex::Autolock lock(mLock);
+    if (mPreviewThread != 0) {
+        // already running
+        return INVALID_OPERATION;
+    }
+    mPreviewCallback = cb;
+    mPreviewCallbackCookie = user;
+    mPreviewThread = new PreviewThread(this);
+    return NO_ERROR;
+}
+
+void CameraHardwareStub::stopPreview()
+{
+    sp<PreviewThread> previewThread;
+    
+    { // scope for the lock
+        Mutex::Autolock lock(mLock);
+        previewThread = mPreviewThread;
+    }
+
+    // don't hold the lock while waiting for the thread to quit
+    if (previewThread != 0) {
+        previewThread->requestExitAndWait();
+    }
+
+    Mutex::Autolock lock(mLock);
+    mPreviewThread.clear();
+}
+
+bool CameraHardwareStub::previewEnabled() {
+    return mPreviewThread != 0;
+}
+
+status_t CameraHardwareStub::startRecording(recording_callback cb, void* user)
+{
+    return UNKNOWN_ERROR;
+}
+
+void CameraHardwareStub::stopRecording()
+{
+}
+
+bool CameraHardwareStub::recordingEnabled()
+{
+    return false;
+}
+
+void CameraHardwareStub::releaseRecordingFrame(const sp<IMemory>& mem)
+{
+}
+
+// ---------------------------------------------------------------------------
+
+int CameraHardwareStub::beginAutoFocusThread(void *cookie)
+{
+    CameraHardwareStub *c = (CameraHardwareStub *)cookie;
+    return c->autoFocusThread();
+}
+
+int CameraHardwareStub::autoFocusThread()
+{
+    if (mAutoFocusCallback != NULL) {
+        mAutoFocusCallback(true, mAutoFocusCallbackCookie);
+        mAutoFocusCallback = NULL;
+        return NO_ERROR;
+    }
+    return UNKNOWN_ERROR;
+}
+
+status_t CameraHardwareStub::autoFocus(autofocus_callback af_cb,
+                                       void *user)
+{
+    Mutex::Autolock lock(mLock);
+
+    if (mAutoFocusCallback != NULL) {
+        return mAutoFocusCallback == af_cb ? NO_ERROR : INVALID_OPERATION;
+    }
+
+    mAutoFocusCallback = af_cb;
+    mAutoFocusCallbackCookie = user;
+    if (createThread(beginAutoFocusThread, this) == false)
+        return UNKNOWN_ERROR;
+    return NO_ERROR;
+}
+
+/*static*/ int CameraHardwareStub::beginPictureThread(void *cookie)
+{
+    CameraHardwareStub *c = (CameraHardwareStub *)cookie;
+    return c->pictureThread();
+}
+
+int CameraHardwareStub::pictureThread()
+{
+    if (mShutterCallback)
+        mShutterCallback(mPictureCallbackCookie);
+
+    if (mRawPictureCallback) {
+        //FIXME: use a canned YUV image!
+        // In the meantime just make another fake camera picture.
+        int w, h;
+        mParameters.getPictureSize(&w, &h);
+        sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * 2 * h);
+        FakeCamera cam(w, h);
+        cam.getNextFrameAsYuv422((uint8_t *)mRawHeap->base());
+        if (mRawPictureCallback)
+            mRawPictureCallback(mem, mPictureCallbackCookie);
+    }
+
+    if (mJpegPictureCallback) {
+        sp<MemoryHeapBase> heap = new MemoryHeapBase(kCannedJpegSize);
+        sp<MemoryBase> mem = new MemoryBase(heap, 0, kCannedJpegSize);
+        memcpy(heap->base(), kCannedJpeg, kCannedJpegSize);
+        if (mJpegPictureCallback)
+            mJpegPictureCallback(mem, mPictureCallbackCookie);
+    }
+    return NO_ERROR;
+}
+
+status_t CameraHardwareStub::takePicture(shutter_callback shutter_cb,
+                                         raw_callback raw_cb,
+                                         jpeg_callback jpeg_cb,
+                                         void* user)
+{
+    stopPreview();
+    mShutterCallback = shutter_cb;
+    mRawPictureCallback = raw_cb;
+    mJpegPictureCallback = jpeg_cb;
+    mPictureCallbackCookie = user;
+    if (createThread(beginPictureThread, this) == false)
+        return -1;
+    return NO_ERROR;
+}
+
+status_t CameraHardwareStub::cancelPicture(bool cancel_shutter,
+                                           bool cancel_raw,
+                                           bool cancel_jpeg)
+{
+    if (cancel_shutter) mShutterCallback = NULL;
+    if (cancel_raw) mRawPictureCallback = NULL;
+    if (cancel_jpeg) mJpegPictureCallback = NULL;
+    return NO_ERROR;
+}
+
+status_t CameraHardwareStub::dump(int fd, const Vector<String16>& args) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    AutoMutex lock(&mLock);
+    if (mFakeCamera != 0) {
+        mFakeCamera->dump(fd, args);
+        mParameters.dump(fd, args);
+        snprintf(buffer, 255, " preview frame(%d), size (%d), running(%s)\n", mCurrentPreviewFrame, mPreviewFrameSize, mPreviewRunning?"true": "false");
+        result.append(buffer);
+    } else {
+        result.append("No camera client yet.\n");
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t CameraHardwareStub::setParameters(const CameraParameters& params)
+{
+    Mutex::Autolock lock(mLock);
+    // XXX verify params
+
+    if (strcmp(params.getPreviewFormat(), "yuv422sp") != 0) {
+        LOGE("Only yuv422sp preview is supported");
+        return -1;
+    }
+
+    if (strcmp(params.getPictureFormat(), "jpeg") != 0) {
+        LOGE("Only jpeg still pictures are supported");
+        return -1;
+    }
+
+    int w, h;
+    params.getPictureSize(&w, &h);
+    if (w != kCannedJpegWidth && h != kCannedJpegHeight) {
+        LOGE("Still picture size must be size of canned JPEG (%dx%d)",
+             kCannedJpegWidth, kCannedJpegHeight);
+        return -1;
+    }
+
+    mParameters = params;
+
+    initHeapLocked();
+
+    return NO_ERROR;
+}
+
+CameraParameters CameraHardwareStub::getParameters() const
+{
+    Mutex::Autolock lock(mLock);
+    return mParameters;
+}
+
+void CameraHardwareStub::release()
+{
+}
+
+wp<CameraHardwareInterface> CameraHardwareStub::singleton;
+
+sp<CameraHardwareInterface> CameraHardwareStub::createInstance()
+{
+    if (singleton != 0) {
+        sp<CameraHardwareInterface> hardware = singleton.promote();
+        if (hardware != 0) {
+            return hardware;
+        }
+    }
+    sp<CameraHardwareInterface> hardware(new CameraHardwareStub());
+    singleton = hardware;
+    return hardware;
+}
+
+extern "C" sp<CameraHardwareInterface> openCameraHardware()
+{
+    return CameraHardwareStub::createInstance();
+}
+
+}; // namespace android
diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h
new file mode 100644
index 0000000..0d26d47
--- /dev/null
+++ b/camera/libcameraservice/CameraHardwareStub.h
@@ -0,0 +1,124 @@
+/*
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_STUB_H
+#define ANDROID_HARDWARE_CAMERA_HARDWARE_STUB_H
+
+#include "FakeCamera.h"
+#include <utils/threads.h>
+#include <ui/CameraHardwareInterface.h>
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class CameraHardwareStub : public CameraHardwareInterface {
+public:
+    virtual sp<IMemoryHeap> getPreviewHeap() const;
+    virtual sp<IMemoryHeap> getRawHeap() const;
+
+    virtual status_t    startPreview(preview_callback cb, void* user);
+    virtual void        stopPreview();
+    virtual bool        previewEnabled();
+
+    virtual status_t    startRecording(recording_callback cb, void* user);
+    virtual void        stopRecording();
+    virtual bool        recordingEnabled();
+    virtual void        releaseRecordingFrame(const sp<IMemory>& mem);
+
+    virtual status_t    autoFocus(autofocus_callback, void *user);
+    virtual status_t    takePicture(shutter_callback,
+                                    raw_callback,
+                                    jpeg_callback,
+                                    void* user);
+    virtual status_t    cancelPicture(bool cancel_shutter,
+                                      bool cancel_raw,
+                                      bool cancel_jpeg);
+    virtual status_t    dump(int fd, const Vector<String16>& args) const;
+    virtual status_t    setParameters(const CameraParameters& params);
+    virtual CameraParameters  getParameters() const;
+    virtual void release();
+
+    static sp<CameraHardwareInterface> createInstance();
+
+private:
+                        CameraHardwareStub();
+    virtual             ~CameraHardwareStub();
+
+    static wp<CameraHardwareInterface> singleton;
+
+    static const int kBufferCount = 4;
+
+    class PreviewThread : public Thread {
+        CameraHardwareStub* mHardware;
+    public:
+        PreviewThread(CameraHardwareStub* hw)
+            : Thread(false), mHardware(hw) { }
+        virtual void onFirstRef() {
+            run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
+        }
+        virtual bool threadLoop() {
+            mHardware->previewThread();
+            // loop until we need to quit
+            return true;
+        }
+    };
+
+    void initDefaultParameters();
+    void initHeapLocked();
+
+    int previewThread();
+
+    static int beginAutoFocusThread(void *cookie);
+    int autoFocusThread();
+
+    static int beginPictureThread(void *cookie);
+    int pictureThread();
+
+    mutable Mutex       mLock;
+
+    CameraParameters    mParameters;
+
+    sp<MemoryHeapBase>  mPreviewHeap;
+    sp<MemoryHeapBase>  mRawHeap;
+    sp<MemoryBase>      mBuffers[kBufferCount];
+
+    FakeCamera          *mFakeCamera;
+    bool                mPreviewRunning;
+    int                 mPreviewFrameSize;
+
+    shutter_callback    mShutterCallback;
+    raw_callback        mRawPictureCallback;
+    jpeg_callback       mJpegPictureCallback;
+    void                *mPictureCallbackCookie;
+
+    // protected by mLock
+    sp<PreviewThread>   mPreviewThread;
+    preview_callback    mPreviewCallback;
+    void                *mPreviewCallbackCookie;
+
+    autofocus_callback  mAutoFocusCallback;
+    void                *mAutoFocusCallbackCookie;
+
+    // only used from PreviewThread
+    int                 mCurrentPreviewFrame;
+};
+
+}; // namespace android
+
+#endif
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
new file mode 100644
index 0000000..15e3b21
--- /dev/null
+++ b/camera/libcameraservice/CameraService.cpp
@@ -0,0 +1,1073 @@
+/*
+**
+** Copyright (C) 2008, The Android Open Source Project
+** Copyright (C) 2008 HTC Inc.
+**
+** 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CameraService"
+#include <utils/Log.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/IPCThreadState.h>
+#include <utils/String16.h>
+#include <utils/Errors.h>
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapBase.h>
+#include <ui/ICameraService.h>
+
+#include "CameraService.h"
+
+namespace android {
+
+extern "C" {
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pthread.h>
+}
+
+// When you enable this, as well as DEBUG_REFS=1 and
+// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp, this will track all
+// references to the CameraService::Client in order to catch the case where the
+// client is being destroyed while a callback from the CameraHardwareInterface
+// is outstanding.  This is a serious bug because if we make another call into
+// CameraHardwreInterface that itself triggers a callback, we will deadlock.
+
+#define DEBUG_CLIENT_REFERENCES 0
+
+#define PICTURE_TIMEOUT seconds(5)
+
+#define DEBUG_DUMP_PREVIEW_FRAME_TO_FILE 0 /* n-th frame to write */
+#define DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE 0
+#define DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE 0
+
+#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
+static int debug_frame_cnt;
+#endif
+
+// ----------------------------------------------------------------------------
+
+void CameraService::instantiate() {
+    defaultServiceManager()->addService(
+            String16("media.camera"), new CameraService());
+}
+
+// ----------------------------------------------------------------------------
+
+CameraService::CameraService() :
+    BnCameraService()
+{
+    LOGI("CameraService started: pid=%d", getpid());
+}
+
+CameraService::~CameraService()
+{
+    if (mClient != 0) {
+        LOGE("mClient was still connected in destructor!");
+    }
+}
+
+sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient)
+{
+    LOGD("Connect E from ICameraClient %p", cameraClient->asBinder().get());
+
+    Mutex::Autolock lock(mLock);
+    sp<Client> client;
+    if (mClient != 0) {
+        sp<Client> currentClient = mClient.promote();
+        if (currentClient != 0) {
+            sp<ICameraClient> currentCameraClient(currentClient->getCameraClient());
+            if (cameraClient->asBinder() == currentCameraClient->asBinder()) {
+                // this is the same client reconnecting...
+                LOGD("Connect X same client (%p) is reconnecting...", cameraClient->asBinder().get());
+                return currentClient;
+            } else {
+                // it's another client... reject it
+                LOGD("new client (%p) attempting to connect - rejected", cameraClient->asBinder().get());
+                return client;
+            }
+        } else {
+            // can't promote, the previous client has died...
+            LOGD("new client connecting, old reference was dangling...");
+            mClient.clear();
+        }
+    }
+
+    // create a new Client object
+    client = new Client(this, cameraClient, IPCThreadState::self()->getCallingPid());
+    mClient = client;
+#if DEBUG_CLIENT_REFERENCES
+    // Enable tracking for this object, and track increments and decrements of
+    // the refcount.
+    client->trackMe(true, true);
+#endif
+    LOGD("Connect X");
+    return client;
+}
+
+void CameraService::removeClient(const sp<ICameraClient>& cameraClient)
+{
+    // declar this outside the lock to make absolutely sure the
+    // destructor won't be called with the lock held.
+    sp<Client> client;
+
+    Mutex::Autolock lock(mLock);
+
+    if (mClient == 0) {
+        // This happens when we have already disconnected.
+        LOGV("mClient is null.");
+        return;
+    }
+
+    // Promote mClient. It should never fail because we're called from
+    // a binder call, so someone has to have a strong reference.
+    client = mClient.promote();
+    if (client == 0) {
+        LOGW("can't get a strong reference on mClient!");
+        mClient.clear();
+        return;
+    }
+
+    if (cameraClient->asBinder() != client->getCameraClient()->asBinder()) {
+        // ugh! that's not our client!!
+        LOGW("removeClient() called, but mClient doesn't match!");
+    } else {
+        // okay, good, forget about mClient
+        mClient.clear();
+    }
+}
+
+CameraService::Client::Client(const sp<CameraService>& cameraService,
+        const sp<ICameraClient>& cameraClient, pid_t clientPid)
+{
+    LOGD("Client E constructor");
+    mCameraService = cameraService;
+    mCameraClient = cameraClient;
+    mClientPid = clientPid;
+    mHardware = openCameraHardware();
+    mUseOverlay = mHardware->useOverlay();
+
+    // Callback is disabled by default
+    mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+    LOGD("Client X constructor");
+}
+
+status_t CameraService::Client::checkPid()
+{
+    if (mClientPid == IPCThreadState::self()->getCallingPid()) return NO_ERROR;
+    LOGW("Attempt to use locked camera (%p) from different process", getCameraClient()->asBinder().get());
+    return -EBUSY;
+}
+
+status_t CameraService::Client::lock()
+{
+    Mutex::Autolock _l(mLock);
+    // lock camera to this client if the the camera is unlocked
+    if (mClientPid == 0) {
+        mClientPid = IPCThreadState::self()->getCallingPid();
+        return NO_ERROR;
+    }
+    // returns NO_ERROR if the client already owns the camera, -EBUSY otherwise
+    return checkPid();
+}
+
+status_t CameraService::Client::unlock()
+{
+    Mutex::Autolock _l(mLock);
+    // allow anyone to use camera
+    LOGV("unlock (%p)", getCameraClient()->asBinder().get());
+    status_t result = checkPid();
+    if (result == NO_ERROR) mClientPid = 0;
+    return result;
+}
+
+status_t CameraService::Client::connect(const sp<ICameraClient>& client)
+{
+    // connect a new process to the camera
+    LOGV("connect (%p)", client->asBinder().get());
+
+    // I hate this hack, but things get really ugly when the media recorder
+    // service is handing back the camera to the app. The ICameraClient
+    // destructor will be called during the same IPC, making it look like
+    // the remote client is trying to disconnect. This hack temporarily
+    // sets the mClientPid to an invalid pid to prevent the hardware from
+    //  being torn down.
+    {
+
+        // hold a reference to the old client or we will deadlock if the client is
+        // in the same process and we hold the lock when we remove the reference
+        sp<ICameraClient> oldClient;
+        {
+            Mutex::Autolock _l(mLock);
+            if (mClientPid != 0) {
+                LOGW("Tried to connect to locked camera");
+                return -EBUSY;
+            }
+            oldClient = mCameraClient;
+
+            // did the client actually change?
+            if (client->asBinder() == mCameraClient->asBinder()) return NO_ERROR;
+
+            mCameraClient = client;
+            mClientPid = -1;
+            mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+            LOGV("connect new process (%d) to existing camera client", mClientPid);
+        }
+
+    }
+    // the old client destructor is called when oldClient goes out of scope
+    // now we set the new PID to lock the interface again
+    mClientPid = IPCThreadState::self()->getCallingPid();
+
+    return NO_ERROR;
+}
+
+#if HAVE_ANDROID_OS
+static void *unregister_surface(void *arg)
+{
+    ISurface *surface = (ISurface *)arg;
+    surface->unregisterBuffers();
+    IPCThreadState::self()->flushCommands();
+    return NULL;
+}
+#endif
+
+CameraService::Client::~Client()
+{
+    // tear down client
+    LOGD("Client (%p)  E destructor", getCameraClient()->asBinder().get());
+    if (mSurface != 0 && !mUseOverlay) {
+#if HAVE_ANDROID_OS
+        pthread_t thr;
+        // We unregister the buffers in a different thread because binder does
+        // not let us make sychronous transactions in a binder destructor (that
+        // is, upon our reaching a refcount of zero.)
+        pthread_create(&thr, NULL,
+                       unregister_surface,
+                       mSurface.get());
+        pthread_join(thr, NULL);
+#else
+        mSurface->unregisterBuffers();
+#endif
+    }
+
+    // make sure we tear down the hardware
+    mClientPid = IPCThreadState::self()->getCallingPid();
+    disconnect();
+    LOGD("Client X destructor");
+}
+
+void CameraService::Client::disconnect()
+{
+    LOGD("Client (%p) E disconnect from (%d)",
+            getCameraClient()->asBinder().get(),
+            IPCThreadState::self()->getCallingPid());
+    Mutex::Autolock lock(mLock);
+    if (mClientPid <= 0) {
+        LOGV("camera is unlocked, don't tear down hardware");
+        return;
+    }
+    if (checkPid() != NO_ERROR) {
+        LOGV("Different client - don't disconnect");
+        return;
+    }
+
+    mCameraService->removeClient(mCameraClient);
+    if (mHardware != 0) {
+        LOGV("hardware teardown");
+        // Before destroying mHardware, we must make sure it's in the
+        // idle state.
+        mHardware->stopPreview();
+        // Cancel all picture callbacks.
+        mHardware->cancelPicture(true, true, true);
+        // Release the hardware resources.
+        mHardware->release();
+    }
+    mHardware.clear();
+    LOGD("Client X disconnect");
+}
+
+// pass the buffered ISurface to the camera service
+status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface)
+{
+    LOGD("setPreviewDisplay(%p)", surface.get());
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPid();
+    if (result != NO_ERROR) return result;
+    Mutex::Autolock surfaceLock(mSurfaceLock);
+    // asBinder() is safe on NULL (returns NULL)
+    if (surface->asBinder() != mSurface->asBinder()) {
+        if (mSurface != 0 && !mUseOverlay) {
+            LOGD("clearing old preview surface %p", mSurface.get());
+            mSurface->unregisterBuffers();
+        }
+        mSurface = surface;
+    }
+    return NO_ERROR;
+}
+
+// set the preview callback flag to affect how the received frames from
+// preview are handled.
+void CameraService::Client::setPreviewCallbackFlag(int callback_flag)
+{
+    LOGV("setPreviewCallbackFlag");
+    Mutex::Autolock lock(mLock);
+    if (checkPid() != NO_ERROR) return;
+    mPreviewCallbackFlag = callback_flag;
+}
+
+// start preview mode, must call setPreviewDisplay first
+status_t CameraService::Client::startCameraMode(camera_mode mode)
+{
+    LOGD("startCameraMode(%d)", mode);
+
+    /* we cannot call into mHardware with mLock held because
+     * mHardware has callbacks onto us which acquire this lock
+     */
+
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPid();
+    if (result != NO_ERROR) return result;
+
+    if (mHardware == 0) {
+        LOGE("mHardware is NULL, returning.");
+        return INVALID_OPERATION;
+    }
+
+    if (mSurface == 0) {
+        LOGE("setPreviewDisplay must be called before startCameraMode!");
+        return INVALID_OPERATION;
+    }
+
+    switch(mode) {
+    case CAMERA_RECORDING_MODE:
+        return startRecordingMode();
+
+    default: // CAMERA_PREVIEW_MODE
+        return startPreviewMode();
+    }
+}
+
+status_t CameraService::Client::startRecordingMode()
+{
+    LOGV("startRecordingMode");
+
+    status_t ret = UNKNOWN_ERROR;
+
+    // if preview has not been started, start preview first
+    if (!mHardware->previewEnabled()) {
+        ret = startPreviewMode();
+        if (ret != NO_ERROR) {
+            return ret;
+        }
+    }
+
+    // if recording has been enabled, nothing needs to be done
+    if (mHardware->recordingEnabled()) {
+        return NO_ERROR;
+    }
+
+    // start recording mode
+    ret = mHardware->startRecording(recordingCallback,
+                                    mCameraService.get());
+    if (ret != NO_ERROR) {
+        LOGE("mHardware->startRecording() failed with status %d", ret);
+    }
+    return ret;
+}
+
+status_t CameraService::Client::startPreviewMode()
+{
+    LOGV("startPreviewMode");
+
+    // if preview has been enabled, nothing needs to be done
+    if (mHardware->previewEnabled()) {
+        return NO_ERROR;
+    }
+
+    // start preview mode
+#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
+    debug_frame_cnt = 0;
+#endif
+    status_t ret = UNKNOWN_ERROR;
+    int w, h;
+    CameraParameters params(mHardware->getParameters());
+    params.getPreviewSize(&w, &h);
+
+    if (mUseOverlay) {
+        const char *format = params.getPreviewFormat();
+        int fmt;
+        LOGD("Use Overlays");
+        if (!strcmp(format, "yuv422i"))
+            fmt = OVERLAY_FORMAT_YCbCr_422_I;
+        else if (!strcmp(format, "rgb565"))
+            fmt = OVERLAY_FORMAT_RGB_565;
+        else {
+            LOGE("Invalid preview format for overlays");
+            return -EINVAL;
+        }
+        sp<OverlayRef> ref = mSurface->createOverlay(w, h, fmt);
+        ret = mHardware->setOverlay(new Overlay(ref));
+        if (ret != NO_ERROR) {
+            LOGE("mHardware->setOverlay() failed with status %d\n", ret);
+            return ret;
+        }
+        ret = mHardware->startPreview(NULL, mCameraService.get());
+        if (ret != NO_ERROR)
+            LOGE("mHardware->startPreview() failed with status %d\n", ret);
+
+    } else {
+        ret = mHardware->startPreview(previewCallback,
+                                      mCameraService.get());
+        if (ret == NO_ERROR) {
+
+            mSurface->unregisterBuffers();
+
+            uint32_t transform = 0;
+            if (params.getOrientation() ==
+                CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
+              LOGV("portrait mode");
+              transform = ISurface::BufferHeap::ROT_90;
+            }
+            ISurface::BufferHeap buffers(w, h, w, h,
+                                         PIXEL_FORMAT_YCbCr_420_SP,
+                                         transform,
+                                         0,
+                                         mHardware->getPreviewHeap());
+
+            mSurface->registerBuffers(buffers);
+        } else {
+          LOGE("mHardware->startPreview() failed with status %d", ret);
+        }
+    }
+    return ret;
+}
+
+status_t CameraService::Client::startPreview()
+{
+    return startCameraMode(CAMERA_PREVIEW_MODE);
+}
+
+status_t CameraService::Client::startRecording()
+{
+    return startCameraMode(CAMERA_RECORDING_MODE);
+}
+
+// stop preview mode
+void CameraService::Client::stopPreview()
+{
+    LOGD("stopPreview()");
+
+    Mutex::Autolock lock(mLock);
+    if (checkPid() != NO_ERROR) return;
+
+    if (mHardware == 0) {
+        LOGE("mHardware is NULL, returning.");
+        return;
+    }
+
+    mHardware->stopPreview();
+    LOGD("stopPreview(), hardware stopped OK");
+
+    if (mSurface != 0 && !mUseOverlay) {
+        mSurface->unregisterBuffers();
+    }
+    mPreviewBuffer.clear();
+}
+
+// stop recording mode
+void CameraService::Client::stopRecording()
+{
+    LOGV("stopRecording()");
+
+    Mutex::Autolock lock(mLock);
+    if (checkPid() != NO_ERROR) return;
+
+    if (mHardware == 0) {
+        LOGE("mHardware is NULL, returning.");
+        return;
+    }
+
+    mHardware->stopRecording();
+    LOGV("stopRecording(), hardware stopped OK");
+    mPreviewBuffer.clear();
+}
+
+// release a recording frame
+void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem)
+{
+    LOGV("releaseRecordingFrame()");
+
+    Mutex::Autolock lock(mLock);
+    if (checkPid() != NO_ERROR) return;
+
+    if (mHardware == 0) {
+        LOGE("mHardware is NULL, returning.");
+        return;
+    }
+
+    mHardware->releaseRecordingFrame(mem);
+}
+
+bool CameraService::Client::previewEnabled()
+{
+    Mutex::Autolock lock(mLock);
+    if (mHardware == 0) return false;
+    return mHardware->previewEnabled();
+}
+
+bool CameraService::Client::recordingEnabled()
+{
+    Mutex::Autolock lock(mLock);
+    if (mHardware == 0) return false;
+    return mHardware->recordingEnabled();
+}
+
+// Safely retrieves a strong pointer to the client during a hardware callback.
+sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user)
+{
+    sp<Client> client = 0;
+    CameraService *service = static_cast<CameraService*>(user);
+    if (service != NULL) {
+        Mutex::Autolock ourLock(service->mLock);
+        if (service->mClient != 0) {
+            client = service->mClient.promote();
+            if (client == 0) {
+                LOGE("getClientFromCookie: client appears to have died");
+                service->mClient.clear();
+            }
+        } else {
+            LOGE("getClientFromCookie: got callback but client was NULL");
+        }
+    }
+    return client;
+}
+
+
+#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE || \
+    DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE || \
+    DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
+static void dump_to_file(const char *fname,
+                         uint8_t *buf, uint32_t size)
+{
+    int nw, cnt = 0;
+    uint32_t written = 0;
+
+    LOGD("opening file [%s]\n", fname);
+    int fd = open(fname, O_RDWR | O_CREAT);
+    if (fd < 0) {
+        LOGE("failed to create file [%s]: %s", fname, strerror(errno));
+        return;
+    }
+
+    LOGD("writing %d bytes to file [%s]\n", size, fname);
+    while (written < size) {
+        nw = ::write(fd,
+                     buf + written,
+                     size - written);
+        if (nw < 0) {
+            LOGE("failed to write to file [%s]: %s",
+                 fname, strerror(errno));
+            break;
+        }
+        written += nw;
+        cnt++;
+    }
+    LOGD("done writing %d bytes to file [%s] in %d passes\n",
+         size, fname, cnt);
+    ::close(fd);
+}
+#endif
+
+// preview callback - frame buffer update
+void CameraService::Client::previewCallback(const sp<IMemory>& mem, void* user)
+{
+    LOGV("previewCallback()");
+    sp<Client> client = getClientFromCookie(user);
+    if (client == 0) {
+        return;
+    }
+
+#if DEBUG_HEAP_LEAKS && 0 // debugging
+    if (gWeakHeap == NULL) {
+        ssize_t offset;
+        size_t size;
+        sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+        if (gWeakHeap != heap) {
+            LOGD("SETTING PREVIEW HEAP");
+            heap->trackMe(true, true);
+            gWeakHeap = heap;
+        }
+    }
+#endif
+
+#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
+    {
+        if (debug_frame_cnt++ == DEBUG_DUMP_PREVIEW_FRAME_TO_FILE) {
+            ssize_t offset;
+            size_t size;
+            sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+            dump_to_file("/data/preview.yuv",
+                         (uint8_t *)heap->base() + offset, size);
+        }
+    }
+#endif
+
+    // The strong pointer guarantees the client will exist, but no lock is held.
+    client->postPreviewFrame(mem);
+
+#if DEBUG_CLIENT_REFERENCES
+    //**** if the client's refcount is 1, then we are about to destroy it here,
+    // which is bad--print all refcounts.
+    if (client->getStrongCount() == 1) {
+        LOGE("++++++++++++++++ (PREVIEW) THIS WILL CAUSE A LOCKUP!");
+        client->printRefs();
+    }
+#endif
+}
+
+// recording callback
+void CameraService::Client::recordingCallback(const sp<IMemory>& mem, void* user)
+{
+    LOGV("recordingCallback");
+    sp<Client> client = getClientFromCookie(user);
+    if (client == 0) {
+        return;
+    }
+    // The strong pointer guarantees the client will exist, but no lock is held.
+    client->postRecordingFrame(mem);
+}
+
+// take a picture - image is returned in callback
+status_t CameraService::Client::autoFocus()
+{
+    LOGV("autoFocus");
+
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPid();
+    if (result != NO_ERROR) return result;
+
+    if (mHardware == 0) {
+        LOGE("mHardware is NULL, returning.");
+        return INVALID_OPERATION;
+    }
+
+    return mHardware->autoFocus(autoFocusCallback,
+                                mCameraService.get());
+}
+
+// take a picture - image is returned in callback
+status_t CameraService::Client::takePicture()
+{
+    LOGD("takePicture");
+
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPid();
+    if (result != NO_ERROR) return result;
+
+    if (mHardware == 0) {
+        LOGE("mHardware is NULL, returning.");
+        return INVALID_OPERATION;
+    }
+
+    return mHardware->takePicture(shutterCallback,
+                                  yuvPictureCallback,
+                                  jpegPictureCallback,
+                                  mCameraService.get());
+}
+
+// picture callback - snapshot taken
+void CameraService::Client::shutterCallback(void *user)
+{
+    sp<Client> client = getClientFromCookie(user);
+    if (client == 0) {
+        return;
+    }
+
+    // Screen goes black after the buffer is unregistered.
+    if (client->mSurface != 0 && !client->mUseOverlay) {
+        client->mSurface->unregisterBuffers();
+    }
+
+    client->postShutter();
+
+    // It takes some time before yuvPicture callback to be called.
+    // Register the buffer for raw image here to reduce latency.
+    if (client->mSurface != 0 && !client->mUseOverlay) {
+        int w, h;
+        CameraParameters params(client->mHardware->getParameters());
+        params.getPictureSize(&w, &h);
+        uint32_t transform = 0;
+        if (params.getOrientation() == CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
+            LOGV("portrait mode");
+            transform = ISurface::BufferHeap::ROT_90;
+        }
+        ISurface::BufferHeap buffers(w, h, w, h,
+            PIXEL_FORMAT_YCbCr_420_SP, transform, 0, client->mHardware->getRawHeap());
+
+        client->mSurface->registerBuffers(buffers);
+    }
+}
+
+// picture callback - raw image ready
+void CameraService::Client::yuvPictureCallback(const sp<IMemory>& mem,
+                                               void *user)
+{
+    sp<Client> client = getClientFromCookie(user);
+    if (client == 0) {
+        return;
+    }
+    if (mem == NULL) {
+        client->postRaw(NULL);
+        client->postError(UNKNOWN_ERROR);
+        return;
+    }
+
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+#if DEBUG_HEAP_LEAKS && 0 // debugging
+    gWeakHeap = heap; // debugging
+#endif
+
+    //LOGV("yuvPictureCallback(%d, %d, %p)", offset, size, user);
+#if DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE // for testing pursposes only
+    dump_to_file("/data/photo.yuv",
+                 (uint8_t *)heap->base() + offset, size);
+#endif
+
+    // Put the YUV version of the snapshot in the preview display.
+    if (client->mSurface != 0 && !client->mUseOverlay) {
+        client->mSurface->postBuffer(offset);
+    }
+
+    client->postRaw(mem);
+
+#if DEBUG_CLIENT_REFERENCES
+    //**** if the client's refcount is 1, then we are about to destroy it here,
+    // which is bad--print all refcounts.
+    if (client->getStrongCount() == 1) {
+        LOGE("++++++++++++++++ (RAW) THIS WILL CAUSE A LOCKUP!");
+        client->printRefs();
+    }
+#endif
+}
+
+// picture callback - jpeg ready
+void CameraService::Client::jpegPictureCallback(const sp<IMemory>& mem, void *user)
+{
+    sp<Client> client = getClientFromCookie(user);
+    if (client == 0) {
+        return;
+    }
+    if (mem == NULL) {
+        client->postJpeg(NULL);
+        client->postError(UNKNOWN_ERROR);
+        return;
+    }
+
+    /** We absolutely CANNOT call into user code with a lock held **/
+
+#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE // for testing pursposes only
+    {
+        ssize_t offset;
+        size_t size;
+        sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+        dump_to_file("/data/photo.jpg",
+                     (uint8_t *)heap->base() + offset, size);
+    }
+#endif
+
+    client->postJpeg(mem);
+
+#if DEBUG_CLIENT_REFERENCES
+    //**** if the client's refcount is 1, then we are about to destroy it here,
+    // which is bad--print all refcounts.
+    if (client->getStrongCount() == 1) {
+        LOGE("++++++++++++++++ (JPEG) THIS WILL CAUSE A LOCKUP!");
+        client->printRefs();
+    }
+#endif
+}
+
+void CameraService::Client::autoFocusCallback(bool focused, void *user)
+{
+    LOGV("autoFocusCallback");
+
+    sp<Client> client = getClientFromCookie(user);
+    if (client == 0) {
+        return;
+    }
+
+    client->postAutoFocus(focused);
+
+#if DEBUG_CLIENT_REFERENCES
+    if (client->getStrongCount() == 1) {
+        LOGE("++++++++++++++++ (AUTOFOCUS) THIS WILL CAUSE A LOCKUP!");
+        client->printRefs();
+    }
+#endif
+}
+
+// set preview/capture parameters - key/value pairs
+status_t CameraService::Client::setParameters(const String8& params)
+{
+    LOGD("setParameters(%s)", params.string());
+
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPid();
+    if (result != NO_ERROR) return result;
+
+    if (mHardware == 0) {
+        LOGE("mHardware is NULL, returning.");
+        return INVALID_OPERATION;
+    }
+
+    CameraParameters p(params);
+    mHardware->setParameters(p);
+    return NO_ERROR;
+}
+
+// get preview/capture parameters - key/value pairs
+String8 CameraService::Client::getParameters() const
+{
+    LOGD("getParameters");
+
+    Mutex::Autolock lock(mLock);
+
+    if (mHardware == 0) {
+        LOGE("mHardware is NULL, returning.");
+        return String8();
+    }
+
+    return mHardware->getParameters().flatten();
+}
+
+void CameraService::Client::postAutoFocus(bool focused)
+{
+    LOGV("postAutoFocus");
+    mCameraClient->autoFocusCallback(focused);
+}
+
+void CameraService::Client::postShutter()
+{
+    mCameraClient->shutterCallback();
+}
+
+void CameraService::Client::postRaw(const sp<IMemory>& mem)
+{
+    LOGD("postRaw");
+    mCameraClient->rawCallback(mem);
+}
+
+void CameraService::Client::postJpeg(const sp<IMemory>& mem)
+{
+    LOGD("postJpeg");
+    mCameraClient->jpegCallback(mem);
+}
+
+void CameraService::Client::copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size)
+{
+    LOGV("copyFrameAndPostCopiedFrame");
+    // It is necessary to copy out of pmem before sending this to
+    // the callback. For efficiency, reuse the same MemoryHeapBase
+    // provided it's big enough. Don't allocate the memory or
+    // perform the copy if there's no callback.
+    if (mPreviewBuffer == 0) {
+        mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
+    } else if (size > mPreviewBuffer->virtualSize()) {
+        mPreviewBuffer.clear();
+        mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
+        if (mPreviewBuffer == 0) {
+            LOGE("failed to allocate space for preview buffer");
+            return;
+        }
+    }
+    memcpy(mPreviewBuffer->base(),
+           (uint8_t *)heap->base() + offset, size);
+
+    sp<MemoryBase> frame = new MemoryBase(mPreviewBuffer, 0, size);
+    if (frame == 0) {
+        LOGE("failed to allocate space for frame callback");
+        return;
+    }
+    mCameraClient->previewCallback(frame);
+}
+
+void CameraService::Client::postRecordingFrame(const sp<IMemory>& frame)
+{
+    LOGV("postRecordingFrame");
+    if (frame == 0) {
+        LOGW("frame is a null pointer");
+        return;
+    }
+    mCameraClient->recordingCallback(frame);
+}
+
+void CameraService::Client::postPreviewFrame(const sp<IMemory>& mem)
+{
+    LOGV("postPreviewFrame");
+    if (mem == 0) {
+        LOGW("mem is a null pointer");
+        return;
+    }
+
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+    {
+        Mutex::Autolock surfaceLock(mSurfaceLock);
+        if (mSurface != NULL) {
+            mSurface->postBuffer(offset);
+        }
+    }
+
+    // Is the callback enabled or not?
+    if (!(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
+        // If the enable bit is off, the copy-out and one-shot bits are ignored
+        LOGV("frame callback is diabled");
+        return;
+    }
+
+    // Is the received frame copied out or not?
+    if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
+        LOGV("frame is copied out");
+        copyFrameAndPostCopiedFrame(heap, offset, size);
+    } else {
+        LOGV("frame is directly sent out without copying");
+        mCameraClient->previewCallback(mem);
+    }
+
+    // Is this is one-shot only?
+    if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
+        LOGV("One-shot only, thus clear the bits and disable frame callback");
+        mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
+                                FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
+                                FRAME_CALLBACK_FLAG_ENABLE_MASK);
+    }
+}
+
+void CameraService::Client::postError(status_t error)
+{
+    mCameraClient->errorCallback(error);
+}
+
+status_t CameraService::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        snprintf(buffer, SIZE, "Permission Denial: "
+                "can't dump CameraService from pid=%d, uid=%d\n",
+                IPCThreadState::self()->getCallingPid(),
+                IPCThreadState::self()->getCallingUid());
+        result.append(buffer);
+        write(fd, result.string(), result.size());
+    } else {
+        AutoMutex lock(&mLock);
+        if (mClient != 0) {
+            sp<Client> currentClient = mClient.promote();
+            sprintf(buffer, "Client (%p) PID: %d\n",
+                    currentClient->getCameraClient()->asBinder().get(),
+                    currentClient->mClientPid);
+            result.append(buffer);
+            write(fd, result.string(), result.size());
+            currentClient->mHardware->dump(fd, args);
+        } else {
+            result.append("No camera client yet.\n");
+            write(fd, result.string(), result.size());
+        }
+    }
+    return NO_ERROR;
+}
+
+
+#if DEBUG_HEAP_LEAKS
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t CameraService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    // permission checks...
+    switch (code) {
+        case BnCameraService::CONNECT:
+            IPCThreadState* ipc = IPCThreadState::self();
+            const int pid = ipc->getCallingPid();
+            const int self_pid = getpid();
+            if (pid != self_pid) {
+                // we're called from a different process, do the real check
+                if (!checkCallingPermission(
+                        String16("android.permission.CAMERA")))
+                {
+                    const int uid = ipc->getCallingUid();
+                    LOGE("Permission Denial: "
+                            "can't use the camera pid=%d, uid=%d", pid, uid);
+                    return PERMISSION_DENIED;
+                }
+            }
+            break;
+    }
+
+    status_t err = BnCameraService::onTransact(code, data, reply, flags);
+
+    LOGD("+++ onTransact err %d code %d", err, code);
+
+    if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
+        // the 'service' command interrogates this binder for its name, and then supplies it
+        // even for the debugging commands.  that means we need to check for it here, using
+        // ISurfaceComposer (since we delegated the INTERFACE_TRANSACTION handling to
+        // BnSurfaceComposer before falling through to this code).
+
+        LOGD("+++ onTransact code %d", code);
+
+        CHECK_INTERFACE(ICameraService, data, reply);
+
+        switch(code) {
+        case 1000:
+        {
+            if (gWeakHeap != 0) {
+                sp<IMemoryHeap> h = gWeakHeap.promote();
+                IMemoryHeap *p = gWeakHeap.unsafe_get();
+                LOGD("CHECKING WEAK REFERENCE %p (%p)", h.get(), p);
+                if (h != 0)
+                    h->printRefs();
+                bool attempt_to_delete = data.readInt32() == 1;
+                if (attempt_to_delete) {
+                    // NOT SAFE!
+                    LOGD("DELETING WEAK REFERENCE %p (%p)", h.get(), p);
+                    if (p) delete p;
+                }
+                return NO_ERROR;
+            }
+        }
+        break;
+        default:
+            break;
+        }
+    }
+    return err;
+}
+
+#endif // DEBUG_HEAP_LEAKS
+
+}; // namespace android
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
new file mode 100644
index 0000000..d9b7927
--- /dev/null
+++ b/camera/libcameraservice/CameraService.h
@@ -0,0 +1,206 @@
+/*
+**
+** Copyright (C) 2008, The Android Open Source Project
+** Copyright (C) 2008 HTC Inc.
+**
+** 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.
+*/
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
+#define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
+
+#include <ui/ICameraService.h>
+#include <ui/CameraHardwareInterface.h>
+#include <ui/Camera.h>
+
+class android::MemoryHeapBase;
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+// When enabled, this feature allows you to send an event to the CameraService
+// so that you can cause all references to the heap object gWeakHeap, defined
+// below, to be printed. You will also need to set DEBUG_REFS=1 and
+// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp. You just have to
+// set gWeakHeap to the appropriate heap you want to track.
+
+#define DEBUG_HEAP_LEAKS 0
+
+// ----------------------------------------------------------------------------
+
+class CameraService : public BnCameraService
+{
+    class Client;
+
+public:
+    static void instantiate();
+
+    // ICameraService interface
+    virtual sp<ICamera>     connect(const sp<ICameraClient>& cameraClient);
+
+    virtual status_t        dump(int fd, const Vector<String16>& args);
+
+            void            removeClient(const sp<ICameraClient>& cameraClient);
+
+#if DEBUG_HEAP_LEAKS
+    virtual status_t onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+#endif
+
+private:
+
+// ----------------------------------------------------------------------------
+
+    class Client : public BnCamera {
+
+    public:
+        virtual void            disconnect();
+
+        // connect new client with existing camera remote
+        virtual status_t        connect(const sp<ICameraClient>& client);
+
+        // prevent other processes from using this ICamera interface
+        virtual status_t        lock();
+
+        // allow other processes to use this ICamera interface
+        virtual status_t        unlock();
+
+        // pass the buffered ISurface to the camera service
+        virtual status_t        setPreviewDisplay(const sp<ISurface>& surface);
+
+        // set the preview callback flag to affect how the received frames from
+        // preview are handled.
+        virtual void            setPreviewCallbackFlag(int callback_flag);
+
+        // start preview mode, must call setPreviewDisplay first
+        virtual status_t        startPreview();
+
+        // stop preview mode
+        virtual void            stopPreview();
+
+        // get preview state
+        virtual bool            previewEnabled();
+
+        // start recording mode
+        virtual status_t        startRecording();
+
+        // stop recording mode
+        virtual void            stopRecording();
+
+        // get recording state
+        virtual bool            recordingEnabled();
+
+        // release a recording frame
+        virtual void            releaseRecordingFrame(const sp<IMemory>& mem);
+
+        // auto focus
+        virtual status_t        autoFocus();
+
+        // take a picture - returns an IMemory (ref-counted mmap)
+        virtual status_t        takePicture();
+
+        // set preview/capture parameters - key/value pairs
+        virtual status_t        setParameters(const String8& params);
+
+        // get preview/capture parameters - key/value pairs
+        virtual String8         getParameters() const;
+
+        // our client...
+        const sp<ICameraClient>&    getCameraClient() const { return mCameraClient; }
+
+    private:
+        friend class CameraService;
+                                Client(const sp<CameraService>& cameraService,
+                                        const sp<ICameraClient>& cameraClient,
+                                        pid_t clientPid);
+                                Client();
+        virtual                 ~Client();
+
+                    status_t    checkPid();
+
+        static      void        recordingCallback(const sp<IMemory>& mem, void* user);
+        static      void        previewCallback(const sp<IMemory>& mem, void* user);
+        static      void        shutterCallback(void *user);
+        static      void        yuvPictureCallback(const sp<IMemory>& mem, void* user);
+        static      void        jpegPictureCallback(const sp<IMemory>& mem, void* user);
+        static      void        autoFocusCallback(bool focused, void* user);
+        static      sp<Client>  getClientFromCookie(void* user);
+
+                    void        postShutter();
+                    void        postRaw(const sp<IMemory>& mem);
+                    void        postJpeg(const sp<IMemory>& mem);
+                    void        postPreviewFrame(const sp<IMemory>& mem);
+                    void        postRecordingFrame(const sp<IMemory>& frame);
+                    void        copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size);
+                    void        postError(status_t error);
+                    void        postAutoFocus(bool focused);
+
+        // camera operation mode
+        enum camera_mode {
+            CAMERA_PREVIEW_MODE   = 0,  // frame automatically released
+            CAMERA_RECORDING_MODE = 1,  // frame has to be explicitly released by releaseRecordingFrame()
+        };
+        status_t                startCameraMode(camera_mode mode);
+        status_t                startPreviewMode();
+        status_t                startRecordingMode();
+
+        // Ensures atomicity among the public methods
+        mutable     Mutex                       mLock;
+
+        // mSurfaceLock synchronizes access to mSurface between
+        // setPreviewSurface() and postPreviewFrame().  Note that among
+        // the public methods, all accesses to mSurface are
+        // syncrhonized by mLock.  However, postPreviewFrame() is called
+        // by the CameraHardwareInterface callback, and needs to
+        // access mSurface.  It cannot hold mLock, however, because
+        // stopPreview() may be holding that lock while attempting
+        // to stop preview, and stopPreview itself will block waiting
+        // for a callback from CameraHardwareInterface.  If this
+        // happens, it will cause a deadlock.
+        mutable     Mutex                       mSurfaceLock;
+        mutable     Condition                   mReady;
+                    sp<CameraService>           mCameraService;
+                    sp<ISurface>                mSurface;
+                    sp<MemoryHeapBase>          mPreviewBuffer;
+                    int                         mPreviewCallbackFlag;
+
+                    // these are immutable once the object is created,
+                    // they don't need to be protected by a lock
+                    sp<ICameraClient>           mCameraClient;
+                    sp<CameraHardwareInterface> mHardware;
+                    pid_t                       mClientPid;
+                    bool                        mUseOverlay;
+    };
+
+// ----------------------------------------------------------------------------
+
+                            CameraService();
+    virtual                 ~CameraService();
+
+    mutable     Mutex                       mLock;
+                wp<Client>                  mClient;
+
+#if DEBUG_HEAP_LEAKS
+                wp<IMemoryHeap>             gWeakHeap;
+#endif
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif
diff --git a/camera/libcameraservice/CannedJpeg.h b/camera/libcameraservice/CannedJpeg.h
new file mode 100644
index 0000000..532560a
--- /dev/null
+++ b/camera/libcameraservice/CannedJpeg.h
@@ -0,0 +1,1546 @@
+const int kCannedJpegWidth = 213;
+const int kCannedJpegHeight = 350;
+const int kCannedJpegSize = 18474;
+
+const char kCannedJpeg[] = {
+  0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
+  0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43,
+  0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04, 0x04, 0x05,
+  0x05, 0x05, 0x06, 0x07, 0x0c, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b,
+  0x0b, 0x09, 0x0c, 0x11, 0x0f, 0x12, 0x12, 0x11, 0x0f, 0x11, 0x11, 0x13,
+  0x16, 0x1c, 0x17, 0x13, 0x14, 0x1a, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18,
+  0x1a, 0x1d, 0x1d, 0x1f, 0x1f, 0x1f, 0x13, 0x17, 0x22, 0x24, 0x22, 0x1e,
+  0x24, 0x1c, 0x1e, 0x1f, 0x1e, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x05, 0x05,
+  0x05, 0x07, 0x06, 0x07, 0x0e, 0x08, 0x08, 0x0e, 0x1e, 0x14, 0x11, 0x14,
+  0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+  0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+  0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+  0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+  0x1e, 0x1e, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x01, 0x5e, 0x00, 0xd5, 0x03,
+  0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00,
+  0x1c, 0x00, 0x00, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x05, 0x07, 0x01, 0x03,
+  0x04, 0x02, 0x08, 0xff, 0xc4, 0x00, 0x55, 0x10, 0x00, 0x01, 0x03, 0x04,
+  0x00, 0x03, 0x03, 0x05, 0x0a, 0x09, 0x08, 0x09, 0x02, 0x06, 0x03, 0x00,
+  0x01, 0x02, 0x03, 0x04, 0x00, 0x05, 0x06, 0x11, 0x07, 0x12, 0x21, 0x13,
+  0x31, 0x41, 0x14, 0x22, 0x51, 0x61, 0x71, 0x15, 0x23, 0x32, 0x34, 0x37,
+  0x72, 0x75, 0x81, 0xb1, 0xb3, 0x08, 0x17, 0x33, 0x42, 0x52, 0x62, 0x76,
+  0x93, 0xb2, 0x16, 0x24, 0x43, 0x53, 0x56, 0x91, 0xa1, 0xd2, 0x25, 0x36,
+  0x63, 0x73, 0x82, 0x92, 0xa2, 0xc1, 0xd1, 0x65, 0xf0, 0x26, 0x27, 0x64,
+  0x66, 0x74, 0xe1, 0x83, 0xc2, 0xf1, 0xff, 0xc4, 0x00, 0x1b, 0x01, 0x01,
+  0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff,
+  0xc4, 0x00, 0x35, 0x11, 0x00, 0x02, 0x01, 0x03, 0x03, 0x01, 0x05, 0x05,
+  0x07, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
+  0x04, 0x11, 0x12, 0x21, 0x31, 0x41, 0x05, 0x22, 0x32, 0x51, 0x61, 0x06,
+  0x13, 0x71, 0x81, 0xb1, 0x14, 0x33, 0x42, 0x91, 0xa1, 0xc1, 0xd1, 0x15,
+  0x23, 0xe1, 0xf0, 0x24, 0x53, 0x92, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01,
+  0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xfb, 0x2e, 0x8a, 0x2b,
+  0xca, 0x95, 0xae, 0xfe, 0xea, 0x03, 0xd5, 0x15, 0x8d, 0xfb, 0x28, 0xdf,
+  0xb2, 0x80, 0xcd, 0x15, 0x8d, 0xfb, 0x28, 0xdf, 0xb2, 0x80, 0xcd, 0x15,
+  0x8d, 0xfb, 0x28, 0xe6, 0xa0, 0x33, 0x45, 0x63, 0x9a, 0xb3, 0x40, 0x14,
+  0x51, 0x45, 0x00, 0x51, 0x45, 0x14, 0x01, 0x45, 0x14, 0x50, 0x05, 0x14,
+  0x56, 0x37, 0x40, 0x66, 0x8a, 0x37, 0xd6, 0xb1, 0xbf, 0x65, 0x01, 0x9a,
+  0x2b, 0x1b, 0xf6, 0x51, 0xbf, 0x65, 0x01, 0x9a, 0x2b, 0x1b, 0xf6, 0x51,
+  0xbf, 0x65, 0x01, 0x9a, 0x2b, 0xc9, 0x56, 0xbb, 0xeb, 0xd0, 0xa0, 0x0a,
+  0x2b, 0xca, 0x95, 0xa3, 0x45, 0x01, 0xea, 0x93, 0x78, 0xe1, 0xb1, 0xc1,
+  0xec, 0xb8, 0x82, 0x41, 0xf7, 0x1e, 0x4f, 0x71, 0xd7, 0xf4, 0x66, 0x9c,
+  0xa9, 0x37, 0x8e, 0x5f, 0x23, 0xb9, 0x77, 0xd0, 0xf2, 0x7e, 0xec, 0xd0,
+  0x15, 0xb3, 0x5c, 0x3c, 0xc1, 0xd4, 0xd2, 0x14, 0x71, 0x7b, 0x69, 0x25,
+  0x20, 0x9f, 0x7a, 0xaf, 0x5f, 0x8b, 0xbc, 0x1b, 0xfb, 0x2d, 0x6c, 0xfd,
+  0xd5, 0x33, 0x31, 0xf9, 0x16, 0xfe, 0x68, 0xfb, 0x2b, 0xdd, 0x7b, 0x9a,
+  0x23, 0xe4, 0x78, 0x9a, 0xe5, 0xe6, 0x2b, 0x7e, 0x2e, 0xf0, 0x6f, 0xec,
+  0xb5, 0xb3, 0xf7, 0x54, 0x1e, 0x1e, 0x60, 0xc3, 0xaf, 0xf2, 0x5a, 0xd9,
+  0xaf, 0xf7, 0x54, 0xc7, 0x36, 0x54, 0x68, 0x50, 0xde, 0x99, 0x32, 0x43,
+  0x51, 0xa3, 0x30, 0x92, 0xb7, 0x5e, 0x75, 0x41, 0x28, 0x42, 0x40, 0xea,
+  0x54, 0x4f, 0x40, 0x2a, 0x2e, 0xcf, 0x13, 0x28, 0xcd, 0xf9, 0x5c, 0xb3,
+  0x07, 0xb1, 0xcc, 0x7d, 0x63, 0x7e, 0xeb, 0x49, 0x67, 0xf9, 0xd4, 0x94,
+  0xfa, 0x63, 0x34, 0xaf, 0x80, 0x93, 0xe0, 0xe3, 0x83, 0xae, 0xf6, 0x10,
+  0x7a, 0x1a, 0xce, 0xa4, 0xa9, 0x53, 0x59, 0x92, 0x46, 0x94, 0xe3, 0x52,
+  0xa3, 0xc4, 0x5b, 0x17, 0x2f, 0x98, 0xdf, 0x0b, 0xec, 0xaa, 0x65, 0xa9,
+  0xf6, 0x1b, 0x60, 0x92, 0xff, 0x00, 0x48, 0xf1, 0x19, 0x8c, 0xa7, 0xa4,
+  0x3e, 0x7d, 0x08, 0x69, 0x00, 0xad, 0x5f, 0x50, 0xd7, 0xa7, 0x55, 0x98,
+  0x1c, 0x28, 0x93, 0x91, 0x84, 0x2a, 0x0e, 0x09, 0x62, 0xc5, 0x20, 0xa8,
+  0xef, 0xca, 0x6e, 0xcc, 0x87, 0xe5, 0x91, 0xae, 0xf4, 0xc7, 0x42, 0xb9,
+  0x50, 0x7e, 0x7a, 0xf6, 0x3f, 0x46, 0xae, 0x9c, 0x33, 0x0a, 0xc7, 0x71,
+  0x46, 0xd6, 0xbb, 0x4c, 0x1f, 0xe7, 0x6f, 0x0f, 0xe7, 0x33, 0xa4, 0x2c,
+  0xbb, 0x2a, 0x41, 0xf4, 0xad, 0xd5, 0x79, 0xc7, 0xbb, 0xbb, 0xa2, 0x47,
+  0x80, 0x14, 0xc5, 0xaa, 0xf3, 0xea, 0x5c, 0x6a, 0xf0, 0xa4, 0x8e, 0xfa,
+  0x74, 0x34, 0xee, 0xdb, 0x65, 0x47, 0x8e, 0x7e, 0x0f, 0x1c, 0x37, 0xb6,
+  0xbe, 0x26, 0x5c, 0x6d, 0xef, 0xdf, 0x26, 0xeb, 0xf2, 0x93, 0x1c, 0xe5,
+  0x6d, 0x3e, 0x90, 0x96, 0x5b, 0xe5, 0x6c, 0x0f, 0x68, 0x27, 0xd7, 0x4c,
+  0xbf, 0x8a, 0x2e, 0x19, 0xff, 0x00, 0x62, 0xac, 0xff, 0x00, 0xb8, 0xa7,
+  0x8a, 0x2b, 0x9c, 0xe8, 0x12, 0x3f, 0x14, 0x7c, 0x33, 0xfe, 0xc5, 0x59,
+  0xff, 0x00, 0x71, 0x47, 0xe2, 0x8f, 0x86, 0x7f, 0xd8, 0xab, 0x3f, 0xee,
+  0x29, 0xde, 0x8a, 0x01, 0x09, 0xce, 0x16, 0x70, 0xad, 0xb7, 0xd0, 0xc3,
+  0x98, 0x8d, 0x89, 0x0e, 0xb9, 0xf0, 0x10, 0xa6, 0xc0, 0x52, 0xbd, 0x83,
+  0x7d, 0x6b, 0x77, 0xe2, 0x8f, 0x86, 0x7f, 0xd8, 0xab, 0x3f, 0xee, 0x2b,
+  0xb6, 0xef, 0xef, 0x9c, 0x40, 0xb5, 0x23, 0xaf, 0x98, 0xca, 0xd5, 0xf6,
+  0xd3, 0x55, 0x72, 0xdb, 0xd7, 0x75, 0x65, 0x51, 0x63, 0xc2, 0xf1, 0xfa,
+  0x27, 0xfb, 0x90, 0x9e, 0x44, 0x8f, 0xc5, 0x1f, 0x0c, 0xff, 0x00, 0xb1,
+  0x56, 0x7f, 0xdc, 0x51, 0xf8, 0xa3, 0xe1, 0x9f, 0xf6, 0x2a, 0xcf, 0xfb,
+  0x8a, 0x77, 0xa2, 0xba, 0x89, 0x12, 0x3f, 0x14, 0x7c, 0x33, 0xfe, 0xc5,
+  0x59, 0xff, 0x00, 0x71, 0x58, 0x57, 0x08, 0xb8, 0x66, 0xa4, 0x94, 0x9c,
+  0x2a, 0xd1, 0xa2, 0x34, 0x74, 0xce, 0xa9, 0xe2, 0x8a, 0x02, 0x91, 0xbe,
+  0x7e, 0x0e, 0x38, 0x70, 0x75, 0xd9, 0x58, 0xa9, 0x16, 0xa7, 0xd4, 0x76,
+  0x23, 0x4c, 0x6b, 0xcb, 0xa1, 0xa8, 0xfa, 0x0a, 0x1c, 0x3c, 0xe9, 0xdf,
+  0xea, 0xad, 0x3e, 0xca, 0x58, 0xb8, 0x61, 0x36, 0xcc, 0x68, 0x7f, 0xf1,
+  0x8f, 0x0c, 0xe0, 0x37, 0x19, 0x3f, 0x0a, 0xeb, 0x68, 0x69, 0x52, 0xa2,
+  0x01, 0xae, 0xf5, 0xa3, 0x5d, 0xab, 0x43, 0xd6, 0x52, 0xa4, 0x8f, 0xd2,
+  0xf1, 0xaf, 0xa5, 0x48, 0x1b, 0xdd, 0x63, 0x42, 0xb4, 0x85, 0x47, 0x0e,
+  0x0c, 0xe7, 0x4d, 0x4f, 0x93, 0xe7, 0xfb, 0x76, 0x11, 0xc3, 0xab, 0x94,
+  0x26, 0xe6, 0xdb, 0xac, 0x36, 0x59, 0x91, 0x9d, 0x1b, 0x6d, 0xe6, 0x12,
+  0x16, 0x85, 0x8f, 0x51, 0x49, 0x23, 0xff, 0x00, 0x7a, 0xae, 0x81, 0xc3,
+  0xbc, 0x1b, 0x5f, 0xea, 0xb5, 0xb3, 0xf7, 0x54, 0xf1, 0x95, 0x70, 0xce,
+  0xdf, 0x2a, 0x73, 0xf7, 0x8c, 0x56, 0x51, 0xc6, 0xef, 0x4e, 0x9e, 0x67,
+  0x1c, 0x61, 0xb0, 0xa8, 0xb2, 0x95, 0xff, 0x00, 0xd4, 0x31, 0xd1, 0x2b,
+  0xdf, 0xe9, 0x0e, 0x55, 0x8f, 0xd2, 0xf0, 0xa5, 0x58, 0xb7, 0x89, 0xd0,
+  0xef, 0x28, 0xc7, 0xb2, 0xab, 0x7a, 0x2d, 0x17, 0x85, 0x82, 0x63, 0x94,
+  0xb8, 0x57, 0x16, 0x78, 0x1d, 0xea, 0x8e, 0xe1, 0x1d, 0x74, 0x3a, 0x94,
+  0x11, 0xcc, 0x91, 0xe9, 0x1e, 0x75, 0x77, 0xd2, 0xad, 0x4e, 0xa6, 0xcd,
+  0x24, 0xce, 0x0a, 0xb4, 0x6a, 0x53, 0xdd, 0x36, 0xd1, 0xc3, 0xf8, 0xbb,
+  0xc1, 0xbf, 0xb2, 0xd6, 0xcf, 0xdd, 0x51, 0xf8, 0xbb, 0xc1, 0xbf, 0xb2,
+  0xd6, 0xcf, 0xdd, 0x53, 0x48, 0xee, 0xa2, 0xba, 0x74, 0x47, 0xc8, 0xe7,
+  0xd7, 0x2f, 0x31, 0x0e, 0xf1, 0x88, 0xe3, 0x36, 0x4b, 0xc6, 0x2d, 0x3a,
+  0xd1, 0x65, 0x87, 0x06, 0x50, 0xc9, 0x2d, 0xe8, 0xed, 0x59, 0x47, 0x2a,
+  0xb9, 0x4b, 0xa0, 0x11, 0xbf, 0x41, 0x15, 0xf4, 0x60, 0xee, 0xaa, 0x3f,
+  0x33, 0xf8, 0xd6, 0x2d, 0xfb, 0x4f, 0x6e, 0xfb, 0xe1, 0x57, 0x80, 0xee,
+  0xaf, 0x36, 0xed, 0x25, 0x53, 0x63, 0xd2, 0xb5, 0x6d, 0xc3, 0x73, 0x04,
+  0x6c, 0xf7, 0xd1, 0x59, 0xa2, 0xb9, 0x4e, 0x90, 0xa4, 0xde, 0x39, 0x7c,
+  0x8e, 0xe5, 0xdf, 0x43, 0xc9, 0xfb, 0xb3, 0x4e, 0x54, 0x9b, 0xc7, 0x2f,
+  0x91, 0xdc, 0xbb, 0xe8, 0x79, 0x3f, 0x76, 0x68, 0x05, 0xe6, 0x3f, 0x22,
+  0xdf, 0xcd, 0x1f, 0x65, 0x68, 0xbb, 0xdc, 0x61, 0x5a, 0x2d, 0x92, 0x2e,
+  0x57, 0x29, 0x08, 0x8f, 0x12, 0x3a, 0x39, 0xdd, 0x71, 0x5b, 0xd0, 0x1e,
+  0xaf, 0x49, 0x27, 0x40, 0x01, 0xd4, 0x92, 0x05, 0x74, 0x31, 0xf9, 0x26,
+  0xc7, 0xa5, 0x20, 0x0e, 0x9e, 0xaa, 0xe0, 0xe1, 0xed, 0xa1, 0x19, 0xbe,
+  0x42, 0x8c, 0xba, 0x7a, 0x79, 0xf1, 0xfb, 0x5c, 0x85, 0x26, 0xc6, 0xc2,
+  0xbe, 0x0c, 0x99, 0x08, 0x3c, 0xab, 0x98, 0xa1, 0xe2, 0x12, 0xa0, 0x52,
+  0xd8, 0x3d, 0x3a, 0x15, 0xf7, 0x94, 0x91, 0xec, 0xd6, 0xaa, 0xa9, 0x47,
+  0x27, 0x8f, 0x46, 0x93, 0xa9, 0x2c, 0x1d, 0x18, 0x8e, 0x17, 0x33, 0x29,
+  0x97, 0x1f, 0x22, 0xcd, 0xa1, 0xae, 0x3c, 0x26, 0x5c, 0x4b, 0xd6, 0xcb,
+  0x0b, 0xa3, 0xa3, 0x64, 0x1d, 0xa5, 0xf9, 0x43, 0xb9, 0x4e, 0xf8, 0x86,
+  0xfa, 0xa5, 0xbf, 0x5a, 0xb6, 0x45, 0xb0, 0x07, 0x4a, 0x00, 0x1a, 0xe9,
+  0xfe, 0x15, 0x9a, 0xf2, 0x25, 0x27, 0x37, 0x96, 0x7a, 0xd1, 0x82, 0x8a,
+  0xc2, 0x0a, 0x2b, 0x92, 0xee, 0xfc, 0xa8, 0xd0, 0x1c, 0x7a, 0x1c, 0x6f,
+  0x29, 0x79, 0x23, 0xcd, 0x6f, 0x7a, 0xdd, 0x71, 0xe3, 0xf7, 0xf8, 0x77,
+  0x64, 0x72, 0x02, 0x59, 0x92, 0x9e, 0x8e, 0x32, 0xbe, 0x8a, 0x07, 0xfe,
+  0xf5, 0xcd, 0x2b, 0x9a, 0x71, 0xaa, 0xa9, 0x49, 0xe1, 0xbe, 0x3d, 0x49,
+  0xcf, 0x42, 0x5e, 0x8a, 0xd7, 0x25, 0xf6, 0x63, 0x30, 0xa7, 0x9f, 0x71,
+  0x2d, 0xb6, 0x91, 0xb2, 0xa5, 0x1d, 0x0a, 0xae, 0xb2, 0x8c, 0xe9, 0xf7,
+  0xd4, 0xb8, 0xd6, 0x8f, 0x7a, 0x6b, 0xb8, 0xbc, 0x7e, 0x12, 0xbd, 0x9e,
+  0x8a, 0xe6, 0xbf, 0xed, 0x3a, 0x16, 0x30, 0xd5, 0x55, 0xef, 0xd1, 0x75,
+  0x64, 0x4a, 0x49, 0x72, 0x3e, 0x5c, 0xae, 0xd6, 0xdb, 0x72, 0x79, 0xa6,
+  0xcc, 0x69, 0x9f, 0x51, 0x3d, 0x7f, 0xb8, 0x75, 0xa5, 0xc9, 0x9c, 0x40,
+  0xb4, 0xb4, 0x48, 0x61, 0x97, 0xdf, 0xf5, 0xeb, 0x42, 0xab, 0x17, 0x9d,
+  0x75, 0xe7, 0x0b, 0x8f, 0x38, 0xa7, 0x16, 0x7b, 0xd4, 0xa3, 0xb3, 0x5e,
+  0x2b, 0xe3, 0xae, 0x7d, 0xab, 0xb9, 0x9b, 0xfe, 0xd4, 0x54, 0x57, 0xe6,
+  0xff, 0x00, 0xdf, 0x91, 0x93, 0xaa, 0xfa, 0x0d, 0xef, 0x66, 0x0c, 0xb9,
+  0x93, 0xb5, 0x77, 0x30, 0x97, 0xc8, 0xdb, 0x25, 0xb0, 0x8e, 0x71, 0xbe,
+  0xbe, 0x34, 0xc7, 0x0f, 0x88, 0x16, 0x87, 0x54, 0x03, 0xed, 0x3e, 0xc6,
+  0xfc, 0x48, 0xd8, 0xff, 0x00, 0x0a, 0xab, 0x40, 0x24, 0x80, 0x01, 0x24,
+  0xf7, 0x01, 0x5d, 0x73, 0x6d, 0x97, 0x08, 0x4d, 0x21, 0xd9, 0x51, 0x1d,
+  0x65, 0x0b, 0xf8, 0x2a, 0x52, 0x7a, 0x1a, 0xe3, 0xb6, 0xed, 0xcb, 0xfa,
+  0x5a, 0xa7, 0x1d, 0xd3, 0x79, 0x7b, 0x10, 0xa7, 0x22, 0xea, 0xb7, 0x5d,
+  0x20, 0x5c, 0x51, 0xcf, 0x0e, 0x53, 0x6e, 0x8f, 0x40, 0x3d, 0x47, 0xd5,
+  0x5d, 0x95, 0x41, 0x46, 0x90, 0xfc, 0x67, 0x43, 0xb1, 0xdd, 0x5b, 0x4b,
+  0x1d, 0xca, 0x49, 0xd1, 0xab, 0x07, 0x10, 0xcd, 0xbb, 0x65, 0xa2, 0x15,
+  0xdd, 0x41, 0x2b, 0x3d, 0x10, 0xf7, 0x70, 0x3e, 0xda, 0xfa, 0x5e, 0xcd,
+  0xf6, 0x9a, 0x95, 0xc4, 0x95, 0x3a, 0xeb, 0x4b, 0x7d, 0x7a, 0x7f, 0x83,
+  0x48, 0xd4, 0x4f, 0x91, 0xf2, 0x8a, 0x01, 0x04, 0x6c, 0x1d, 0x83, 0x45,
+  0x7d, 0x41, 0xa0, 0x51, 0x45, 0x14, 0x06, 0x0a, 0x41, 0x3b, 0xa8, 0x7c,
+  0xbf, 0x1b, 0xb3, 0xe5, 0x56, 0x47, 0xac, 0xf7, 0xa8, 0xbe, 0x51, 0x19,
+  0xc5, 0x05, 0xa4, 0xa4, 0xf2, 0xad, 0xa7, 0x13, 0xd5, 0x2e, 0x21, 0x43,
+  0xaa, 0x16, 0x93, 0xd4, 0x28, 0x75, 0x15, 0x33, 0x46, 0xa8, 0x0a, 0x45,
+  0x2e, 0x5d, 0x71, 0x5b, 0xf3, 0x58, 0xae, 0x51, 0x24, 0x4a, 0x32, 0x36,
+  0x2c, 0xf7, 0x52, 0x9e, 0x41, 0x38, 0x24, 0x6c, 0xb4, 0xe0, 0xee, 0x4b,
+  0xe9, 0x03, 0x67, 0x5d, 0x16, 0x3c, 0xe1, 0xae, 0xa2, 0xa7, 0xa9, 0xdb,
+  0x33, 0xc6, 0xed, 0x99, 0x56, 0x3f, 0x2a, 0xcb, 0x74, 0x6d, 0x65, 0x87,
+  0x80, 0x28, 0x71, 0xb5, 0x72, 0xba, 0xcb, 0x89, 0xea, 0x87, 0x1b, 0x50,
+  0xea, 0x95, 0xa4, 0x80, 0xa0, 0x7d, 0x35, 0x57, 0xe3, 0x13, 0x2e, 0x3d,
+  0xa4, 0xeb, 0x05, 0xfb, 0x93, 0xdd, 0xcb, 0x3b, 0x81, 0x89, 0x6a, 0x42,
+  0x42, 0x53, 0x21, 0x24, 0x73, 0x35, 0x21, 0x00, 0x77, 0x25, 0xc4, 0xec,
+  0xeb, 0xc1, 0x41, 0x43, 0xc3, 0x55, 0xe9, 0x5a, 0xd7, 0xd5, 0xdd, 0x97,
+  0x27, 0x9b, 0x73, 0x43, 0x4f, 0x7a, 0x3c, 0x1a, 0x73, 0x3f, 0x8d, 0x62,
+  0xdf, 0xb4, 0xf6, 0xef, 0xbe, 0x15, 0x78, 0x0e, 0xea, 0xa3, 0xb3, 0x3f,
+  0x8d, 0x62, 0xdf, 0xb4, 0xf6, 0xdf, 0xbe, 0x15, 0x78, 0x8e, 0xea, 0xe7,
+  0xbc, 0xfb, 0xcf, 0x91, 0xd1, 0x69, 0xf7, 0x61, 0x45, 0x14, 0x57, 0x29,
+  0xd4, 0x14, 0x9b, 0xc7, 0x2f, 0x91, 0xdc, 0xbb, 0xe8, 0x79, 0x3f, 0x76,
+  0x69, 0xca, 0x93, 0x38, 0xe4, 0x7f, 0xf9, 0x3d, 0x97, 0x74, 0xdf, 0xfa,
+  0x22, 0x4f, 0xdd, 0x9a, 0x01, 0x03, 0x28, 0x12, 0xae, 0x49, 0xb5, 0x62,
+  0x56, 0xd7, 0x96, 0xcc, 0xdb, 0xfb, 0xbe, 0x4c, 0xa7, 0x50, 0x74, 0xa6,
+  0x22, 0xa5, 0x1c, 0xd2, 0x1d, 0x1e, 0x82, 0x10, 0x39, 0x47, 0xeb, 0x2d,
+  0x35, 0x74, 0x5a, 0xa0, 0x44, 0xb6, 0x5b, 0x23, 0x5b, 0x60, 0x30, 0x88,
+  0xf1, 0x22, 0xb4, 0x96, 0x58, 0x69, 0x03, 0xcd, 0x42, 0x12, 0x34, 0x90,
+  0x3d, 0x80, 0x0a, 0xac, 0x78, 0x51, 0x10, 0xdc, 0xf8, 0x87, 0x90, 0xdf,
+  0x1d, 0x4f, 0x33, 0x56, 0x98, 0xac, 0x59, 0xe2, 0x1d, 0xf4, 0x0b, 0x52,
+  0x43, 0xf2, 0x0e, 0xbd, 0x27, 0x99, 0x81, 0xbf, 0xd4, 0xab, 0x60, 0x56,
+  0xf7, 0x35, 0x35, 0xcd, 0xfa, 0x18, 0x5b, 0x43, 0x44, 0x17, 0xa8, 0x01,
+  0xa1, 0xaa, 0x28, 0xa2, 0xb0, 0x37, 0x0a, 0x81, 0xc8, 0xf1, 0xf8, 0xb3,
+  0x41, 0x9a, 0xc3, 0x9e, 0x47, 0x31, 0xa1, 0xcc, 0x97, 0xd1, 0xd3, 0xbb,
+  0xd3, 0x53, 0xd4, 0x9d, 0xc4, 0xfb, 0xb9, 0x87, 0x6d, 0x4d, 0xbd, 0x95,
+  0x69, 0xd9, 0x3f, 0x0b, 0xd4, 0x8a, 0xf3, 0xfb, 0x52, 0x74, 0x69, 0xda,
+  0xca, 0x75, 0x96, 0x52, 0xfa, 0xf4, 0xc1, 0x59, 0x63, 0x1b, 0x89, 0x59,
+  0x06, 0x45, 0x73, 0xb9, 0xb4, 0x88, 0x72, 0x5f, 0x4a, 0x9b, 0x6b, 0xcd,
+  0x25, 0x1d, 0x03, 0x84, 0x78, 0x9a, 0x84, 0xad, 0x91, 0x63, 0xbd, 0x29,
+  0xf4, 0xb3, 0x1d, 0xa5, 0x38, 0xe2, 0xbb, 0x92, 0x91, 0xd4, 0xd7, 0xb9,
+  0xd0, 0xa5, 0x41, 0x7b, 0xb1, 0x96, 0xc2, 0xd9, 0x5e, 0xb7, 0xa5, 0x0d,
+  0x57, 0xe5, 0xd5, 0xaa, 0x56, 0xb8, 0x6e, 0xad, 0x4c, 0xbe, 0x99, 0xfd,
+  0xb2, 0x73, 0xbc, 0xbd, 0xcd, 0x14, 0x51, 0x45, 0x73, 0x10, 0x74, 0x5b,
+  0x24, 0x08, 0x97, 0x06, 0x24, 0xa9, 0x1c, 0xe1, 0xa5, 0x85, 0x14, 0xfa,
+  0x75, 0x4e, 0x19, 0x9e, 0x59, 0x6f, 0xba, 0xd9, 0x84, 0x38, 0x8d, 0x2c,
+  0xad, 0x6a, 0x05, 0x45, 0x69, 0xd7, 0x2e, 0xa9, 0x1e, 0x8a, 0xee, 0xb7,
+  0xed, 0x0a, 0xd6, 0xf4, 0x67, 0x46, 0x1c, 0x4b, 0x92, 0x54, 0x9a, 0x58,
+  0x0a, 0x28, 0x48, 0x2a, 0x3a, 0x00, 0x92, 0x7c, 0x05, 0x30, 0x59, 0xb1,
+  0x3b, 0x9c, 0xf4, 0x87, 0x5d, 0x48, 0x8b, 0x1f, 0xbc, 0xb8, 0xef, 0x4e,
+  0x9e, 0xca, 0xc2, 0x85, 0xb5, 0x5b, 0x89, 0x69, 0xa5, 0x16, 0xd8, 0x49,
+  0xbe, 0x06, 0xae, 0x1a, 0xe4, 0x0a, 0x96, 0xd1, 0xb5, 0x4b, 0x5e, 0xdd,
+  0x6c, 0x6d, 0xa5, 0x1e, 0xf5, 0x27, 0xd1, 0xed, 0xa7, 0x47, 0xdd, 0x6d,
+  0x86, 0x56, 0xf3, 0xcb, 0x4a, 0x1b, 0x40, 0xda, 0x94, 0x4e, 0x80, 0x15,
+  0x5d, 0xc7, 0x93, 0x8c, 0xe3, 0x0e, 0x85, 0xb0, 0xa5, 0xcf, 0x9a, 0x9e,
+  0x9c, 0xe0, 0xf4, 0x4d, 0x4a, 0x71, 0x16, 0xe0, 0x5f, 0xc4, 0xa3, 0xbf,
+  0x15, 0x5e, 0xf3, 0x25, 0x69, 0xe6, 0x23, 0xd1, 0xa2, 0x75, 0xff, 0x00,
+  0xbf, 0x45, 0x7d, 0xf5, 0x8f, 0x68, 0x3b, 0x6b, 0x29, 0x46, 0xac, 0x94,
+  0xa7, 0x4d, 0x70, 0x9e, 0x76, 0xe9, 0x96, 0x6d, 0x19, 0x61, 0x6e, 0x78,
+  0x9f, 0xc4, 0x38, 0x4d, 0x3e, 0x5b, 0x8b, 0x0d, 0xc7, 0xd0, 0x0f, 0xc3,
+  0x2a, 0xe5, 0x07, 0xd8, 0x2a, 0x6f, 0x1a, 0xc9, 0x60, 0x5f, 0x01, 0x43,
+  0x04, 0xb6, 0xfa, 0x46, 0xd4, 0xd2, 0xfb, 0xf5, 0xe9, 0x1e, 0x9a, 0xa6,
+  0x6b, 0xb2, 0xcb, 0x3d, 0xcb, 0x65, 0xd1, 0x89, 0xad, 0x13, 0xb6, 0xd5,
+  0xb2, 0x07, 0x88, 0xf1, 0x1f, 0xdd, 0x5e, 0x0d, 0xaf, 0xb4, 0xf7, 0x4a,
+  0xba, 0x75, 0x9a, 0x71, 0x7c, 0xac, 0x71, 0xf0, 0x28, 0xaa, 0x3c, 0xee,
+  0x5e, 0xb4, 0x56, 0xa8, 0x8f, 0xb7, 0x2a, 0x2b, 0x52, 0x1a, 0x50, 0x53,
+  0x6e, 0x24, 0x29, 0x24, 0x78, 0x83, 0x5b, 0x6b, 0xf4, 0x24, 0xd4, 0x96,
+  0x51, 0xb8, 0x6b, 0xae, 0xea, 0xae, 0xe3, 0x5c, 0x1f, 0x72, 0x2e, 0x16,
+  0x9c, 0xfa, 0x38, 0xe5, 0x4c, 0x25, 0xa6, 0x05, 0xdf, 0x47, 0x41, 0x70,
+  0x9e, 0x58, 0x01, 0x47, 0xfd, 0xd3, 0xa5, 0x0b, 0x1e, 0x80, 0x57, 0xe9,
+  0xab, 0x46, 0xa3, 0xb2, 0x5b, 0x4c, 0x5b, 0xf5, 0x82, 0xe1, 0x64, 0x9a,
+  0x9e, 0x68, 0xd3, 0xe3, 0x39, 0x19, 0xdf, 0x9a, 0xb4, 0x94, 0x9d, 0x7a,
+  0xfa, 0xd5, 0xe3, 0x2d, 0x2d, 0x34, 0x56, 0x51, 0x52, 0x4d, 0x32, 0xa0,
+  0xcc, 0xc1, 0x12, 0xb1, 0x60, 0x7b, 0xc6, 0x4f, 0x6e, 0xfb, 0xe1, 0x57,
+  0x80, 0xee, 0xaf, 0x9b, 0xad, 0xd3, 0xa4, 0xcf, 0xc5, 0x70, 0x57, 0x27,
+  0x12, 0x67, 0x31, 0x92, 0x5b, 0xe2, 0x4b, 0xdf, 0x7f, 0x6e, 0xcc, 0x8e,
+  0xc9, 0xcd, 0xfa, 0xca, 0x90, 0x4f, 0xd7, 0x5f, 0x48, 0x8e, 0xea, 0xde,
+  0xed, 0xea, 0x9a, 0x7e, 0x86, 0x16, 0xab, 0x4c, 0x1a, 0xf5, 0x0a, 0x28,
+  0xa2, 0xb9, 0x8e, 0x90, 0xa4, 0xde, 0x37, 0x8d, 0xf0, 0x7f, 0x2e, 0x1b,
+  0xd7, 0xfa, 0x22, 0x47, 0xdd, 0x9a, 0x72, 0xa4, 0xee, 0x37, 0x74, 0xe1,
+  0x06, 0x5c, 0x7d, 0x16, 0x89, 0x1f, 0x76, 0x68, 0x08, 0x8f, 0xc1, 0xcd,
+  0x21, 0xee, 0x1b, 0x0b, 0xc7, 0x4e, 0xd2, 0xef, 0x73, 0x9b, 0x35, 0x64,
+  0x7a, 0xe4, 0x2d, 0x09, 0xff, 0x00, 0xa1, 0x08, 0x15, 0x64, 0x55, 0x7b,
+  0xf8, 0x37, 0xa5, 0x23, 0x81, 0xb8, 0x98, 0x1e, 0x30, 0x42, 0x8f, 0xb4,
+  0xad, 0x44, 0xff, 0x00, 0x89, 0x35, 0x61, 0x51, 0xee, 0xf2, 0x42, 0xd8,
+  0x28, 0xa2, 0x8a, 0x12, 0x15, 0x4e, 0xf1, 0x02, 0x62, 0xa5, 0xe4, 0xf2,
+  0x7c, 0xe2, 0x52, 0xc9, 0xec, 0xd2, 0x3d, 0x1a, 0xab, 0x88, 0xf7, 0x55,
+  0x17, 0x7e, 0x25, 0x57, 0xa9, 0xa4, 0xf7, 0xf6, 0xea, 0xfb, 0x6b, 0xe4,
+  0xfd, 0xad, 0xa8, 0xe3, 0x6f, 0x08, 0x2e, 0xaf, 0xe8, 0x8c, 0xaa, 0xf0,
+  0x76, 0xe1, 0x97, 0x76, 0x6c, 0xd7, 0x94, 0xca, 0x90, 0xd9, 0x5b, 0x65,
+  0x25, 0x27, 0x97, 0xbc, 0x6f, 0xc6, 0xbb, 0x33, 0xdb, 0xf4, 0x5b, 0xdc,
+  0x96, 0x3c, 0x91, 0xb5, 0x04, 0x34, 0x0f, 0x9e, 0xa1, 0xa2, 0x77, 0x4b,
+  0x34, 0x57, 0xc7, 0xc7, 0xb4, 0x2b, 0x46, 0xd5, 0xda, 0xaf, 0x0b, 0x79,
+  0x32, 0xd4, 0xf1, 0x80, 0xa2, 0xbd, 0xb2, 0xd3, 0xaf, 0x38, 0x1b, 0x65,
+  0xb5, 0x38, 0xb3, 0xdc, 0x12, 0x36, 0x69, 0x9a, 0xd9, 0x87, 0x48, 0x53,
+  0x42, 0x4d, 0xd9, 0xf4, 0x41, 0x8e, 0x3a, 0x9e, 0x63, 0xe7, 0x1a, 0xce,
+  0xda, 0xce, 0xb5, 0xcb, 0xc5, 0x28, 0xe7, 0xe9, 0xf3, 0x61, 0x26, 0xc5,
+  0x74, 0x21, 0x6e, 0x28, 0x25, 0x09, 0x2a, 0x51, 0xee, 0x00, 0x6e, 0x99,
+  0x2d, 0x18, 0x7c, 0xf9, 0x2d, 0x89, 0x13, 0x54, 0x98, 0x51, 0xfb, 0xca,
+  0x9c, 0x3a, 0x3a, 0xf6, 0x54, 0x83, 0x97, 0xcb, 0x05, 0x89, 0x05, 0xab,
+  0x2c, 0x31, 0x25, 0xf1, 0xd0, 0xbe, 0xe0, 0xe9, 0x4b, 0x77, 0x7b, 0xdd,
+  0xca, 0xe8, 0xe1, 0x54, 0xb9, 0x2b, 0x52, 0x7c, 0x10, 0x0e, 0x92, 0x3e,
+  0xaa, 0xed, 0xf7, 0x36, 0x76, 0xbf, 0x7b, 0x2f, 0x79, 0x2f, 0x28, 0xf1,
+  0xf3, 0x7d, 0x7e, 0x44, 0xe1, 0x21, 0x94, 0xdc, 0x71, 0x9c, 0x78, 0x72,
+  0xdb, 0xd8, 0xf7, 0x42, 0x58, 0xfe, 0x95, 0x7f, 0x04, 0x1a, 0x5f, 0xbc,
+  0xe4, 0x57, 0x4b, 0xa2, 0x88, 0x7e, 0x41, 0x43, 0x5e, 0x0d, 0xa3, 0xa2,
+  0x45, 0x44, 0xd1, 0x58, 0x57, 0xed, 0x2a, 0xd5, 0x63, 0xee, 0xe3, 0xdd,
+  0x8f, 0x92, 0xd9, 0x7c, 0xfc, 0xfe, 0x64, 0x39, 0x36, 0x14, 0xed, 0x87,
+  0x38, 0x8b, 0xd6, 0x39, 0x37, 0x1d, 0x7d, 0x43, 0xb4, 0x4a, 0x7b, 0x48,
+  0xe4, 0xf8, 0x1f, 0xff, 0x00, 0xdf, 0xfb, 0xd2, 0x4d, 0x77, 0x58, 0x2e,
+  0x0e, 0x5b, 0x2e, 0xcc, 0x4c, 0x6c, 0xfc, 0x05, 0x79, 0xc3, 0xd2, 0x3c,
+  0x45, 0x57, 0xb3, 0xae, 0x55, 0xbd, 0x74, 0xe7, 0xe1, 0x7b, 0x3f, 0x83,
+  0xe4, 0x45, 0xe1, 0x9c, 0x6e, 0xb6, 0xb6, 0x9d, 0x5b, 0x4e, 0x24, 0xa5,
+  0x68, 0x51, 0x4a, 0x81, 0xf0, 0x23, 0xbc, 0x57, 0x9a, 0x6a, 0xe2, 0x35,
+  0xbd, 0xb6, 0xae, 0x0d, 0x5d, 0x62, 0xf5, 0x8d, 0x39, 0x21, 0x7b, 0x1e,
+  0x0a, 0xd7, 0xfd, 0xc7, 0xfd, 0xe9, 0x56, 0xb2, 0xbc, 0xb6, 0x76, 0xd5,
+  0xa5, 0x49, 0xf4, 0xfd, 0x57, 0x47, 0xf9, 0x06, 0xb0, 0xf0, 0x59, 0x7c,
+  0x2b, 0xbb, 0x76, 0xf0, 0x1c, 0xb5, 0xba, 0xad, 0xad, 0x8f, 0x39, 0xbd,
+  0xf8, 0xa4, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xda, 0x9d, 0xaa, 0x8e, 0xc7,
+  0x2e, 0x4b, 0xb5, 0x5e, 0x18, 0x98, 0x92, 0x79, 0x52, 0xad, 0x2c, 0x7a,
+  0x52, 0x7b, 0xea, 0xee, 0x65, 0xc4, 0x3c, 0xca, 0x1d, 0x6c, 0x85, 0x21,
+  0x60, 0x10, 0x47, 0x88, 0xaf, 0xbe, 0xf6, 0x6a, 0xfb, 0xed, 0x16, 0xbe,
+  0xea, 0x4f, 0xbd, 0x0d, 0xbe, 0x5d, 0x3f, 0x83, 0x6a, 0x72, 0xca, 0x3d,
+  0xd6, 0x08, 0xeb, 0x59, 0xa3, 0x55, 0xf4, 0x66, 0x87, 0xce, 0x37, 0x58,
+  0xc2, 0xdb, 0x9b, 0xcf, 0xb5, 0x05, 0xf3, 0x06, 0xf8, 0x8b, 0x6f, 0x96,
+  0x9f, 0x52, 0x64, 0x86, 0x5e, 0x3f, 0xf5, 0x29, 0x75, 0xf4, 0x70, 0xee,
+  0xaf, 0x9e, 0x33, 0x51, 0xae, 0x33, 0xdc, 0xff, 0x00, 0x6a, 0x71, 0xd3,
+  0xf5, 0xf2, 0x01, 0xff, 0x00, 0x8a, 0xfa, 0x1c, 0x77, 0x56, 0x93, 0x79,
+  0xc7, 0xc0, 0xce, 0x1c, 0xbf, 0x8f, 0xf0, 0x14, 0x51, 0x45, 0x66, 0x68,
+  0x14, 0x9b, 0xc6, 0xf3, 0xae, 0x10, 0x65, 0xa7, 0xff, 0x00, 0x48, 0x91,
+  0xf7, 0x66, 0x9c, 0xa9, 0x33, 0x8e, 0x5f, 0x23, 0xb9, 0x77, 0xd0, 0xf2,
+  0x7e, 0xec, 0xd0, 0x11, 0x9f, 0x83, 0x79, 0x2d, 0xf0, 0x82, 0xd5, 0x05,
+  0x67, 0xdf, 0x60, 0x3f, 0x2e, 0x1b, 0xa0, 0xf7, 0x82, 0xdc, 0x97, 0x53,
+  0xaf, 0xee, 0x03, 0xfb, 0xea, 0xc6, 0xaa, 0xb7, 0x82, 0xb2, 0xbc, 0x87,
+  0x22, 0xcb, 0x31, 0xb7, 0x34, 0x92, 0x64, 0xb5, 0x78, 0x8f, 0xb3, 0xf0,
+  0x9b, 0x90, 0xd8, 0x4a, 0xf4, 0x3d, 0x01, 0xd6, 0x9c, 0xff, 0x00, 0x98,
+  0x7a, 0x6a, 0xd2, 0x1d, 0xd5, 0x69, 0xad, 0x32, 0x68, 0xac, 0x25, 0xaa,
+  0x29, 0x85, 0x14, 0x51, 0x55, 0x2c, 0x15, 0x4a, 0xe6, 0x71, 0x8c, 0x4c,
+  0x9a, 0x6b, 0x44, 0x10, 0x0b, 0x9c, 0xc3, 0xd8, 0x7a, 0xd5, 0xd5, 0x4a,
+  0xd9, 0x8d, 0x86, 0xd7, 0x26, 0x4a, 0x6e, 0xd7, 0x17, 0xd4, 0xcb, 0x4d,
+  0x23, 0x95, 0xce, 0x51, 0xf0, 0xbd, 0x15, 0xe0, 0xfb, 0x43, 0x61, 0x2b,
+  0xcb, 0x65, 0xa3, 0x98, 0xbc, 0xef, 0xb6, 0xdd, 0x4a, 0x4e, 0x39, 0x45,
+  0x59, 0x16, 0x34, 0x89, 0x4e, 0x86, 0xa3, 0xb2, 0xb7, 0x56, 0x7b, 0x82,
+  0x46, 0xe9, 0xa6, 0x06, 0x1e, 0x19, 0x68, 0x4a, 0xbe, 0xcb, 0x6e, 0x1b,
+  0x3d, 0xfc, 0x9b, 0xf3, 0x8d, 0x7b, 0x97, 0x96, 0x43, 0xb7, 0xb4, 0x63,
+  0x63, 0xd0, 0x50, 0xca, 0x7b, 0xbb, 0x65, 0x8f, 0x38, 0xfa, 0xe9, 0x5a,
+  0x7c, 0xe9, 0x73, 0x9e, 0x2e, 0xcb, 0x90, 0xb7, 0x54, 0x7f, 0x48, 0xd7,
+  0xc5, 0x62, 0xca, 0xd7, 0x9f, 0xee, 0xcb, 0xf2, 0x8f, 0xf2, 0xcc, 0x76,
+  0x43, 0x5b, 0xf9, 0x2d, 0xa6, 0xd0, 0xd9, 0x63, 0x1f, 0x82, 0x92, 0xbe,
+  0xe2, 0xfb, 0x83, 0xad, 0x2c, 0x5c, 0xee, 0x93, 0xee, 0x4e, 0x97, 0x26,
+  0x49, 0x5b, 0x87, 0xd1, 0xbe, 0x83, 0xea, 0xae, 0x3a, 0x2b, 0x9a, 0xe7,
+  0xb4, 0x2b, 0xdc, 0x2d, 0x2d, 0xe2, 0x3e, 0x4b, 0x65, 0xf9, 0x10, 0xe4,
+  0xd8, 0x51, 0x45, 0x15, 0xc2, 0x40, 0x51, 0x45, 0x14, 0x01, 0x45, 0x14,
+  0x50, 0x0f, 0x18, 0xe2, 0x86, 0x41, 0x88, 0xca, 0xb2, 0x38, 0x41, 0x93,
+  0x18, 0x76, 0x91, 0xc9, 0xff, 0x00, 0x0f, 0xfc, 0x7d, 0x74, 0x8e, 0xa0,
+  0x52, 0xa2, 0x95, 0x02, 0x08, 0x3a, 0x20, 0xf8, 0x54, 0x9e, 0x2f, 0x73,
+  0x55, 0xaa, 0xf4, 0xc4, 0xa0, 0x4f, 0x20, 0x57, 0x2b, 0x83, 0xd2, 0x93,
+  0xdf, 0x52, 0x5c, 0x42, 0xb6, 0x26, 0x1d, 0xe0, 0x4c, 0x8e, 0x37, 0x1a,
+  0x6a, 0x7b, 0x54, 0x11, 0xdd, 0xbf, 0x1f, 0xfc, 0xfd, 0x75, 0xec, 0x57,
+  0xff, 0x00, 0x95, 0x67, 0x1a, 0xdf, 0x8a, 0x9f, 0x75, 0xfc, 0x3f, 0x0b,
+  0xfd, 0xbf, 0x22, 0xcf, 0x75, 0x91, 0x6a, 0xad, 0x2e, 0x18, 0x5d, 0xbc,
+  0xb2, 0xd0, 0x60, 0x3a, 0xad, 0xbb, 0x17, 0xa2, 0x77, 0xe2, 0x83, 0xdd,
+  0xfd, 0xdd, 0xd5, 0x56, 0xd4, 0xc6, 0x19, 0x71, 0x5d, 0xb7, 0x21, 0x8c,
+  0xea, 0x49, 0xe4, 0x71, 0x41, 0xb7, 0x07, 0xa4, 0x13, 0xaf, 0xfc, 0x1a,
+  0xaf, 0x62, 0xde, 0xbb, 0x3b, 0xb8, 0xc9, 0xf0, 0xf6, 0x7f, 0x07, 0xfc,
+  0x08, 0x3c, 0x32, 0xe9, 0xac, 0x13, 0xaa, 0xcd, 0x68, 0x9b, 0x25, 0x98,
+  0x91, 0x9e, 0x95, 0x25, 0xc4, 0xb4, 0xc3, 0x2d, 0xa9, 0xc7, 0x16, 0xa3,
+  0xa0, 0x94, 0xa4, 0x6c, 0x93, 0xec, 0x15, 0xfa, 0xa1, 0xd2, 0x7c, 0xf9,
+  0x92, 0x3c, 0xdc, 0xde, 0x27, 0x5c, 0xee, 0x0c, 0xab, 0x99, 0x07, 0x3b,
+  0xb3, 0xc3, 0xdf, 0xeb, 0x32, 0xdb, 0x01, 0x5f, 0xf5, 0x28, 0xd7, 0xd1,
+  0x43, 0xba, 0xbe, 0x69, 0xb3, 0xa1, 0xd7, 0x71, 0xfc, 0x56, 0xef, 0x25,
+  0xb2, 0xdc, 0x9b, 0xde, 0x63, 0x16, 0xec, 0xf2, 0x7d, 0x06, 0x44, 0xa2,
+  0xb4, 0x8f, 0xa9, 0x05, 0x03, 0xea, 0xaf, 0xa5, 0x85, 0x6b, 0x56, 0x3a,
+  0x70, 0xbd, 0x0c, 0x68, 0xcb, 0x56, 0x5f, 0xa8, 0x51, 0x45, 0x15, 0x91,
+  0xb0, 0x52, 0x67, 0x1c, 0xbe, 0x47, 0x72, 0xef, 0xa1, 0xe4, 0xfd, 0xd9,
+  0xa7, 0x3a, 0x4c, 0xe3, 0x91, 0xd7, 0x07, 0x72, 0xfd, 0xf7, 0x7b, 0x91,
+  0x27, 0xee, 0xcd, 0x00, 0x83, 0x74, 0x98, 0x31, 0x9c, 0x8e, 0xc3, 0x9a,
+  0x95, 0x72, 0x44, 0x86, 0x0c, 0x1b, 0xa9, 0x1e, 0x10, 0xde, 0x29, 0xf7,
+  0xc5, 0x78, 0xe9, 0xb7, 0x03, 0x6b, 0xf9, 0xbc, 0xf5, 0x78, 0xa7, 0xb8,
+  0x55, 0x65, 0x1a, 0xd0, 0xf5, 0xde, 0x12, 0xa2, 0x18, 0x7e, 0x53, 0x1d,
+  0xe6, 0xbb, 0x37, 0x50, 0xe0, 0xd2, 0x16, 0x92, 0x34, 0x52, 0x49, 0xf0,
+  0x20, 0x91, 0x5d, 0x5c, 0x36, 0x9f, 0x37, 0x19, 0x9c, 0x9e, 0x1c, 0xe4,
+  0x6f, 0xf3, 0xbf, 0x19, 0x92, 0xbb, 0x1c, 0xc5, 0x9d, 0xf9, 0x7c, 0x34,
+  0xfe, 0x66, 0xfc, 0x5e, 0x6b, 0xa2, 0x54, 0x3b, 0xca, 0x79, 0x55, 0xd7,
+  0x6a, 0xd7, 0x5d, 0xdc, 0x62, 0xa5, 0x94, 0xce, 0x4b, 0x49, 0x4b, 0x4e,
+  0x1a, 0xe0, 0xb0, 0xea, 0x37, 0x23, 0xbb, 0xb3, 0x65, 0xb6, 0x2e, 0x63,
+  0xc3, 0x98, 0x8e, 0x88, 0x46, 0xf5, 0xcc, 0xaf, 0x45, 0x49, 0x0a, 0x4a,
+  0xe2, 0xd3, 0x2e, 0xae, 0xd5, 0x15, 0xd4, 0x6c, 0xa1, 0x0e, 0x9e, 0x7d,
+  0x7a, 0xc7, 0x4a, 0xf1, 0xbb, 0x4e, 0xe2, 0x76, 0xf6, 0x93, 0xab, 0x4f,
+  0x94, 0x8e, 0xa9, 0x3c, 0x21, 0x5a, 0x5e, 0x69, 0x7e, 0x7d, 0xf2, 0xe2,
+  0x25, 0x06, 0x53, 0xbe, 0x88, 0x42, 0x46, 0xa9, 0x8b, 0x1b, 0xc8, 0x7f,
+  0x94, 0x71, 0x9e, 0xb2, 0x5d, 0x12, 0x8e, 0xd9, 0xc6, 0xc8, 0x42, 0xc0,
+  0xd0, 0x57, 0xff, 0x00, 0xba, 0xae, 0xab, 0x7d, 0xbe, 0x53, 0x90, 0xa6,
+  0xb3, 0x2d, 0xa3, 0xa5, 0xb4, 0xb0, 0xa1, 0x5f, 0x9d, 0x5a, 0xf6, 0xc5,
+  0xcd, 0x3a, 0xba, 0xaa, 0xcd, 0xca, 0x2f, 0x94, 0xf7, 0xca, 0xea, 0x73,
+  0xa9, 0xbc, 0xee, 0x17, 0x08, 0xae, 0x42, 0x9a, 0xf4, 0x57, 0x46, 0x96,
+  0xd2, 0x8a, 0x4d, 0x68, 0xa7, 0x1e, 0x20, 0x45, 0x6e, 0x5c, 0x78, 0x99,
+  0x04, 0x50, 0x0b, 0x72, 0x10, 0x03, 0x9a, 0xf0, 0x55, 0x27, 0x57, 0x25,
+  0xf5, 0xb7, 0xd9, 0xab, 0xca, 0x9a, 0xe3, 0x95, 0xea, 0x9f, 0x04, 0x49,
+  0x61, 0x85, 0x14, 0x51, 0x5c, 0x64, 0x05, 0x14, 0x51, 0x40, 0x14, 0x51,
+  0x45, 0x00, 0x51, 0x45, 0x14, 0x01, 0x4f, 0x56, 0x84, 0xff, 0x00, 0x29,
+  0xf0, 0xb7, 0x2d, 0xa4, 0x83, 0x36, 0x11, 0xe6, 0x64, 0x9e, 0xf2, 0x3c,
+  0x07, 0xda, 0x3e, 0xb1, 0x48, 0xb5, 0x33, 0x86, 0xdd, 0x0d, 0xa6, 0xfa,
+  0xcb, 0xe4, 0x9e, 0xc9, 0x67, 0x91, 0xc1, 0xea, 0x35, 0xe9, 0x76, 0x65,
+  0x78, 0x52, 0xad, 0xa2, 0xa7, 0x82, 0x7d, 0xd7, 0xf0, 0x7d, 0x7e, 0x5c,
+  0x96, 0x8b, 0xc3, 0x22, 0xa4, 0xc7, 0x7a, 0x33, 0xca, 0x65, 0xf6, 0x94,
+  0xdb, 0x89, 0x3a, 0x29, 0x50, 0xd5, 0x32, 0xf0, 0xff, 0x00, 0x1f, 0x7e,
+  0xe3, 0x74, 0x6e, 0x6b, 0xc8, 0x28, 0x89, 0x1d, 0x41, 0x44, 0x91, 0xf0,
+  0xd4, 0x3b, 0x92, 0x3f, 0xef, 0x56, 0x83, 0xd0, 0xe1, 0x4a, 0xe5, 0x71,
+  0xd8, 0xcc, 0xbb, 0xe2, 0x14, 0xa4, 0x03, 0x5b, 0x9b, 0x42, 0x1b, 0x40,
+  0x43, 0x68, 0x4a, 0x12, 0x3b, 0x82, 0x46, 0x80, 0xaf, 0xab, 0xb4, 0xf6,
+  0x5a, 0x14, 0xab, 0xaa, 0x93, 0x9e, 0xa8, 0xad, 0xd2, 0xc7, 0xd4, 0xd1,
+  0x53, 0xc3, 0x3d, 0x55, 0x75, 0xc7, 0x7b, 0x82, 0xd7, 0x8e, 0x47, 0xc4,
+  0x22, 0x3a, 0x51, 0x37, 0x25, 0x7b, 0xc8, 0xc9, 0x49, 0xf3, 0x9b, 0x88,
+  0x00, 0x54, 0xa7, 0x3d, 0x81, 0xbd, 0xa3, 0xda, 0xe2, 0x69, 0xea, 0xf1,
+  0x72, 0x83, 0x67, 0xb5, 0xca, 0xba, 0x5c, 0xa5, 0x37, 0x16, 0x14, 0x46,
+  0x94, 0xf3, 0xef, 0x38, 0x74, 0x94, 0x21, 0x23, 0x64, 0x93, 0x54, 0xed,
+  0x95, 0xc9, 0xb9, 0x0d, 0xfe, 0x6e, 0x6f, 0x75, 0x8c, 0xe4, 0x77, 0xa6,
+  0xb6, 0x23, 0xdb, 0x62, 0x3a, 0x34, 0xb8, 0x70, 0x41, 0xda, 0x42, 0xc7,
+  0x83, 0x8e, 0x1f, 0x3d, 0x43, 0xbc, 0x6d, 0x29, 0xfc, 0xda, 0xfb, 0x3a,
+  0x14, 0x9d, 0x49, 0xe0, 0x8a, 0xd5, 0x55, 0x38, 0xe7, 0xa9, 0xa7, 0x2e,
+  0x43, 0x6d, 0x3d, 0x8a, 0xb4, 0xd2, 0x02, 0x1b, 0x4e, 0x4b, 0x6d, 0x4a,
+  0x52, 0x06, 0x82, 0x40, 0x78, 0x68, 0x0f, 0x65, 0x5e, 0x63, 0xba, 0xa8,
+  0xec, 0xcb, 0xe3, 0x38, 0xb7, 0x7f, 0xfa, 0xcf, 0x6e, 0xfb, 0xe1, 0x57,
+  0x88, 0xee, 0xad, 0x2f, 0x3e, 0xf3, 0xe4, 0x67, 0x67, 0xf7, 0x61, 0x45,
+  0x14, 0x57, 0x29, 0xd4, 0x14, 0x99, 0xc7, 0x1f, 0x91, 0xec, 0xb7, 0xe8,
+  0x89, 0x1f, 0xc0, 0x69, 0xce, 0x93, 0x38, 0xe3, 0xf2, 0x3d, 0x97, 0x7d,
+  0x11, 0x23, 0xf8, 0x0d, 0x00, 0xdb, 0x11, 0x09, 0x4c, 0x56, 0x92, 0x90,
+  0x00, 0x09, 0x1d, 0x00, 0xa8, 0x5c, 0xe7, 0x17, 0x81, 0x95, 0xd9, 0xc4,
+  0x09, 0x6b, 0x76, 0x3b, 0xec, 0xb8, 0x99, 0x10, 0x66, 0xb2, 0x74, 0xf4,
+  0x39, 0x09, 0xf8, 0x0e, 0xb6, 0x7f, 0x48, 0x1f, 0x0e, 0xe2, 0x36, 0x08,
+  0x20, 0x9a, 0x9c, 0x8d, 0xf1, 0x76, 0xfe, 0x60, 0xfb, 0x2b, 0x61, 0x1b,
+  0xa0, 0x11, 0xf1, 0x3c, 0xb6, 0x74, 0x7b, 0xab, 0x78, 0x96, 0x6c, 0xdb,
+  0x30, 0xaf, 0xda, 0x3e, 0x47, 0x29, 0x03, 0x96, 0x35, 0xd9, 0x03, 0xf3,
+  0xd9, 0x27, 0xb9, 0xc0, 0x3a, 0xa9, 0xa3, 0xe7, 0x0e, 0xa4, 0x6d, 0x3d,
+  0x69, 0xbe, 0xe1, 0x12, 0x3d, 0xc2, 0x13, 0x91, 0x24, 0xa0, 0x2d, 0xa7,
+  0x06, 0x88, 0xae, 0x3c, 0x9b, 0x1f, 0xb3, 0xe4, 0x96, 0x87, 0x2d, 0x57,
+  0xb8, 0x2d, 0xcc, 0x88, 0xb2, 0x15, 0xc8, 0xad, 0x82, 0x85, 0x0e, 0xe5,
+  0xa1, 0x43, 0xaa, 0x14, 0x3b, 0xc2, 0x92, 0x41, 0x07, 0xba, 0x93, 0xfb,
+  0x4c, 0xd7, 0x05, 0x46, 0x9f, 0x4c, 0xbc, 0xd3, 0x1e, 0x47, 0x73, 0xad,
+  0x80, 0x6e, 0xb1, 0x13, 0xd7, 0xe1, 0x27, 0xa2, 0x64, 0xa4, 0x00, 0x3a,
+  0x8e, 0x57, 0x3d, 0x4b, 0x3d, 0x4d, 0x65, 0x15, 0x24, 0xe3, 0x25, 0x94,
+  0xc1, 0x1d, 0x91, 0xe1, 0x17, 0x1b, 0x79, 0x53, 0xf0, 0x42, 0xa6, 0xc6,
+  0xef, 0xf3, 0x47, 0xbe, 0x27, 0xda, 0x3c, 0x7d, 0xa2, 0x95, 0x08, 0x20,
+  0x90, 0x41, 0x04, 0x74, 0x20, 0xd5, 0xd1, 0x8a, 0xe4, 0xf6, 0x2c, 0xa2,
+  0x07, 0x97, 0x58, 0xae, 0x6c, 0x4d, 0x69, 0x27, 0x95, 0xc0, 0x82, 0x43,
+  0x8c, 0xab, 0xf4, 0x5c, 0x41, 0xd2, 0x90, 0xaf, 0xd5, 0x50, 0x07, 0xd5,
+  0x5e, 0xaf, 0x58, 0xed, 0xa2, 0xef, 0xb5, 0x4a, 0x8a, 0x90, 0xef, 0xf5,
+  0xad, 0xf9, 0xab, 0xfe, 0xf1, 0xdf, 0xf5, 0xee, 0xbe, 0x46, 0xff, 0x00,
+  0xd9, 0x58, 0xcd, 0xb9, 0xda, 0xcb, 0x1e, 0x8f, 0x8f, 0x93, 0x32, 0x95,
+  0x3f, 0x21, 0x27, 0x06, 0x7d, 0xbb, 0xa5, 0xa2, 0x66, 0x3b, 0x24, 0xef,
+  0x99, 0x25, 0x6c, 0x6f, 0xc0, 0xd2, 0x7c, 0xa6, 0x1c, 0x8d, 0x25, 0xc6,
+  0x1d, 0x1a, 0x5b, 0x6a, 0x29, 0x22, 0xac, 0x04, 0x61, 0x13, 0xad, 0x77,
+  0x26, 0x67, 0xda, 0x26, 0xa1, 0xde, 0xc9, 0x7b, 0xec, 0xdd, 0x1c, 0xaa,
+  0x23, 0xc4, 0x6c, 0x74, 0x3f, 0xe1, 0x5c, 0x5c, 0x48, 0xb1, 0xc9, 0xf2,
+  0xe4, 0x5c, 0xe3, 0x45, 0x71, 0x49, 0x79, 0x3e, 0xfc, 0x10, 0x92, 0xae,
+  0x55, 0x7a, 0xf5, 0x5e, 0x55, 0xef, 0x67, 0x5c, 0xfd, 0x8d, 0x3a, 0xb0,
+  0x7a, 0xa9, 0xed, 0xe7, 0x98, 0xbe, 0x38, 0xf2, 0x7f, 0xa1, 0x57, 0x17,
+  0x8d, 0xc4, 0x8a, 0x28, 0x20, 0x82, 0x41, 0x04, 0x11, 0xe0, 0x68, 0xaf,
+  0x9a, 0x33, 0x0a, 0x28, 0xa2, 0x80, 0x28, 0xa2, 0xbd, 0x34, 0xd3, 0x8f,
+  0x2c, 0x21, 0xa6, 0xd6, 0xe2, 0x8f, 0x72, 0x52, 0x9d, 0x9a, 0x94, 0x9b,
+  0xd9, 0x03, 0xcd, 0x15, 0x39, 0x6f, 0xc4, 0xaf, 0xf3, 0x48, 0x29, 0x80,
+  0xb6, 0x50, 0x7f, 0x39, 0xff, 0x00, 0x33, 0x5f, 0x51, 0xeb, 0xfe, 0x14,
+  0xd3, 0x69, 0xe1, 0xdb, 0x28, 0x21, 0x77, 0x49, 0xa5, 0xc3, 0xe2, 0xdb,
+  0x03, 0x43, 0xfe, 0x63, 0xd4, 0xff, 0x00, 0x70, 0xaf, 0x4e, 0xdb, 0xb1,
+  0xaf, 0x6e, 0x5f, 0x76, 0x9b, 0x4b, 0xcd, 0xec, 0xbf, 0x5f, 0xd8, 0xb2,
+  0x83, 0x65, 0x7d, 0x16, 0x3b, 0xf2, 0x9f, 0x4b, 0x11, 0x99, 0x5b, 0xce,
+  0xab, 0xb9, 0x28, 0x4e, 0xc9, 0xa7, 0xbc, 0x67, 0x02, 0x51, 0x52, 0x24,
+  0xde, 0xd5, 0xca, 0x06, 0x88, 0x8e, 0x85, 0x75, 0x3f, 0x38, 0x8f, 0xb0,
+  0x7f, 0x7d, 0x3b, 0xdb, 0x2d, 0x90, 0x2d, 0x8c, 0xf6, 0x50, 0x62, 0xb6,
+  0xc2, 0x7c, 0x4a, 0x47, 0x53, 0xed, 0x3d, 0xe7, 0xeb, 0xae, 0xa2, 0x48,
+  0xaf, 0xad, 0xec, 0xff, 0x00, 0x66, 0x28, 0xd1, 0x6a, 0x77, 0x0f, 0x53,
+  0xf2, 0xe9, 0xfe, 0x7f, 0xdd, 0x8d, 0x63, 0x4d, 0x2e, 0x41, 0xb4, 0x25,
+  0xb6, 0xd2, 0xda, 0x12, 0x12, 0x94, 0x80, 0x12, 0x07, 0x70, 0x02, 0xb9,
+  0x6e, 0xd7, 0x18, 0x36, 0x9b, 0x74, 0x8b, 0x95, 0xca, 0x5b, 0x10, 0xe1,
+  0x46, 0x6c, 0xb8, 0xfb, 0xef, 0x2c, 0x25, 0x0d, 0xa4, 0x77, 0x92, 0x4f,
+  0x41, 0x4b, 0x79, 0x46, 0x7d, 0x6c, 0xb5, 0x5c, 0x7d, 0xc4, 0xb5, 0xc7,
+  0x7f, 0x20, 0xc8, 0x54, 0x3c, 0xcb, 0x5d, 0xbf, 0x4b, 0x71, 0x1e, 0x85,
+  0x3c, 0xb2, 0x79, 0x18, 0x47, 0x77, 0x9c, 0xb2, 0x3d, 0x41, 0x47, 0xa5,
+  0x70, 0x5b, 0xf0, 0xeb, 0xa5, 0xfe, 0xe6, 0xc5, 0xef, 0x88, 0x72, 0x62,
+  0xcd, 0x5c, 0x77, 0x03, 0xb0, 0xac, 0xb1, 0x49, 0x30, 0x21, 0xac, 0x1f,
+  0x35, 0x6a, 0xe6, 0x00, 0xbe, 0xe8, 0xfd, 0x25, 0x00, 0x94, 0x9f, 0x82,
+  0x90, 0x7a, 0xd7, 0xd4, 0xf0, 0x68, 0x72, 0x44, 0x8b, 0x33, 0x89, 0x37,
+  0x18, 0xd7, 0x7b, 0xc4, 0x57, 0xe0, 0xe2, 0x11, 0x1e, 0x43, 0xf6, 0xeb,
+  0x73, 0xc9, 0x28, 0x76, 0xe8, 0xea, 0x4e, 0xd3, 0x21, 0xf4, 0x9e, 0xa9,
+  0x65, 0x24, 0x02, 0xdb, 0x67, 0xaa, 0x88, 0xe7, 0x5e, 0x86, 0x93, 0x4e,
+  0xf7, 0x3b, 0x34, 0x19, 0xe9, 0xdb, 0x8d, 0xf2, 0x39, 0xe0, 0xb4, 0x74,
+  0x23, 0xff, 0x00, 0x35, 0x22, 0x00, 0xd5, 0x1a, 0x1a, 0xa9, 0x8c, 0x9c,
+  0x5e, 0x51, 0x59, 0x45, 0x49, 0x61, 0x95, 0x17, 0x12, 0xec, 0xd2, 0x6d,
+  0xd2, 0x31, 0x67, 0x54, 0xa4, 0xb8, 0xc9, 0xca, 0x2d, 0xa0, 0x2c, 0x74,
+  0x23, 0xdf, 0x87, 0x78, 0xab, 0x78, 0x77, 0x52, 0x27, 0x19, 0x47, 0xf3,
+  0x2c, 0x5f, 0xf6, 0xaa, 0xd9, 0xf7, 0xe2, 0x9e, 0xea, 0xd5, 0x2a, 0x4a,
+  0xa3, 0xcc, 0x88, 0xa7, 0x4d, 0x53, 0x58, 0x41, 0x45, 0x79, 0x24, 0x83,
+  0xa0, 0x01, 0xfa, 0xe8, 0xaa, 0x17, 0x3d, 0x52, 0x67, 0x1c, 0x7e, 0x47,
+  0xb2, 0xef, 0xa2, 0x24, 0x7f, 0x01, 0xa7, 0x3a, 0x4c, 0xe3, 0x8f, 0xc8,
+  0xf6, 0x5d, 0xf4, 0x44, 0x8f, 0xe0, 0x34, 0x03, 0x7c, 0x6f, 0x8b, 0xb7,
+  0xf3, 0x07, 0xd9, 0x5b, 0x2b, 0x5c, 0x6f, 0x8b, 0xb7, 0xf3, 0x07, 0xd9,
+  0x5b, 0x28, 0x03, 0x5d, 0x68, 0xd5, 0x14, 0x50, 0x0a, 0xd9, 0x3e, 0x07,
+  0x8e, 0xdf, 0xa7, 0x7b, 0xa6, 0xe4, 0x77, 0xad, 0xf7, 0x74, 0x8d, 0x22,
+  0xe9, 0x6e, 0x78, 0xc6, 0x96, 0x9f, 0x57, 0x68, 0x8d, 0x15, 0x0f, 0xd5,
+  0x5f, 0x32, 0x7d, 0x55, 0x14, 0x22, 0xf1, 0x37, 0x1e, 0xf8, 0x94, 0xfb,
+  0x5e, 0x63, 0x0d, 0x00, 0xe9, 0xa9, 0xc3, 0xc8, 0x66, 0x81, 0xe0, 0x03,
+  0xa8, 0x49, 0x69, 0x67, 0xda, 0x84, 0x7b, 0x7c, 0x69, 0xf7, 0x5d, 0x77,
+  0x47, 0x28, 0xa0, 0x11, 0x07, 0x13, 0x6d, 0xd6, 0xf0, 0x53, 0x95, 0xd8,
+  0x72, 0x1c, 0x64, 0xa0, 0x00, 0xa7, 0x66, 0x40, 0x53, 0xb1, 0xb7, 0xea,
+  0x7d, 0x9e, 0x76, 0xf5, 0xeb, 0x51, 0x4f, 0xd5, 0x4c, 0xb6, 0x2c, 0x9f,
+  0x1d, 0xbf, 0xa4, 0xaa, 0xc7, 0x7d, 0xb6, 0x5c, 0xf4, 0x36, 0x44, 0x59,
+  0x48, 0x70, 0x81, 0xeb, 0x09, 0x24, 0x8a, 0x96, 0xd5, 0x2e, 0x5f, 0xf0,
+  0x2c, 0x2a, 0xfc, 0xb5, 0x39, 0x77, 0xc5, 0xad, 0x12, 0xde, 0x57, 0x7b,
+  0xca, 0x8a, 0x80, 0xef, 0xd4, 0xb0, 0x02, 0x87, 0xd4, 0x68, 0x09, 0xc9,
+  0x31, 0x22, 0x49, 0x1f, 0xce, 0x62, 0x30, 0xf8, 0xff, 0x00, 0x68, 0xd8,
+  0x57, 0xdb, 0x51, 0xee, 0xe3, 0x36, 0x07, 0xb7, 0xcf, 0x69, 0x8c, 0x3e,
+  0x6a, 0x79, 0x7e, 0xca, 0x5b, 0x5f, 0x0b, 0xac, 0x6c, 0x21, 0x2d, 0xd9,
+  0x6f, 0x59, 0x55, 0x91, 0x29, 0xee, 0x4c, 0x2b, 0xe4, 0x8e, 0x41, 0xff,
+  0x00, 0x03, 0x8a, 0x5a, 0x7f, 0xc2, 0xa1, 0x32, 0xf0, 0x30, 0xb8, 0x61,
+  0xdb, 0x9f, 0x1c, 0xa6, 0xd9, 0x5a, 0xd7, 0x98, 0x2e, 0xc8, 0x82, 0xea,
+  0x97, 0xec, 0x05, 0xa4, 0xa9, 0x5f, 0x56, 0xeb, 0x1a, 0x96, 0xd4, 0x6a,
+  0x78, 0xe0, 0x9f, 0xc5, 0x26, 0x46, 0x10, 0xee, 0xac, 0x37, 0x1b, 0x27,
+  0xad, 0xb0, 0x7d, 0x4f, 0x38, 0x3f, 0xfe, 0xd5, 0x94, 0x61, 0xf8, 0xda,
+  0x4f, 0x4b, 0x62, 0x4f, 0xb5, 0xd5, 0x9f, 0xb5, 0x55, 0x4e, 0x5a, 0xb8,
+  0x99, 0x16, 0x74, 0xd1, 0x16, 0x0f, 0xe1, 0x11, 0x8b, 0x29, 0xd3, 0xf0,
+  0x53, 0x70, 0xb0, 0x25, 0x90, 0xaf, 0x62, 0x94, 0xeb, 0x60, 0xfd, 0x54,
+  0xfd, 0x0a, 0xdb, 0xc4, 0xc9, 0xb1, 0xd1, 0x26, 0x1f, 0x12, 0x31, 0xb9,
+  0x0c, 0x2c, 0x6d, 0x0e, 0x35, 0x8f, 0x73, 0x21, 0x43, 0xd2, 0x08, 0x93,
+  0xa3, 0x58, 0x7f, 0x4e, 0xb3, 0xff, 0x00, 0xaa, 0x3f, 0xf9, 0x5f, 0xc0,
+  0xd2, 0xbc, 0x87, 0x06, 0x31, 0xeb, 0x13, 0x3d, 0x5b, 0xb4, 0xc4, 0xd8,
+  0xf1, 0x53, 0x41, 0x5f, 0x6e, 0xea, 0x41, 0x96, 0x9a, 0x65, 0x1c, 0xac,
+  0xb4, 0xdb, 0x49, 0xf4, 0x21, 0x3a, 0x14, 0x88, 0x31, 0xae, 0x26, 0x39,
+  0xf9, 0x7e, 0x27, 0xc5, 0x6f, 0xff, 0x00, 0xc7, 0xc7, 0x1a, 0x4e, 0xbf,
+  0xe7, 0x71, 0x75, 0xb5, 0x58, 0x3e, 0x41, 0x2d, 0xbe, 0x5b, 0xa7, 0x13,
+  0xb2, 0x97, 0x7f, 0xfc, 0x36, 0xe2, 0x45, 0x1f, 0xf4, 0x33, 0xbf, 0xf1,
+  0xae, 0x8a, 0x74, 0x29, 0xd3, 0xf0, 0x45, 0x2f, 0x82, 0x27, 0x08, 0x79,
+  0x27, 0xd5, 0x50, 0xf9, 0x56, 0x51, 0x60, 0xc5, 0xa1, 0x22, 0x66, 0x43,
+  0x75, 0x8d, 0x6f, 0x65, 0xc5, 0x72, 0x34, 0x5d, 0x57, 0x9c, 0xe2, 0xb5,
+  0xbe, 0x54, 0x24, 0x75, 0x51, 0xd7, 0x80, 0x04, 0xd2, 0x3d, 0x8e, 0xcc,
+  0xdd, 0x87, 0x8c, 0xf0, 0x6d, 0x71, 0x2f, 0x77, 0xe9, 0xe3, 0xf9, 0x3f,
+  0x26, 0x4c, 0xb1, 0x71, 0xb9, 0xbd, 0x27, 0x9b, 0x6f, 0xb0, 0x86, 0xcf,
+  0x2a, 0x89, 0x48, 0xf8, 0x2e, 0x6b, 0x40, 0x78, 0xd4, 0x8c, 0x12, 0x32,
+  0x6e, 0x31, 0xbf, 0x3d, 0xb0, 0x95, 0xdb, 0xb1, 0x58, 0x8b, 0x84, 0xdb,
+  0x9e, 0x06, 0x7c, 0x8e, 0x55, 0x3a, 0x12, 0x7c, 0x7b, 0x36, 0x92, 0xda,
+  0x4f, 0xa0, 0xba, 0x47, 0x78, 0xad, 0x41, 0xb1, 0x59, 0xf5, 0xd2, 0xea,
+  0x4a, 0x31, 0x0c, 0x22, 0xf5, 0x73, 0x04, 0x8e, 0x59, 0x77, 0x04, 0x7b,
+  0x9b, 0x17, 0x94, 0xfe, 0x76, 0xde, 0x1d, 0xaa, 0x87, 0xcd, 0x6c, 0xd7,
+  0x93, 0x8a, 0xe6, 0x39, 0x01, 0xde, 0x5f, 0x96, 0x98, 0x90, 0xd4, 0x7c,
+  0xeb, 0x66, 0x3e, 0x95, 0x46, 0x42, 0x87, 0x5e, 0x8b, 0x90, 0xad, 0xbc,
+  0xa0, 0x47, 0x7f, 0x2f, 0x67, 0xec, 0xa7, 0xd0, 0x01, 0x1e, 0x04, 0x1f,
+  0x55, 0x67, 0x42, 0x80, 0x8a, 0xc6, 0x71, 0xdb, 0x1e, 0x37, 0x6d, 0x16,
+  0xfb, 0x0d, 0xae, 0x35, 0xba, 0x30, 0x3c, 0xca, 0x43, 0x28, 0xd7, 0x3a,
+  0xbc, 0x54, 0xa3, 0xde, 0xa5, 0x1f, 0x15, 0x12, 0x49, 0xf4, 0xd4, 0xae,
+  0xba, 0x6a, 0x8a, 0x28, 0x02, 0x8a, 0x28, 0xa0, 0x11, 0x38, 0xcb, 0xf1,
+  0x2c, 0x5f, 0xf6, 0xaa, 0xd9, 0xf7, 0xe2, 0x9e, 0xe9, 0x13, 0x8c, 0xbf,
+  0x12, 0xc5, 0xff, 0x00, 0x6a, 0xad, 0x9f, 0x7e, 0x29, 0xee, 0x80, 0xc1,
+  0xef, 0xdd, 0x14, 0x1a, 0x2a, 0x51, 0x56, 0xcc, 0xd2, 0x67, 0x1c, 0x7e,
+  0x47, 0xb2, 0xef, 0xa2, 0x24, 0x7f, 0x01, 0xa7, 0x3a, 0x4c, 0xe3, 0x8f,
+  0xc8, 0xf6, 0x5d, 0xf4, 0x44, 0x8f, 0xe0, 0x35, 0x05, 0x86, 0xf8, 0xdf,
+  0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x56, 0xb8, 0xdf, 0x17, 0x6f, 0xe6,
+  0x0f, 0xb2, 0xb6, 0x50, 0x05, 0x14, 0x56, 0x09, 0x3b, 0xee, 0xa0, 0x33,
+  0x58, 0x2a, 0xd7, 0x7d, 0x28, 0xe7, 0x3c, 0x48, 0xc3, 0xf0, 0xd7, 0x51,
+  0x16, 0xf5, 0x77, 0x47, 0xba, 0x2e, 0xfe, 0x42, 0xdb, 0x15, 0xb5, 0x48,
+  0x98, 0xf1, 0xf0, 0x09, 0x65, 0xb0, 0x56, 0x77, 0xd3, 0xa9, 0x00, 0x7a,
+  0xe9, 0x64, 0xe4, 0x1c, 0x56, 0xcc, 0x55, 0xc9, 0x8c, 0xe3, 0x4c, 0xe1,
+  0x16, 0xc5, 0x74, 0xf7, 0x4f, 0x21, 0x48, 0x7a, 0x62, 0x87, 0xfb, 0x38,
+  0x8d, 0xab, 0x49, 0x3f, 0xef, 0x56, 0x3d, 0x94, 0x05, 0x8d, 0x7d, 0xbd,
+  0x5a, 0x6c, 0x36, 0xc7, 0x6e, 0x77, 0xbb, 0x94, 0x4b, 0x6c, 0x26, 0x46,
+  0xdc, 0x91, 0x29, 0xd4, 0xb6, 0x84, 0xff, 0x00, 0xc4, 0xa2, 0x05, 0x57,
+  0x6b, 0xe2, 0xe4, 0x8b, 0xfa, 0x8b, 0x3c, 0x34, 0xc2, 0xaf, 0x19, 0x60,
+  0x3b, 0xd5, 0xc5, 0xd1, 0xee, 0x7d, 0xb8, 0x6b, 0xd0, 0xfb, 0xc3, 0x6b,
+  0xeb, 0xfa, 0x09, 0x57, 0xb6, 0xba, 0xac, 0x7c, 0x1d, 0xc7, 0xd3, 0x76,
+  0x66, 0xff, 0x00, 0x97, 0xcf, 0xb8, 0x66, 0xb7, 0xc6, 0xba, 0xb7, 0x2a,
+  0xf2, 0xb0, 0xb6, 0x59, 0x3f, 0xec, 0xa3, 0xa4, 0x06, 0x9b, 0x1f, 0xf0,
+  0x93, 0xeb, 0xab, 0x19, 0x29, 0x4a, 0x3c, 0xd4, 0x80, 0x00, 0x1d, 0x00,
+  0x1d, 0x05, 0x01, 0x56, 0x1c, 0x3b, 0x89, 0xb9, 0x67, 0xfa, 0xeb, 0x9d,
+  0x33, 0x62, 0x80, 0xb1, 0xe7, 0xdb, 0x31, 0x56, 0x94, 0xd2, 0xd4, 0x35,
+  0xf0, 0x57, 0x2d, 0xcd, 0xb9, 0xed, 0xe4, 0x4a, 0x37, 0x4c, 0x18, 0x8f,
+  0x0a, 0x38, 0x77, 0x8b, 0xc8, 0x13, 0x2d, 0x38, 0xa5, 0xbc, 0x4e, 0xef,
+  0x33, 0x64, 0xa4, 0xc9, 0x90, 0x4f, 0xa4, 0xba, 0xe9, 0x52, 0xf7, 0xf5,
+  0xd3, 0xa8, 0x03, 0x54, 0x6f, 0xc3, 0x54, 0x07, 0x0d, 0xda, 0xc9, 0x67,
+  0xbb, 0xb1, 0xe4, 0xf7, 0x6b, 0x54, 0x1b, 0x83, 0x3a, 0xd7, 0x67, 0x2a,
+  0x3a, 0x1d, 0x4e, 0xbd, 0x1a, 0x50, 0x22, 0xaa, 0x9c, 0xb3, 0x0d, 0x77,
+  0x86, 0x12, 0x3f, 0x96, 0xdc, 0x31, 0xb7, 0x3e, 0xd4, 0x16, 0x17, 0xcf,
+  0x7d, 0xc6, 0xe2, 0x28, 0xf9, 0x3c, 0xd8, 0xff, 0x00, 0x9e, 0xeb, 0x2d,
+  0x1e, 0x88, 0x7d, 0x03, 0xa8, 0xe5, 0xd0, 0x50, 0x04, 0x6b, 0x75, 0x70,
+  0xbc, 0xf3, 0x6c, 0xb4, 0xb7, 0x5d, 0x71, 0x08, 0x6d, 0x00, 0x95, 0x29,
+  0x6a, 0xd0, 0x48, 0x1e, 0x24, 0xf8, 0x57, 0x05, 0x9a, 0xf9, 0x65, 0xbd,
+  0xa1, 0xc7, 0xac, 0xd7, 0x68, 0x17, 0x24, 0x34, 0xa0, 0x97, 0x15, 0x16,
+  0x4a, 0x1d, 0x4a, 0x0f, 0xa0, 0xf2, 0x93, 0xa3, 0x40, 0x18, 0xcd, 0xf2,
+  0xd7, 0x91, 0xe3, 0xf0, 0x6f, 0xb6, 0x59, 0xad, 0xcc, 0xb7, 0x4d, 0x64,
+  0x3c, 0xc3, 0xe8, 0xee, 0x52, 0x4f, 0xd8, 0x7c, 0x08, 0x3d, 0xc4, 0x1a,
+  0x90, 0xd9, 0x1b, 0xd8, 0xaa, 0x93, 0x07, 0xe5, 0xe1, 0xd7, 0x16, 0xae,
+  0x58, 0x33, 0xde, 0xf3, 0x60, 0xc9, 0x9c, 0x76, 0xed, 0x8f, 0x1e, 0xe4,
+  0x35, 0x23, 0xbe, 0x54, 0x51, 0xd3, 0x43, 0xaf, 0xbe, 0xa4, 0x0f, 0x05,
+  0x2b, 0xd1, 0x56, 0x85, 0xf2, 0x1b, 0xd7, 0x1b, 0x34, 0xeb, 0x7c, 0x79,
+  0x8e, 0xc2, 0x7a, 0x4c, 0x77, 0x19, 0x44, 0x96, 0xc6, 0xd6, 0xca, 0x94,
+  0x92, 0x02, 0xc0, 0xf4, 0x8d, 0xef, 0xea, 0xa0, 0x29, 0xd8, 0x99, 0x2d,
+  0xc2, 0xe5, 0x95, 0xe4, 0x17, 0x1c, 0x6c, 0xb7, 0x2a, 0xfb, 0x90, 0x3a,
+  0x9b, 0x6d, 0x88, 0x2c, 0x05, 0xb7, 0x0e, 0xdf, 0x14, 0xad, 0x0e, 0x4e,
+  0x70, 0x8e, 0xe6, 0x8b, 0xca, 0x78, 0xa4, 0x7f, 0x48, 0x42, 0x12, 0x37,
+  0xbd, 0x8b, 0x5f, 0x0d, 0xc7, 0x60, 0xe3, 0x18, 0xe4, 0x5b, 0x34, 0x12,
+  0xb5, 0xa1, 0x90, 0x54, 0xeb, 0xce, 0x1d, 0xb8, 0xfb, 0xaa, 0x3c, 0xce,
+  0x3a, 0xb3, 0xe2, 0xb5, 0x28, 0x95, 0x13, 0xe9, 0x3e, 0x8d, 0x0a, 0x89,
+  0xe1, 0x6e, 0x01, 0x69, 0xc0, 0xac, 0x29, 0x83, 0x0d, 0xc7, 0x26, 0x4d,
+  0x75, 0x0d, 0x89, 0x93, 0xde, 0xfc, 0xa4, 0x82, 0x84, 0xf2, 0xa0, 0x7a,
+  0x12, 0x84, 0x8e, 0x89, 0x40, 0xe8, 0x3a, 0x9e, 0xa4, 0x92, 0x5b, 0xc7,
+  0x41, 0x40, 0x14, 0x51, 0x45, 0x00, 0x51, 0x45, 0x14, 0x01, 0x45, 0x14,
+  0x50, 0x08, 0x9c, 0x65, 0xf8, 0x96, 0x2f, 0xfb, 0x55, 0x6c, 0xfb, 0xf1,
+  0x4f, 0x74, 0x89, 0xc6, 0x5f, 0x89, 0x62, 0xff, 0x00, 0xb5, 0x56, 0xcf,
+  0xbf, 0x14, 0xf7, 0x40, 0x79, 0x51, 0xeb, 0x45, 0x64, 0x8d, 0x9e, 0xf3,
+  0x45, 0x0a, 0xb4, 0xf2, 0x66, 0x93, 0x38, 0xe3, 0xf2, 0x3d, 0x97, 0x7d,
+  0x11, 0x23, 0xf8, 0x0d, 0x39, 0xd2, 0x67, 0x1c, 0x7e, 0x47, 0xb2, 0xef,
+  0xa2, 0x24, 0x7f, 0x01, 0xa1, 0x61, 0xbe, 0x37, 0xc5, 0xdb, 0xf9, 0x83,
+  0xec, 0xaf, 0x64, 0xfb, 0x2a, 0x2e, 0xf5, 0x7b, 0xb5, 0xe3, 0xb8, 0xeb,
+  0xd7, 0x9b, 0xd4, 0xe6, 0x60, 0xdb, 0xe2, 0x32, 0x1c, 0x7d, 0xf7, 0x4e,
+  0x92, 0x81, 0xd0, 0x0f, 0x59, 0x24, 0x90, 0x00, 0x1d, 0x49, 0x20, 0x0d,
+  0x93, 0x55, 0xea, 0xa6, 0x71, 0x03, 0x89, 0x40, 0xa2, 0xd6, 0x64, 0x60,
+  0x98, 0xaa, 0xf5, 0xb9, 0x6f, 0x37, 0xfe, 0x98, 0x98, 0x8f, 0x1e, 0xcd,
+  0xb3, 0xd2, 0x32, 0x4f, 0x82, 0x95, 0xb5, 0xeb, 0x44, 0x04, 0xee, 0x80,
+  0x60, 0xce, 0xb8, 0x9d, 0x8d, 0x62, 0x93, 0x5b, 0xb5, 0x28, 0xca, 0xbc,
+  0xdf, 0x9e, 0xd8, 0x62, 0xcb, 0x69, 0x6b, 0xca, 0x66, 0xb9, 0xeb, 0x28,
+  0x07, 0xcc, 0x4f, 0xeb, 0x2c, 0xa4, 0x7a, 0xfa, 0x54, 0x0f, 0xb9, 0x5c,
+  0x5b, 0xcd, 0x00, 0x55, 0xea, 0xf1, 0x13, 0x01, 0xb4, 0x3a, 0x36, 0x61,
+  0x5a, 0x08, 0x93, 0x72, 0x52, 0x4f, 0xe6, 0xb9, 0x21, 0x63, 0x91, 0xa5,
+  0x6b, 0xc5, 0xb4, 0xa8, 0x8d, 0xfc, 0x2a, 0x73, 0xc1, 0xf0, 0xac, 0x5f,
+  0x0c, 0xb7, 0x18, 0x98, 0xe5, 0xa1, 0x88, 0x7d, 0xa7, 0x57, 0xdf, 0xd7,
+  0x33, 0xf2, 0x15, 0xbd, 0x95, 0x3a, 0xe9, 0xda, 0xdc, 0x56, 0xc9, 0xea,
+  0xa2, 0x69, 0x87, 0x42, 0x80, 0x56, 0xc1, 0xb0, 0x0c, 0x4f, 0x0c, 0x69,
+  0xc3, 0x60, 0xb4, 0x32, 0xcc, 0xb7, 0xb6, 0x64, 0x4d, 0x74, 0x97, 0x65,
+  0x48, 0x51, 0xea, 0x4b, 0x8f, 0x2b, 0x6b, 0x56, 0xcf, 0xa4, 0xeb, 0xd0,
+  0x05, 0x77, 0xe5, 0xf9, 0x56, 0x3b, 0x88, 0xda, 0xcd, 0xcf, 0x24, 0xbc,
+  0x44, 0xb6, 0x45, 0xdf, 0x2a, 0x56, 0xf2, 0xf4, 0xa7, 0x15, 0xfa, 0x28,
+  0x48, 0xf3, 0x96, 0xaf, 0xd5, 0x48, 0x24, 0xfa, 0x2b, 0xb2, 0xf0, 0xdd,
+  0xcd, 0xd4, 0x47, 0x4d, 0xae, 0x54, 0x78, 0xea, 0x12, 0x5b, 0x53, 0xe5,
+  0xe6, 0x4b, 0x9c, 0xcc, 0x83, 0xe7, 0xa5, 0x3a, 0x50, 0xd2, 0x88, 0xee,
+  0x27, 0x60, 0x7a, 0x0d, 0x7b, 0x93, 0x6f, 0x81, 0x2e, 0x5c, 0x69, 0x72,
+  0xa0, 0xc6, 0x7a, 0x4c, 0x55, 0x15, 0x47, 0x75, 0xc6, 0x92, 0xa5, 0xb2,
+  0x4f, 0x42, 0x52, 0x48, 0xda, 0x77, 0xea, 0xa0, 0x12, 0x71, 0x9c, 0xdf,
+  0x27, 0xcb, 0x2f, 0xd1, 0x95, 0x63, 0xc3, 0x26, 0x5b, 0xf1, 0x94, 0xa8,
+  0x99, 0x17, 0x4b, 0xde, 0xe3, 0x3b, 0x21, 0x3a, 0xe8, 0x23, 0xc7, 0xf8,
+  0x7d, 0x49, 0x07, 0x99, 0xce, 0x51, 0xaf, 0x0a, 0x71, 0x9b, 0x69, 0x89,
+  0x32, 0xed, 0x6f, 0xbb, 0x3c, 0x5f, 0x12, 0x60, 0x07, 0x7b, 0x00, 0x87,
+  0x96, 0x94, 0x7b, 0xe2, 0x42, 0x54, 0x54, 0x90, 0x74, 0xae, 0x83, 0xa7,
+  0x30, 0x3a, 0xeb, 0x50, 0x39, 0x7f, 0x11, 0x71, 0x1c, 0x5e, 0x4f, 0x90,
+  0x4e, 0xb9, 0xf9, 0x4d, 0xd5, 0x63, 0x6d, 0xdb, 0x20, 0xb6, 0x64, 0xcc,
+  0x70, 0xeb, 0x63, 0x4d, 0x23, 0x6a, 0x03, 0xf5, 0x95, 0xa4, 0xfa, 0xe9,
+  0x32, 0xe3, 0x96, 0x71, 0x13, 0x26, 0xda, 0x2d, 0xb1, 0xa3, 0x61, 0x56,
+  0xe5, 0x7f, 0x4d, 0x24, 0x22, 0x65, 0xc5, 0x43, 0xd4, 0xd8, 0x3d, 0x93,
+  0x47, 0xe7, 0x17, 0x08, 0xf4, 0x78, 0x55, 0xe1, 0x4e, 0x53, 0xf0, 0xa2,
+  0x93, 0xa9, 0x18, 0x78, 0x99, 0x67, 0x64, 0x79, 0x05, 0x8f, 0x1a, 0xb5,
+  0xae, 0xe5, 0x7f, 0xba, 0xc2, 0xb5, 0x42, 0x6f, 0xbd, 0xe9, 0x6f, 0xa5,
+  0xb4, 0x7b, 0x01, 0x27, 0xa9, 0xf5, 0x0e, 0xb5, 0x40, 0x66, 0x9f, 0x85,
+  0x35, 0xad, 0x4d, 0xb8, 0xd6, 0x01, 0x66, 0x55, 0xdf, 0x5c, 0xc9, 0xf7,
+  0x42, 0x66, 0xda, 0x8e, 0x08, 0x3a, 0x25, 0x28, 0x1e, 0x7a, 0x87, 0xb7,
+  0x93, 0xeb, 0x15, 0x3a, 0xce, 0x03, 0x89, 0xcc, 0xf2, 0xa1, 0x94, 0x44,
+  0x93, 0x92, 0xbb, 0x3a, 0x3a, 0xa3, 0xc9, 0x9d, 0x75, 0x78, 0xc8, 0x92,
+  0x94, 0x2b, 0xc5, 0xb5, 0x2b, 0xa3, 0x5a, 0xef, 0x01, 0x01, 0x35, 0xf2,
+  0xb7, 0x10, 0x30, 0xeb, 0xcf, 0xe0, 0xff, 0x00, 0xc4, 0x98, 0xee, 0xa5,
+  0x5e, 0xe9, 0x62, 0xd7, 0x25, 0x15, 0x42, 0x98, 0xa6, 0xd2, 0xa2, 0xe3,
+  0x40, 0x8e, 0x61, 0xd4, 0x69, 0x0f, 0xa0, 0x11, 0xd4, 0x68, 0xf5, 0x04,
+  0x6b, 0x7d, 0x34, 0x9d, 0x19, 0x53, 0x6b, 0x51, 0x48, 0x56, 0x55, 0x13,
+  0xd2, 0x36, 0xe4, 0x57, 0x2c, 0xeb, 0x88, 0x6e, 0x89, 0x19, 0x9d, 0xfe,
+  0x6c, 0x88, 0x0b, 0x21, 0x4d, 0xc0, 0x1e, 0xf1, 0x11, 0x43, 0x7f, 0x9a,
+  0xd2, 0x01, 0x2e, 0xfb, 0x40, 0x77, 0x5e, 0x24, 0x77, 0xd3, 0x9e, 0x26,
+  0xfc, 0xdc, 0x32, 0x74, 0x5c, 0xb6, 0xd7, 0xda, 0x49, 0x55, 0x95, 0xb0,
+  0x6e, 0x6d, 0x34, 0x94, 0xa4, 0x3d, 0x6d, 0xd0, 0x4b, 0x88, 0x3a, 0x51,
+  0x0a, 0x28, 0x00, 0x2d, 0x03, 0x99, 0x44, 0x14, 0x7c, 0x14, 0x6e, 0xba,
+  0x20, 0x45, 0x81, 0x21, 0xbf, 0x2d, 0x66, 0x42, 0x66, 0x25, 0xd4, 0x25,
+  0xe5, 0x3c, 0x09, 0x29, 0x29, 0x50, 0x04, 0x29, 0x44, 0xe8, 0x9e, 0x84,
+  0x69, 0x4b, 0xec, 0xfe, 0x79, 0xa6, 0x2b, 0x25, 0xb8, 0xb8, 0xa6, 0xa4,
+  0x06, 0x10, 0x88, 0xa1, 0xc4, 0xee, 0x43, 0x9c, 0x9c, 0xbd, 0x7f, 0x45,
+  0x4a, 0x1c, 0xbc, 0xde, 0xb4, 0x25, 0x64, 0xef, 0xf2, 0x86, 0xb7, 0x8d,
+  0x14, 0xd6, 0x0e, 0x79, 0x56, 0x79, 0xc9, 0x6c, 0x71, 0x5b, 0x19, 0x6f,
+  0x3f, 0xe1, 0xfb, 0x4e, 0xd8, 0xa6, 0x36, 0x9b, 0xa4, 0x62, 0xdd, 0xdb,
+  0x1f, 0x9e, 0xda, 0xb6, 0x1b, 0x92, 0x81, 0xce, 0xd2, 0xc2, 0xbf, 0x41,
+  0x40, 0xf2, 0x9f, 0x4a, 0x56, 0x6a, 0x53, 0x85, 0x99, 0x6b, 0x19, 0xce,
+  0x05, 0x6b, 0xc9, 0x1a, 0x6b, 0xb0, 0x72, 0x4b, 0x5c, 0xb2, 0xa3, 0x9e,
+  0xf6, 0x24, 0x20, 0x94, 0x3a, 0xd9, 0x1f, 0xaa, 0xb4, 0xa8, 0x75, 0xf0,
+  0xd1, 0xf1, 0xa4, 0xee, 0x09, 0x5c, 0x06, 0x3f, 0x73, 0x9b, 0xc3, 0x49,
+  0x4e, 0x28, 0xb1, 0x15, 0x06, 0x75, 0x85, 0x6b, 0x3d, 0x5c, 0x84, 0xa5,
+  0x79, 0xcc, 0xef, 0xc4, 0xb2, 0xe1, 0xd7, 0x7f, 0xc0, 0x52, 0x3d, 0x15,
+  0xaa, 0x12, 0x87, 0x0d, 0x78, 0xd8, 0xfc, 0x27, 0x13, 0xd9, 0xe3, 0x19,
+  0xe4, 0x8e, 0xda, 0x2a, 0x87, 0xc0, 0x8b, 0x76, 0x08, 0xf7, 0xc4, 0x1f,
+  0x40, 0x7d, 0x29, 0xe6, 0x1f, 0xac, 0x92, 0x3c, 0x6b, 0x8e, 0x51, 0x71,
+  0x78, 0x67, 0x64, 0x64, 0xa4, 0xb2, 0x8b, 0x7c, 0x74, 0x14, 0x56, 0x12,
+  0x76, 0x90, 0x6b, 0x35, 0x52, 0xc1, 0x45, 0x14, 0x50, 0x05, 0x14, 0x51,
+  0x40, 0x1d, 0x68, 0xa2, 0x8a, 0x01, 0x13, 0x8c, 0xbf, 0x12, 0xc5, 0xff,
+  0x00, 0x6a, 0xad, 0x9f, 0x7e, 0x29, 0xee, 0x91, 0x38, 0xcb, 0xf1, 0x2c,
+  0x5f, 0xf6, 0xaa, 0xd9, 0xf7, 0xe2, 0x9e, 0xe8, 0x02, 0x8a, 0xf2, 0xa2,
+  0x41, 0xe8, 0x07, 0xd6, 0x75, 0x45, 0x01, 0xea, 0x93, 0x38, 0xe3, 0xbf,
+  0xc4, 0xfe, 0x5c, 0x3f, 0xf4, 0x89, 0x1a, 0xff, 0x00, 0x90, 0xd3, 0x9d,
+  0x26, 0x71, 0xc7, 0xe4, 0x7b, 0x2e, 0xfa, 0x22, 0x47, 0xf0, 0x1a, 0x02,
+  0xbe, 0x9f, 0x7f, 0x63, 0x27, 0xe2, 0x52, 0xfd, 0xd2, 0x61, 0x4f, 0xdb,
+  0xac, 0x37, 0x37, 0x2d, 0xb6, 0x78, 0xab, 0xd7, 0x66, 0x67, 0x30, 0xca,
+  0x5c, 0x7e, 0x63, 0xa9, 0x3d, 0xe5, 0x1c, 0xe8, 0x43, 0x60, 0xef, 0x44,
+  0x95, 0x0e, 0xa7, 0xa5, 0xdb, 0x05, 0x96, 0xd9, 0x8a, 0x84, 0xa0, 0xa8,
+  0x82, 0x36, 0x54, 0x7b, 0xd4, 0x4f, 0x79, 0x3e, 0xb3, 0x5f, 0x38, 0x71,
+  0x36, 0x1c, 0xcc, 0x3f, 0x8d, 0xb6, 0xf9, 0x69, 0x98, 0xd4, 0x7b, 0x3e,
+  0x50, 0xfa, 0x6e, 0x2c, 0xad, 0xf0, 0x7b, 0x36, 0x67, 0x32, 0xcf, 0x65,
+  0x25, 0xae, 0x80, 0xeb, 0xb6, 0x60, 0x82, 0x0e, 0xba, 0xb8, 0xda, 0x47,
+  0xa6, 0xaf, 0x5c, 0x16, 0xf0, 0xc5, 0xdf, 0x1f, 0x8c, 0xf3, 0x0f, 0x07,
+  0x51, 0xd9, 0x25, 0x6d, 0xab, 0x44, 0x15, 0x36, 0xa1, 0xb4, 0xab, 0x47,
+  0xaf, 0x71, 0xf1, 0xeb, 0x5a, 0xe3, 0x34, 0xf2, 0xba, 0x33, 0x27, 0x2c,
+  0x54, 0xc3, 0xea, 0x86, 0x02, 0x75, 0xe1, 0xd2, 0xbc, 0xb8, 0xe2, 0x5b,
+  0x6d, 0x4b, 0x71, 0x49, 0x42, 0x52, 0x36, 0xa2, 0x4e, 0x80, 0x1e, 0x93,
+  0x54, 0x1f, 0x1c, 0x7f, 0x08, 0x85, 0x61, 0xb9, 0x14, 0x9c, 0x4f, 0x14,
+  0xc5, 0x9f, 0xbe, 0x5e, 0x59, 0x21, 0xb7, 0x64, 0x3c, 0x4a, 0x22, 0xb4,
+  0xb2, 0x90, 0xae, 0x5f, 0x37, 0x6a, 0x70, 0x80, 0x46, 0xc0, 0xe5, 0x03,
+  0x7a, 0xdf, 0x7d, 0x7c, 0x77, 0xc6, 0xee, 0x29, 0x71, 0x47, 0x29, 0xbb,
+  0x48, 0xb4, 0xe6, 0x17, 0xf9, 0x09, 0x8e, 0x9d, 0x1f, 0x20, 0x8b, 0xef,
+  0x51, 0x8a, 0x48, 0xd8, 0xf3, 0x52, 0x7c, 0xee, 0x84, 0x7c, 0x22, 0xa2,
+  0x3b, 0xab, 0x34, 0x8d, 0x32, 0x8f, 0xbe, 0xaf, 0x3c, 0x60, 0xc7, 0x3c,
+  0xb6, 0x45, 0xaf, 0x11, 0x62, 0x46, 0x63, 0x75, 0x60, 0xf2, 0xbc, 0xd5,
+  0xad, 0x49, 0x31, 0xd8, 0x57, 0x87, 0x6b, 0x21, 0x47, 0xb3, 0x47, 0x71,
+  0xe8, 0x0a, 0x95, 0xea, 0xa5, 0x6b, 0xa3, 0xb9, 0xb6, 0x44, 0xdb, 0xb2,
+  0x32, 0xec, 0x95, 0x18, 0xfd, 0xaf, 0xbc, 0xdb, 0xac, 0x8e, 0x96, 0x7c,
+  0xcf, 0x43, 0xd2, 0xd4, 0x03, 0x87, 0xbf, 0x44, 0x36, 0x10, 0x3d, 0xb5,
+  0xf3, 0x77, 0xe0, 0x29, 0x74, 0x4b, 0x79, 0x16, 0x4b, 0x66, 0x5b, 0x89,
+  0xdc, 0x88, 0x8d, 0x49, 0x42, 0x09, 0xe8, 0x7b, 0x35, 0x94, 0x9e, 0x9f,
+  0xff, 0x00, 0x20, 0xfe, 0xea, 0xfa, 0x1b, 0x89, 0x39, 0x26, 0x3f, 0x89,
+  0xdb, 0x5b, 0xbc, 0xde, 0xd2, 0xec, 0xb7, 0xb9, 0xbb, 0x2b, 0x7c, 0x06,
+  0x93, 0xda, 0x3b, 0x25, 0xef, 0x00, 0xdb, 0x7e, 0x2a, 0xfd, 0x63, 0xdd,
+  0xea, 0xf1, 0xee, 0xa1, 0x46, 0x1a, 0x35, 0xb3, 0x8a, 0xbd, 0x59, 0xeb,
+  0xd0, 0x89, 0x1c, 0x42, 0xdd, 0x8e, 0xdb, 0x61, 0x29, 0xac, 0x72, 0xdc,
+  0xcc, 0x46, 0x15, 0xd5, 0x6b, 0x6d, 0x82, 0x92, 0xf1, 0xfd, 0x25, 0x2c,
+  0x8d, 0xb8, 0x77, 0xe2, 0x49, 0xf6, 0xd4, 0xd8, 0xef, 0xdf, 0xd5, 0xeb,
+  0xff, 0x00, 0xdf, 0xfe, 0xfa, 0xd5, 0x28, 0xde, 0x47, 0xc7, 0x4b, 0xc5,
+  0xd1, 0x0b, 0x6e, 0x0e, 0x2f, 0x8c, 0x32, 0xe8, 0xe7, 0x8f, 0x6d, 0x98,
+  0xdb, 0xb3, 0x26, 0x2d, 0x1e, 0x1c, 0xc8, 0x68, 0x29, 0x43, 0xfb, 0x93,
+  0x56, 0x74, 0x1b, 0xe2, 0xd9, 0x87, 0x1e, 0x3d, 0xd1, 0xb7, 0x5c, 0xbd,
+  0xa5, 0x09, 0x12, 0x22, 0xc7, 0x86, 0xeb, 0x6a, 0xe7, 0x00, 0x15, 0x28,
+  0x21, 0xcd, 0x29, 0x0d, 0xf5, 0xd8, 0x52, 0xb4, 0x3c, 0x37, 0xba, 0xea,
+  0x85, 0x58, 0xbd, 0x8e, 0x49, 0xd3, 0x97, 0x2c, 0x52, 0xce, 0xf8, 0x83,
+  0x73, 0x4d, 0xe9, 0x78, 0xa6, 0x05, 0x6f, 0x66, 0xe7, 0x7b, 0x6d, 0xc0,
+  0xdc, 0xb9, 0x92, 0x12, 0x7c, 0x92, 0x0a, 0x94, 0x36, 0x12, 0x79, 0x7c,
+  0xe7, 0x5d, 0xd7, 0x5e, 0xcd, 0x20, 0x91, 0xe3, 0xdc, 0x45, 0x42, 0x71,
+  0x1f, 0x0c, 0xcd, 0xee, 0xdc, 0x10, 0xc9, 0x23, 0x66, 0xf7, 0x0b, 0xcd,
+  0xde, 0x40, 0x69, 0x12, 0xed, 0xe5, 0x56, 0xb6, 0x23, 0xc5, 0x86, 0xf3,
+  0x67, 0x98, 0x94, 0x84, 0x92, 0xf0, 0x0a, 0x4f, 0x32, 0x36, 0xa0, 0x07,
+  0x9d, 0xb2, 0x07, 0x78, 0xb5, 0xb8, 0x67, 0x62, 0xf2, 0x0c, 0x4a, 0xf6,
+  0xee, 0x2b, 0x6b, 0x89, 0x03, 0x23, 0x5d, 0xc5, 0xe6, 0x82, 0xa7, 0x28,
+  0x2c, 0x47, 0x0b, 0x58, 0x57, 0x3a, 0xb4, 0x4f, 0x36, 0xd2, 0xb0, 0xb3,
+  0xa2, 0x79, 0x95, 0xa0, 0x4e, 0x80, 0xd4, 0x8e, 0x2f, 0x8d, 0xdc, 0x71,
+  0xbc, 0x22, 0xf5, 0x74, 0xcf, 0x6e, 0xfe, 0xe8, 0xdd, 0x5d, 0x8c, 0xff,
+  0x00, 0x96, 0x48, 0x12, 0xde, 0x71, 0x92, 0xc9, 0x4f, 0x41, 0xd9, 0xa8,
+  0x84, 0x03, 0xd0, 0x9f, 0x35, 0x09, 0xd7, 0x37, 0x28, 0xf4, 0x9f, 0x3a,
+  0xbd, 0x69, 0x4d, 0xb4, 0xcf, 0x46, 0x85, 0x18, 0xc1, 0x26, 0x8a, 0x43,
+  0xf0, 0x66, 0x4a, 0xae, 0x3c, 0x26, 0xb2, 0xc6, 0x90, 0x1b, 0x66, 0xec,
+  0xd0, 0x71, 0x71, 0x15, 0x29, 0xb5, 0x3a, 0x04, 0x60, 0xe9, 0x48, 0x75,
+  0xa4, 0x28, 0x84, 0x92, 0x0e, 0xd2, 0x48, 0xee, 0x29, 0xeb, 0xd7, 0xa5,
+  0x59, 0x4c, 0xdb, 0x2e, 0x2b, 0x9c, 0x5e, 0x4b, 0x49, 0x0e, 0x21, 0x5a,
+  0x33, 0xae, 0x0b, 0x12, 0x1e, 0x23, 0x7f, 0xd1, 0xb6, 0x9f, 0x31, 0x03,
+  0xbf, 0xd1, 0xf3, 0x69, 0x62, 0xdd, 0x65, 0x5e, 0x15, 0x87, 0x18, 0x32,
+  0x16, 0x96, 0xdd, 0xc7, 0x6e, 0x91, 0xee, 0xb1, 0x47, 0x2f, 0x9c, 0xcc,
+  0x19, 0xea, 0x4a, 0x1f, 0x6b, 0xe6, 0x85, 0xad, 0xcd, 0x81, 0xd3, 0x6d,
+  0x83, 0xe1, 0x56, 0x3a, 0x18, 0x6d, 0xb7, 0x9d, 0x71, 0x3c, 0xdc, 0xee,
+  0x1f, 0x3c, 0x95, 0x13, 0xdd, 0xd3, 0xa0, 0x3d, 0x00, 0xe9, 0xdc, 0x34,
+  0x2b, 0xb6, 0xdd, 0xeb, 0x8f, 0xc0, 0xe3, 0xb8, 0x5a, 0x65, 0xb7, 0x52,
+  0x07, 0x37, 0xb7, 0xdc, 0x9c, 0x89, 0x0a, 0xf9, 0x61, 0xda, 0xaf, 0xf6,
+  0x27, 0xbc, 0xb6, 0x07, 0x5d, 0x76, 0xe4, 0x27, 0x4e, 0xb0, 0xaf, 0xd5,
+  0x75, 0xbe, 0x64, 0x6b, 0xa6, 0x8f, 0x29, 0xf0, 0xa7, 0x3c, 0x9a, 0xdd,
+  0x67, 0xe2, 0xff, 0x00, 0x08, 0x35, 0x06, 0x49, 0x43, 0x57, 0x38, 0xc8,
+  0x97, 0x6e, 0x97, 0xdc, 0xe4, 0x49, 0x29, 0x3c, 0xcd, 0x2f, 0xd2, 0x95,
+  0x21, 0xc4, 0x80, 0x47, 0xa9, 0x42, 0xa3, 0x7c, 0x7f, 0xfd, 0xd4, 0x77,
+  0x0d, 0xa7, 0x7f, 0x24, 0x78, 0x83, 0x2f, 0x16, 0x78, 0xf2, 0xd9, 0xf2,
+  0x45, 0xb9, 0x3e, 0xd4, 0x4f, 0x44, 0xb3, 0x30, 0x0e, 0x69, 0x2c, 0x0f,
+  0x40, 0x58, 0xf7, 0xd4, 0x8e, 0x9d, 0x7b, 0x5a, 0xca, 0xf2, 0x96, 0x7b,
+  0xe8, 0xd2, 0xce, 0xa6, 0x3b, 0x8c, 0x6b, 0xe0, 0xce, 0x62, 0xfe, 0x5f,
+  0x86, 0x21, 0xeb, 0xa2, 0x11, 0x1e, 0xff, 0x00, 0x6d, 0x75, 0x76, 0xfb,
+  0xdc, 0x6d, 0xe8, 0xb1, 0x31, 0xa3, 0xca, 0xe7, 0x41, 0xf9, 0xaa, 0xe8,
+  0xb4, 0xfa, 0x42, 0x85, 0x3b, 0x8e, 0xea, 0xa7, 0xf3, 0x34, 0xa3, 0x86,
+  0xdc, 0x5d, 0x83, 0x9e, 0x35, 0xef, 0x58, 0xf6, 0x50, 0xb6, 0xad, 0x59,
+  0x10, 0x1d, 0x10, 0xc4, 0xae, 0xe8, 0x92, 0xc8, 0xde, 0x86, 0xff, 0x00,
+  0x24, 0xa3, 0xdc, 0x01, 0x49, 0xab, 0x80, 0x77, 0x77, 0x6a, 0xbc, 0xf3,
+  0xd0, 0x0a, 0x28, 0xa2, 0x80, 0x28, 0xa2, 0x8a, 0x00, 0xa2, 0x8a, 0x28,
+  0x04, 0x4e, 0x32, 0xfc, 0x4b, 0x17, 0xfd, 0xaa, 0xb6, 0x7d, 0xf8, 0xa7,
+  0xba, 0x44, 0xe3, 0x2f, 0xc4, 0xb1, 0x7f, 0xda, 0xab, 0x67, 0xdf, 0x8a,
+  0x7b, 0xa0, 0x30, 0x40, 0x3d, 0xe2, 0x8a, 0xcd, 0x15, 0x00, 0x29, 0x33,
+  0x8e, 0x3f, 0x23, 0xd9, 0x77, 0xd1, 0x12, 0x3f, 0x80, 0xd3, 0x9d, 0x26,
+  0x71, 0xc7, 0xe4, 0x7b, 0x2e, 0xfa, 0x22, 0x47, 0xf0, 0x1a, 0x90, 0x47,
+  0x71, 0xcf, 0x06, 0x56, 0x7d, 0xc3, 0x27, 0xed, 0x70, 0xdc, 0x2c, 0x5e,
+  0x22, 0xf6, 0x73, 0xad, 0x12, 0x12, 0x74, 0xa6, 0x65, 0xb5, 0xd5, 0xb2,
+  0x0f, 0x86, 0xfa, 0xa7, 0xfe, 0x2a, 0xae, 0xb8, 0x23, 0xc4, 0xc9, 0x37,
+  0x9b, 0xb3, 0x6f, 0xdd, 0x96, 0xb4, 0xc8, 0xb8, 0xb6, 0xb7, 0x54, 0xd2,
+  0xc6, 0xbb, 0x09, 0x0c, 0xf2, 0xb7, 0x36, 0x31, 0xf4, 0x14, 0x2f, 0x95,
+  0xd4, 0x83, 0xbf, 0x31, 0xe1, 0xd4, 0xf2, 0x93, 0x5f, 0x42, 0xc6, 0x1f,
+  0xcd, 0xdb, 0xf9, 0x83, 0xec, 0xaf, 0x97, 0x38, 0xd5, 0x8d, 0x3b, 0x85,
+  0x71, 0xa2, 0x2d, 0xda, 0xdc, 0x43, 0x16, 0xec, 0xb2, 0x5a, 0x24, 0x44,
+  0x70, 0xab, 0x95, 0xb8, 0xd7, 0xa6, 0xc1, 0x00, 0x2c, 0x9e, 0xe4, 0x48,
+  0x42, 0x94, 0xda, 0xba, 0x8e, 0xae, 0x15, 0x77, 0x23, 0x55, 0x7a, 0x72,
+  0xd2, 0xf7, 0xe0, 0xa5, 0x48, 0x6a, 0x5e, 0xa6, 0x38, 0xf7, 0x89, 0x7b,
+  0x93, 0xc4, 0x77, 0x6e, 0x03, 0xb4, 0x5c, 0x2c, 0x97, 0xdf, 0xe1, 0xba,
+  0x56, 0x02, 0x1a, 0x94, 0x84, 0xfb, 0xf3, 0x2a, 0x3a, 0x27, 0x4a, 0x4a,
+  0x52, 0xea, 0x7b, 0x81, 0xe5, 0x70, 0x78, 0x0a, 0xa0, 0xb8, 0xfb, 0x83,
+  0xad, 0x8b, 0x14, 0x3c, 0xa2, 0x31, 0x71, 0xd5, 0xb6, 0xbe, 0xc2, 0x52,
+  0x95, 0xe6, 0xf3, 0x20, 0x9f, 0x35, 0x69, 0x0a, 0xeb, 0xca, 0x15, 0xe6,
+  0x9e, 0xa7, 0x5d, 0x37, 0xaa, 0xfb, 0x3d, 0xf8, 0x70, 0xb8, 0xa5, 0xc2,
+  0xd5, 0xdb, 0x19, 0x77, 0xb1, 0x93, 0xca, 0x89, 0x76, 0xc7, 0x5d, 0x48,
+  0x2b, 0x8d, 0x21, 0xb5, 0x6d, 0x05, 0x40, 0xef, 0xaa, 0x16, 0x0a, 0x14,
+  0x3d, 0x1c, 0xc2, 0xab, 0xfc, 0x52, 0x20, 0xc9, 0x2c, 0x4f, 0x35, 0x32,
+  0xce, 0xd6, 0xa4, 0x87, 0x21, 0x5e, 0x22, 0x38, 0xb0, 0xdb, 0x4c, 0x3a,
+  0x93, 0xc8, 0xf3, 0x2a, 0x00, 0xa9, 0xd7, 0x14, 0x0f, 0xc1, 0x2a, 0x3a,
+  0xd1, 0x4a, 0x93, 0xaa, 0xe9, 0x8d, 0x3d, 0x59, 0x83, 0x39, 0xe5, 0x53,
+  0x18, 0x99, 0xf1, 0x7f, 0x07, 0xb3, 0x17, 0x70, 0x4e, 0x21, 0x5b, 0x32,
+  0x24, 0x85, 0x29, 0x86, 0x97, 0xc9, 0x29, 0xb1, 0xde, 0xe3, 0x2b, 0x1a,
+  0x58, 0x1e, 0xbd, 0x1d, 0x8f, 0x58, 0x15, 0xf7, 0x8b, 0x96, 0xbb, 0x45,
+  0xeb, 0x29, 0xb3, 0x5f, 0x6d, 0xf2, 0x58, 0x5d, 0xce, 0x74, 0x51, 0x16,
+  0x04, 0xc5, 0xa9, 0x2a, 0x4c, 0x78, 0xaa, 0xdb, 0x8b, 0x75, 0xb4, 0x2b,
+  0xa7, 0x31, 0x1a, 0x1b, 0xf1, 0xe6, 0x48, 0x3b, 0x1b, 0x07, 0xe5, 0xfb,
+  0xcf, 0xe0, 0xd7, 0x73, 0x57, 0x11, 0xe6, 0xe3, 0xf6, 0x9b, 0xf4, 0x36,
+  0x20, 0xf9, 0x11, 0xb8, 0x42, 0x7a, 0x5f, 0x31, 0x51, 0x6f, 0xb4, 0x08,
+  0x2d, 0xab, 0x94, 0x7c, 0x24, 0x92, 0x36, 0x7c, 0x41, 0x07, 0x43, 0x7a,
+  0xab, 0x9f, 0xf0, 0x79, 0xb6, 0x5c, 0x2d, 0xf8, 0x7d, 0xc7, 0x0d, 0xc8,
+  0x63, 0x2a, 0x25, 0xfa, 0xc3, 0x2c, 0x32, 0x64, 0x20, 0xed, 0x4a, 0x68,
+  0xfb, 0xe4, 0x77, 0x1b, 0x59, 0xef, 0x48, 0x3b, 0x09, 0xf6, 0x68, 0x8e,
+  0xfa, 0xbd, 0x18, 0xcd, 0x66, 0x18, 0xe7, 0xea, 0x56, 0xb4, 0xa9, 0xc9,
+  0xa9, 0xa7, 0xc7, 0xd0, 0xb5, 0xaf, 0x37, 0x0b, 0xc6, 0x2f, 0x7d, 0xb6,
+  0x62, 0x98, 0x56, 0x2a, 0xf3, 0x30, 0xe6, 0x48, 0x4b, 0x53, 0xaf, 0xcf,
+  0xc3, 0x5c, 0xb0, 0x1d, 0x52, 0x79, 0xb9, 0x96, 0x94, 0xa9, 0x2a, 0x59,
+  0xf3, 0x81, 0x2e, 0x2d, 0x40, 0x0e, 0xa0, 0x6f, 0x5a, 0x12, 0x7c, 0x40,
+  0x61, 0x4c, 0x5d, 0x31, 0x89, 0x4f, 0xbc, 0xd3, 0xb7, 0x25, 0x97, 0x61,
+  0xc8, 0x5b, 0x4d, 0x72, 0x25, 0xe6, 0xcb, 0x45, 0xc5, 0x2b, 0x94, 0x92,
+  0x40, 0x0b, 0x6d, 0x1a, 0x1b, 0x3a, 0xe7, 0xef, 0xf1, 0xa1, 0x8c, 0xb3,
+  0x29, 0x62, 0x38, 0x61, 0xfb, 0x6d, 0xa6, 0x73, 0xc0, 0x69, 0x32, 0x44,
+  0xa5, 0xb0, 0x17, 0xe8, 0x25, 0xae, 0x45, 0x6b, 0xea, 0x57, 0xf7, 0x77,
+  0x54, 0x59, 0x4c, 0xe9, 0xb7, 0x33, 0x75, 0xbd, 0xcb, 0x6e, 0x54, 0xd0,
+  0xd9, 0x69, 0xb4, 0xb4, 0x8e, 0x46, 0x63, 0x20, 0x9d, 0xa9, 0x2d, 0x8d,
+  0x93, 0xb2, 0x40, 0xda, 0x89, 0x24, 0xe8, 0x77, 0x0e, 0x95, 0x4a, 0x56,
+  0xf5, 0x35, 0xa6, 0xcb, 0x56, 0xaf, 0x4f, 0x46, 0x16, 0xe6, 0xf8, 0x51,
+  0xe7, 0x37, 0x70, 0x5c, 0xcb, 0x2d, 0xc4, 0xc0, 0xb8, 0x3a, 0xda, 0x52,
+  0xb0, 0xa6, 0x43, 0xad, 0x48, 0x09, 0xde, 0x92, 0xa4, 0x6c, 0x1e, 0x61,
+  0xcc, 0x74, 0xa0, 0x47, 0x4e, 0x87, 0x63, 0x40, 0x72, 0x4b, 0x89, 0x2e,
+  0xe6, 0xf3, 0x6f, 0x5f, 0xee, 0x92, 0x6e, 0xaa, 0x69, 0x41, 0x6d, 0xb2,
+  0xb0, 0x1b, 0x8e, 0x85, 0x0e, 0xe2, 0x1a, 0x4f, 0x42, 0x47, 0xeb, 0xf3,
+  0x11, 0x5d, 0x85, 0xc4, 0xb4, 0x0b, 0xcb, 0x58, 0x42, 0x5b, 0x1c, 0xe5,
+  0x65, 0x5d, 0x12, 0x07, 0x5d, 0x93, 0xe0, 0x3a, 0x75, 0xde, 0xbb, 0xaa,
+  0x2f, 0x1a, 0xbb, 0xcb, 0xbf, 0xc6, 0x95, 0x76, 0x90, 0x91, 0xe4, 0xf2,
+  0x26, 0x3a, 0x60, 0xac, 0x34, 0x51, 0xda, 0xc6, 0x07, 0x48, 0x73, 0x5d,
+  0xfe, 0x76, 0x89, 0x07, 0x5d, 0x46, 0x8e, 0xba, 0xd7, 0x67, 0xbb, 0x8f,
+  0xbc, 0xce, 0x39, 0x38, 0x95, 0x49, 0x7b, 0xbc, 0x67, 0x82, 0x03, 0x8d,
+  0xf2, 0x53, 0x12, 0xd0, 0x89, 0xcb, 0x4b, 0x8b, 0x4d, 0xde, 0xc3, 0x3a,
+  0xc8, 0xe6, 0xfa, 0x8e, 0xdd, 0x1a, 0x76, 0x3f, 0xd6, 0x7d, 0xf3, 0x54,
+  0xe9, 0xa2, 0x3a, 0x13, 0xb2, 0x3b, 0xcf, 0xa6, 0x97, 0xf8, 0x98, 0x5a,
+  0x46, 0x04, 0xbb, 0x83, 0xa3, 0x9f, 0xdc, 0x4b, 0xb4, 0x0b, 0x98, 0x04,
+  0x6f, 0xcd, 0x0f, 0x25, 0xb7, 0x3a, 0x1f, 0xd4, 0x5a, 0xa9, 0x85, 0x40,
+  0x85, 0x28, 0x1e, 0xfd, 0x9a, 0xad, 0x18, 0xe9, 0x9c, 0x91, 0x6a, 0xd2,
+  0xd5, 0x18, 0xb3, 0x15, 0x09, 0x9a, 0x59, 0x5d, 0xbd, 0xd8, 0xd4, 0xc4,
+  0x29, 0x02, 0x2d, 0xce, 0x33, 0xc8, 0x97, 0x6d, 0x92, 0x7f, 0xa0, 0x94,
+  0xd1, 0xe6, 0x6d, 0x7e, 0xb1, 0xbe, 0x84, 0x78, 0xa4, 0xa8, 0x78, 0xd4,
+  0xdd, 0x1a, 0xad, 0xe4, 0x93, 0x4d, 0x33, 0x14, 0xda, 0x69, 0xa2, 0x4e,
+  0xda, 0xed, 0xa3, 0x8b, 0xfc, 0x23, 0x91, 0x0e, 0xe9, 0x14, 0xb2, 0xd5,
+  0xce, 0x33, 0x90, 0xae, 0x51, 0x4f, 0x55, 0xc4, 0x92, 0x92, 0x52, 0xe2,
+  0x0f, 0xa1, 0x48, 0x70, 0x6c, 0x1f, 0x52, 0x4d, 0x72, 0x70, 0x13, 0x24,
+  0xb9, 0x5c, 0xb1, 0x99, 0x58, 0xbe, 0x48, 0xe7, 0x3e, 0x51, 0x8b, 0x48,
+  0xf7, 0x32, 0xe6, 0x4f, 0x7b, 0xe1, 0x23, 0xde, 0x64, 0xf5, 0xea, 0x52,
+  0xeb, 0x7c, 0xaa, 0xdf, 0xa7, 0x9b, 0xd1, 0x4b, 0x76, 0x19, 0xa9, 0xc2,
+  0xf8, 0x9e, 0xdc, 0x92, 0xae, 0x4b, 0x1e, 0x58, 0xe2, 0x22, 0xcc, 0x04,
+  0xf9, 0x91, 0xee, 0x21, 0x3a, 0x65, 0xdf, 0x50, 0x75, 0x29, 0xec, 0xcf,
+  0xeb, 0x25, 0xbf, 0x4d, 0x76, 0x71, 0x83, 0x9f, 0x02, 0xcd, 0xac, 0xfc,
+  0x5b, 0x88, 0x85, 0x26, 0xde, 0x90, 0x8b, 0x4e, 0x50, 0x84, 0x0e, 0x8a,
+  0x86, 0xb5, 0x69, 0xa9, 0x07, 0xd2, 0x59, 0x71, 0x43, 0x67, 0xbf, 0x95,
+  0x44, 0x77, 0x0a, 0xf1, 0x6a, 0x41, 0xd3, 0x93, 0x89, 0xec, 0x52, 0x9e,
+  0xb8, 0xa6, 0x5b, 0xe9, 0x24, 0x80, 0x4d, 0x66, 0xbc, 0xb4, 0xb4, 0x38,
+  0xd2, 0x5c, 0x6d, 0x49, 0x5a, 0x16, 0x02, 0x92, 0xa4, 0x9d, 0x82, 0x0f,
+  0x71, 0x15, 0xea, 0xa8, 0x68, 0x14, 0x51, 0x45, 0x00, 0x51, 0x45, 0x14,
+  0x02, 0x27, 0x19, 0x7e, 0x25, 0x8b, 0xfe, 0xd5, 0x5b, 0x3e, 0xfc, 0x53,
+  0xdd, 0x22, 0x71, 0x97, 0xe2, 0x58, 0xbf, 0xed, 0x55, 0xb3, 0xef, 0xc5,
+  0x3d, 0xd0, 0x05, 0x14, 0x51, 0x50, 0x02, 0x93, 0x38, 0xe3, 0xf2, 0x3d,
+  0x97, 0x7d, 0x11, 0x23, 0xf8, 0x0d, 0x39, 0xd2, 0x67, 0x1c, 0x7e, 0x47,
+  0xb2, 0xef, 0xa2, 0x24, 0x7f, 0x01, 0xa9, 0x03, 0x7c, 0x6f, 0x8b, 0xb7,
+  0xf3, 0x07, 0xd9, 0x4a, 0x9c, 0x5f, 0xc2, 0x21, 0x71, 0x0b, 0x01, 0xb9,
+  0xe3, 0x12, 0xc8, 0x69, 0xd7, 0xdb, 0xe7, 0x87, 0x23, 0xf3, 0xa3, 0xc8,
+  0x4f, 0x56, 0xdc, 0x49, 0xef, 0x04, 0x2b, 0xbf, 0x5e, 0x04, 0x8f, 0x1a,
+  0x6b, 0x8d, 0xf1, 0x76, 0xfe, 0x60, 0xfb, 0x2b, 0x66, 0xba, 0xd0, 0x1f,
+  0x30, 0x70, 0x4f, 0x2e, 0xb8, 0x31, 0x3d, 0xbf, 0x75, 0x12, 0x63, 0xce,
+  0x7a, 0x5b, 0xb0, 0xae, 0xb1, 0xd6, 0x75, 0xe4, 0xf7, 0x86, 0x47, 0xbf,
+  0x7b, 0x13, 0x25, 0xb4, 0xf6, 0xc3, 0xd2, 0xb4, 0x3d, 0xaf, 0x0a, 0x70,
+  0xe2, 0x45, 0xa6, 0x35, 0x83, 0x38, 0x87, 0x96, 0xc6, 0x49, 0x66, 0xcd,
+  0x92, 0xad, 0xb8, 0xb3, 0xdc, 0x46, 0x93, 0xe4, 0xb3, 0xb5, 0xca, 0xc4,
+  0x8e, 0xbb, 0xe5, 0xed, 0x13, 0xef, 0x2a, 0x3e, 0x9e, 0xcf, 0xd3, 0x4a,
+  0xff, 0x00, 0x84, 0x36, 0x3a, 0xac, 0x53, 0x89, 0x51, 0xf2, 0xc8, 0x6f,
+  0x26, 0x0d, 0xa3, 0x2c, 0x2c, 0xdb, 0xee, 0x2f, 0x9e, 0x8d, 0xc2, 0xba,
+  0x34, 0x79, 0xa0, 0xcc, 0x57, 0x4e, 0x83, 0x98, 0x04, 0x28, 0xfe, 0x81,
+  0x5f, 0xe9, 0x55, 0x8b, 0x89, 0x49, 0xb6, 0xf1, 0x13, 0x02, 0xb8, 0x63,
+  0x77, 0x98, 0xab, 0x65, 0x32, 0xdb, 0x76, 0x24, 0xc8, 0x8a, 0x50, 0xed,
+  0x21, 0xc8, 0x41, 0xd3, 0x8d, 0xfa, 0x94, 0x85, 0x8e, 0x64, 0x9f, 0x50,
+  0x23, 0xc2, 0xba, 0x21, 0x37, 0xa7, 0x57, 0x58, 0xfd, 0x0e, 0x7a, 0x90,
+  0x5a, 0xb1, 0xd2, 0x5f, 0x51, 0x53, 0x88, 0x96, 0xb9, 0x8a, 0x11, 0x72,
+  0x2b, 0x4c, 0x11, 0x3e, 0x75, 0xb4, 0x38, 0x87, 0xa0, 0x68, 0x1f, 0x2f,
+  0x86, 0xe6, 0xbb, 0x66, 0x3a, 0xf4, 0x2a, 0xf3, 0x52, 0xb4, 0x6f, 0xf3,
+  0x90, 0x07, 0x8d, 0x6b, 0xc1, 0xee, 0xd6, 0xe7, 0x25, 0x88, 0xd6, 0xd9,
+  0xce, 0x4b, 0xb4, 0xce, 0x8a, 0x89, 0x36, 0x97, 0x16, 0x95, 0x29, 0x48,
+  0x4e, 0xd6, 0x1c, 0x60, 0xac, 0xf5, 0xf7, 0xb2, 0x9d, 0xf2, 0x28, 0xf3,
+  0x27, 0x98, 0x8f, 0x01, 0x52, 0x38, 0x3c, 0xeb, 0x8b, 0x90, 0xe4, 0xd9,
+  0x6f, 0xaa, 0xdd, 0xfa, 0xc8, 0xf1, 0x83, 0x71, 0x3d, 0xdd, 0xa9, 0x00,
+  0x16, 0xdf, 0x1f, 0xaa, 0xeb, 0x7c, 0xab, 0x07, 0xd3, 0xcc, 0x2b, 0x92,
+  0xe3, 0x88, 0x3c, 0x8b, 0x9c, 0x9b, 0xae, 0x2d, 0x7e, 0x91, 0x8f, 0x4b,
+  0x98, 0xae, 0x79, 0xad, 0xb7, 0x1d, 0x12, 0x22, 0xc9, 0x5f, 0xf5, 0x8a,
+  0x61, 0x5d, 0x03, 0x9f, 0xac, 0x92, 0x92, 0x7c, 0x77, 0x5e, 0x8a, 0xef,
+  0x62, 0x71, 0x3c, 0xe6, 0xf1, 0xdd, 0x90, 0xd5, 0xcc, 0x90, 0x4a, 0x7d,
+  0x03, 0x7a, 0xf4, 0xd6, 0x36, 0x08, 0x1d, 0x41, 0x1d, 0xfb, 0xdf, 0x4a,
+  0x53, 0xb8, 0x31, 0x79, 0xc7, 0x6d, 0x89, 0xba, 0x19, 0xf3, 0xb2, 0x0e,
+  0xc5, 0x3c, 0xd7, 0x36, 0x94, 0x84, 0x07, 0x1e, 0x46, 0xce, 0xdd, 0x65,
+  0x09, 0x00, 0x25, 0x69, 0xd8, 0xf3, 0x07, 0x45, 0x25, 0x24, 0x7c, 0x2e,
+  0xa6, 0x4e, 0xcd, 0x78, 0xb7, 0x5f, 0x2d, 0x2d, 0xdd, 0xad, 0x13, 0xd9,
+  0x9b, 0x09, 0xf4, 0x85, 0x21, 0xe6, 0x55, 0xb4, 0xe8, 0xf5, 0x3b, 0xf1,
+  0x49, 0xee, 0x1a, 0x20, 0x1a, 0xbe, 0xbd, 0xf0, 0xca, 0x69, 0xd8, 0xd5,
+  0x9b, 0x65, 0x10, 0x31, 0x9b, 0x58, 0x97, 0x35, 0x89, 0x92, 0xbb, 0x55,
+  0x16, 0xd9, 0x62, 0x2c, 0x72, 0xea, 0xdd, 0x57, 0xa3, 0x5d, 0xc9, 0x1e,
+  0x92, 0xa2, 0x07, 0x77, 0xb2, 0xa0, 0x31, 0x5b, 0x86, 0x7d, 0x7e, 0xbe,
+  0xc7, 0x9f, 0x73, 0x85, 0x17, 0x1d, 0xb0, 0x20, 0x29, 0x42, 0x1b, 0x88,
+  0x0b, 0x95, 0x2b, 0xa1, 0x09, 0x04, 0xab, 0xaa, 0x52, 0x0e, 0x89, 0xf3,
+  0x52, 0x7d, 0x1b, 0xef, 0xa7, 0x1e, 0x77, 0x5b, 0x49, 0xf3, 0x94, 0x95,
+  0x12, 0x41, 0x00, 0xf8, 0xfe, 0x77, 0xd5, 0xbe, 0x83, 0x7e, 0x83, 0x5c,
+  0x71, 0x6d, 0xb1, 0x63, 0x4c, 0x7e, 0x4c, 0x66, 0xb9, 0x64, 0x48, 0x57,
+  0xbe, 0xbc, 0x56, 0x56, 0xa5, 0x1d, 0x6c, 0x9d, 0x92, 0x74, 0x94, 0x8e,
+  0xe0, 0x08, 0x03, 0xaf, 0xa2, 0xab, 0x24, 0xdb, 0xce, 0x4b, 0x45, 0xa4,
+  0xb1, 0x83, 0x4f, 0x10, 0xdc, 0x67, 0xf1, 0x6b, 0x9a, 0xa5, 0xc2, 0x39,
+  0x3d, 0xc2, 0x92, 0x4a, 0x89, 0x1a, 0x4a, 0xb5, 0xe6, 0x7f, 0xd4, 0x05,
+  0x78, 0x91, 0x9b, 0x62, 0x50, 0x18, 0x40, 0x9d, 0x93, 0xda, 0x1b, 0x75,
+  0x28, 0x1d, 0xa2, 0x04, 0xa4, 0x29, 0x49, 0x3a, 0xea, 0x08, 0x49, 0x24,
+  0x52, 0xd5, 0xd6, 0xee, 0xde, 0x4f, 0x2a, 0x0d, 0xa2, 0x03, 0x25, 0xdc,
+  0x57, 0xdd, 0x46, 0x99, 0xba, 0xdc, 0x92, 0x90, 0x59, 0x79, 0xf4, 0x92,
+  0xe3, 0x51, 0x1b, 0x27, 0xa2, 0xd0, 0x5c, 0x6d, 0x01, 0x6a, 0x1d, 0x36,
+  0x94, 0x24, 0x1d, 0xa8, 0xd4, 0x9e, 0x4b, 0x17, 0x12, 0xc7, 0x67, 0x22,
+  0xe6, 0xed, 0xe7, 0xf9, 0x3d, 0x71, 0x90, 0xb1, 0xd8, 0xf9, 0x1a, 0x00,
+  0x90, 0xfe, 0xcf, 0xc1, 0x42, 0x5a, 0x48, 0x75, 0x67, 0xd0, 0x3c, 0xf4,
+  0xfa, 0x50, 0x77, 0x58, 0x4a, 0x72, 0x52, 0x94, 0xe2, 0xb2, 0x74, 0x46,
+  0x11, 0x71, 0x8c, 0x24, 0xf0, 0x6d, 0x1c, 0x4e, 0xc0, 0xd5, 0xae, 0x4c,
+  0x8d, 0x85, 0xef, 0xbb, 0x91, 0x87, 0x95, 0xf6, 0x20, 0xd7, 0xa3, 0xc4,
+  0xdc, 0x05, 0x09, 0x2a, 0x7b, 0x27, 0x87, 0x1d, 0x20, 0xeb, 0x9a, 0x42,
+  0x56, 0xc8, 0x27, 0xd0, 0x0a, 0xd2, 0x36, 0x7d, 0x5d, 0xf5, 0x2d, 0x64,
+  0xfc, 0x70, 0x64, 0x6c, 0xa1, 0xa8, 0x52, 0x17, 0x8f, 0xc0, 0x0a, 0x20,
+  0x5d, 0x6f, 0x51, 0x80, 0x9a, 0xea, 0x37, 0xd1, 0x49, 0x86, 0x83, 0xca,
+  0x85, 0x6b, 0xbc, 0xb8, 0x47, 0xa7, 0x90, 0x77, 0x54, 0xef, 0xf2, 0x67,
+  0x06, 0xc3, 0xe5, 0xc6, 0xbc, 0xe5, 0x97, 0x69, 0x37, 0xcb, 0xe6, 0xf5,
+  0x1a, 0x65, 0xe5, 0xf3, 0x2e, 0x49, 0x56, 0xc1, 0xe5, 0x8e, 0xc0, 0x1a,
+  0x49, 0xdf, 0x83, 0x48, 0x07, 0xdb, 0x59, 0x4a, 0xee, 0x4b, 0xc8, 0xd2,
+  0x36, 0x91, 0x7e, 0x68, 0x4c, 0x75, 0xbb, 0x97, 0x12, 0x63, 0x37, 0x67,
+  0xb3, 0x63, 0xb7, 0x01, 0x61, 0x90, 0xfb, 0x2a, 0x97, 0x79, 0x9c, 0x83,
+  0x15, 0xae, 0xc9, 0x2e, 0x25, 0x64, 0xc7, 0x42, 0xbd, 0xf1, 0xc5, 0x1e,
+  0x5d, 0x05, 0x04, 0x84, 0x83, 0xa3, 0xba, 0xbb, 0xef, 0x76, 0xd8, 0x37,
+  0x9b, 0x34, 0xbb, 0x4d, 0xd2, 0x23, 0x72, 0xe1, 0x4c, 0x61, 0x4c, 0x48,
+  0x65, 0xc1, 0xb4, 0xb8, 0x85, 0x0e, 0x55, 0x24, 0x8f, 0x58, 0x26, 0x93,
+  0x66, 0x64, 0x99, 0x35, 0xe1, 0x61, 0x9b, 0x4c, 0x36, 0xb1, 0xf8, 0xca,
+  0xde, 0xa4, 0x4e, 0x6f, 0xb7, 0x98, 0xb1, 0xaf, 0xe8, 0xe3, 0x24, 0xe9,
+  0x1d, 0x47, 0x7b, 0xaa, 0x1e, 0xb4, 0x50, 0x71, 0x3b, 0x84, 0xc0, 0xa7,
+  0x1f, 0xbe, 0xe5, 0x6e, 0x38, 0x76, 0x4b, 0xcb, 0xbb, 0x79, 0x31, 0x3e,
+  0xc6, 0xda, 0x48, 0x40, 0x1e, 0xa2, 0x2b, 0x9e, 0xa3, 0x9d, 0x47, 0xaa,
+  0x47, 0x45, 0x35, 0x0a, 0x6b, 0x4a, 0x22, 0xb8, 0x0b, 0x73, 0x99, 0x67,
+  0x55, 0xdb, 0x85, 0x37, 0xd9, 0x2a, 0x7a, 0xe7, 0x8a, 0xa9, 0x29, 0x84,
+  0xfb, 0xa7, 0xce, 0x99, 0x6d, 0x5e, 0xcc, 0x77, 0x7d, 0x65, 0x23, 0x6d,
+  0xab, 0x5d, 0xc5, 0x03, 0xd3, 0x56, 0xb0, 0xee, 0xaf, 0x9c, 0x38, 0xca,
+  0xbc, 0x8f, 0x87, 0x79, 0x26, 0x3b, 0xc4, 0x19, 0x6e, 0xc9, 0xbb, 0x35,
+  0x69, 0x77, 0xb0, 0x33, 0x4b, 0x68, 0x0f, 0xbd, 0x05, 0xdf, 0xcb, 0x43,
+  0x91, 0xc8, 0x02, 0x54, 0xb4, 0xe9, 0x2e, 0x36, 0xb0, 0x00, 0x25, 0x2a,
+  0x07, 0xa9, 0x05, 0x5f, 0x42, 0xdb, 0x27, 0x45, 0xb9, 0x5b, 0x63, 0x5c,
+  0x60, 0xbe, 0xdc, 0x88, 0x92, 0x99, 0x43, 0xcc, 0x3a, 0x83, 0xb4, 0xad,
+  0x0b, 0x00, 0xa5, 0x43, 0xd4, 0x41, 0x06, 0xb1, 0x36, 0x3a, 0xa8, 0xa2,
+  0x8a, 0x00, 0xa2, 0x8a, 0x28, 0x04, 0x4e, 0x32, 0xfc, 0x4b, 0x17, 0xfd,
+  0xaa, 0xb6, 0x7d, 0xf8, 0xa7, 0xba, 0x44, 0xe3, 0x2f, 0xc4, 0xb1, 0x7f,
+  0xda, 0xab, 0x67, 0xdf, 0x8a, 0x7b, 0xa0, 0x0a, 0x28, 0xa2, 0xa0, 0x05,
+  0x26, 0x71, 0xc7, 0xe4, 0x7b, 0x2e, 0xfa, 0x22, 0x47, 0xf0, 0x1a, 0x73,
+  0xa4, 0xce, 0x38, 0xfc, 0x8f, 0x65, 0xdf, 0x44, 0x48, 0xfe, 0x03, 0x52,
+  0x06, 0xf8, 0xdf, 0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x56, 0xb8, 0xdf,
+  0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x50, 0x0b, 0xbc, 0x47, 0xc5, 0x2d,
+  0xd9, 0xc6, 0x15, 0x77, 0xc5, 0xae, 0xa8, 0xdc, 0x5b, 0x8c, 0x72, 0xd7,
+  0x37, 0x79, 0x6d, 0x7d, 0xe8, 0x58, 0xf5, 0xa5, 0x40, 0x28, 0x7b, 0x2b,
+  0xe7, 0x0e, 0x13, 0xe4, 0x57, 0x3b, 0x3e, 0x4a, 0x18, 0xbd, 0x2b, 0xb0,
+  0xbd, 0x46, 0x98, 0x8c, 0x7f, 0x22, 0x04, 0xf4, 0x33, 0x9b, 0x49, 0xf2,
+  0x29, 0x87, 0xd2, 0x99, 0x0d, 0x20, 0xb4, 0x4f, 0x8a, 0x9b, 0x41, 0x3f,
+  0x0b, 0xaf, 0xd6, 0x04, 0x6c, 0xee, 0xbe, 0x75, 0xfc, 0x28, 0x71, 0x88,
+  0x96, 0x4c, 0x92, 0x27, 0x10, 0x9c, 0x4b, 0x8d, 0xd8, 0xee, 0x8c, 0x26,
+  0xc5, 0x95, 0xa9, 0xad, 0xed, 0xa6, 0x56, 0xa0, 0x63, 0xcd, 0x1a, 0xfc,
+  0xe6, 0x5d, 0x08, 0x3b, 0xef, 0xd2, 0x52, 0x3c, 0x4d, 0x5a, 0x12, 0x70,
+  0x92, 0x68, 0xac, 0xe2, 0xa7, 0x1c, 0x31, 0xa3, 0x8b, 0x0d, 0xb5, 0x69,
+  0x97, 0x6e, 0xe2, 0x9c, 0x24, 0x94, 0xc4, 0x6d, 0xa4, 0xc1, 0xc8, 0x50,
+  0x91, 0xbf, 0xe6, 0x85, 0x5e, 0x63, 0xe7, 0xd2, 0x59, 0x70, 0x92, 0x7f,
+  0x51, 0x6b, 0xf4, 0x0a, 0x91, 0xd8, 0x52, 0x76, 0x0a, 0x54, 0x9d, 0x7c,
+  0x20, 0x76, 0x35, 0xe9, 0xad, 0x1c, 0x1d, 0xbf, 0x2e, 0xfd, 0x65, 0x9d,
+  0x8e, 0xe4, 0xad, 0x32, 0xed, 0xc1, 0x85, 0xb9, 0x6e, 0xbb, 0x33, 0xa0,
+  0x5b, 0x71, 0xd0, 0x81, 0xb5, 0x8f, 0x02, 0xdb, 0xcd, 0xa9, 0x2e, 0x27,
+  0xc0, 0x85, 0x74, 0xa4, 0x76, 0xe7, 0x5f, 0x31, 0x0b, 0x83, 0xdc, 0x32,
+  0x85, 0x01, 0xcb, 0xa5, 0xee, 0x17, 0x5b, 0x43, 0xf2, 0x02, 0xbb, 0x03,
+  0x6e, 0x27, 0x4d, 0x3e, 0xfb, 0x80, 0x75, 0x0d, 0x7e, 0x49, 0x40, 0x0e,
+  0x65, 0x29, 0x03, 0x5d, 0xfb, 0x1d, 0xf4, 0x2a, 0x28, 0x37, 0x1e, 0x8f,
+  0x74, 0x70, 0x56, 0xa6, 0xe6, 0xb5, 0x75, 0x5b, 0x32, 0x53, 0x89, 0x79,
+  0x14, 0xab, 0x3c, 0x38, 0xb6, 0xdb, 0x53, 0xed, 0xb1, 0x78, 0xba, 0x2d,
+  0xc4, 0xc7, 0x75, 0x63, 0x98, 0x46, 0x69, 0x09, 0x2a, 0x7a, 0x41, 0x4f,
+  0xe7, 0x72, 0xa0, 0x69, 0x23, 0xc5, 0x45, 0x20, 0xf4, 0xde, 0x97, 0xb1,
+  0xcc, 0x42, 0xd5, 0x6f, 0xc9, 0x67, 0x58, 0x12, 0xbb, 0x94, 0x09, 0x26,
+  0x3a, 0x67, 0xdb, 0xa7, 0xc7, 0x94, 0x5a, 0x94, 0xa6, 0xd4, 0x40, 0x79,
+  0xb7, 0x14, 0x9f, 0x35, 0xc2, 0x97, 0x7a, 0xe9, 0x41, 0x40, 0x07, 0x07,
+  0x80, 0x15, 0x1d, 0x27, 0x14, 0x5c, 0x4e, 0x28, 0xb7, 0x2a, 0x7c, 0xb7,
+  0xae, 0x72, 0x9e, 0xb4, 0x36, 0xb9, 0x97, 0x17, 0xbc, 0xd0, 0x49, 0x9c,
+  0xc8, 0x52, 0x52, 0x37, 0xca, 0xdb, 0x69, 0x6d, 0x04, 0x04, 0xfa, 0x09,
+  0x24, 0x92, 0x49, 0xa6, 0xb7, 0xef, 0x71, 0x32, 0x1b, 0xfc, 0x37, 0x70,
+  0xfb, 0x4c, 0xec, 0xaa, 0xe7, 0x6e, 0x53, 0xa8, 0x4b, 0x90, 0x48, 0x44,
+  0x36, 0xfb, 0x44, 0x72, 0xad, 0x0e, 0xc9, 0x5f, 0xbd, 0x81, 0xd0, 0x1d,
+  0x27, 0x99, 0x5b, 0x48, 0xe9, 0xd2, 0xb5, 0x72, 0x59, 0x72, 0x9e, 0xd8,
+  0x32, 0x51, 0x78, 0x4a, 0x3b, 0xe4, 0xda, 0xac, 0x77, 0x32, 0x6d, 0x7c,
+  0x90, 0xb3, 0xc4, 0xad, 0xa1, 0xa0, 0x8f, 0x2a, 0xb2, 0x32, 0xeb, 0x80,
+  0x0e, 0xef, 0x39, 0x2a, 0x40, 0x3f, 0xf2, 0xee, 0x96, 0xee, 0xb1, 0x6d,
+  0x2f, 0x5c, 0x7d, 0xc8, 0xbe, 0xe4, 0xb7, 0xfc, 0xe6, 0xe6, 0x01, 0xff,
+  0x00, 0x41, 0x5a, 0x99, 0x4a, 0x50, 0xaf, 0xf7, 0xad, 0xb0, 0x12, 0x00,
+  0xf5, 0xba, 0xb0, 0x9f, 0x4d, 0x58, 0x8d, 0xf0, 0xf2, 0xf7, 0x75, 0x8a,
+  0xe4, 0xbe, 0x21, 0xe5, 0x48, 0x83, 0x6e, 0x09, 0xe6, 0x76, 0xd7, 0x65,
+  0x71, 0x51, 0x98, 0x09, 0x1e, 0x0f, 0x49, 0x56, 0x9c, 0x58, 0xd7, 0x7f,
+  0x2f, 0x66, 0x2a, 0x52, 0xd7, 0x7d, 0xb0, 0x58, 0x2d, 0xf1, 0xac, 0x9c,
+  0x35, 0xc5, 0x11, 0x2d, 0x97, 0x5d, 0x0c, 0xb2, 0xb8, 0xe9, 0x4c, 0x68,
+  0x6a, 0x57, 0x5e, 0x65, 0x17, 0x48, 0xdb, 0xba, 0x00, 0x92, 0xa4, 0x25,
+  0x7e, 0x3b, 0x3b, 0xae, 0x6a, 0x97, 0x31, 0xe2, 0x08, 0xea, 0xa7, 0x6b,
+  0x27, 0xbc, 0xc8, 0x3b, 0x4e, 0x0b, 0x9b, 0x5f, 0xed, 0xe9, 0x83, 0x74,
+  0x7e, 0x1e, 0x13, 0x61, 0xd2, 0x12, 0x2d, 0xd6, 0xc0, 0x87, 0xe6, 0x14,
+  0x21, 0x5c, 0xc9, 0x05, 0xd2, 0x3b, 0x26, 0x74, 0x40, 0x23, 0xb3, 0x4a,
+  0x88, 0xf0, 0x50, 0xa9, 0x9b, 0x24, 0x6e, 0x1d, 0x60, 0xb2, 0xe4, 0xb7,
+  0x8d, 0xda, 0x9f, 0xbc, 0x5f, 0xca, 0x7f, 0x9c, 0xae, 0x1a, 0x55, 0x3e,
+  0x7b, 0x87, 0xb8, 0xf6, 0xaf, 0x28, 0x9e, 0x4d, 0x9f, 0x05, 0xa9, 0x23,
+  0xd5, 0x5b, 0x9d, 0xb1, 0x5f, 0x72, 0x85, 0x2c, 0x5e, 0xef, 0x0b, 0x93,
+  0x10, 0x9d, 0x2a, 0x34, 0x5e, 0x68, 0xf0, 0xfd, 0x69, 0xd0, 0x3d, 0xa3,
+  0xa0, 0x1f, 0x15, 0x2b, 0x94, 0xfe, 0x88, 0xae, 0xe6, 0xda, 0xc5, 0x6c,
+  0xcd, 0x1b, 0x70, 0x9a, 0x48, 0x6b, 0x6a, 0x54, 0x6b, 0x73, 0x2a, 0xe4,
+  0x6b, 0x43, 0x64, 0xa9, 0x0c, 0xa4, 0xf2, 0xf4, 0xf1, 0x3a, 0xac, 0x24,
+  0x9b, 0x79, 0x9b, 0x36, 0x86, 0x23, 0xb4, 0x11, 0xc8, 0xc5, 0xd3, 0x2b,
+  0xc9, 0xdd, 0x72, 0x3b, 0x6f, 0x0c, 0x70, 0xa0, 0x02, 0xe4, 0x06, 0xd2,
+  0x0c, 0xe4, 0xa0, 0xec, 0x05, 0x29, 0xc7, 0x13, 0xca, 0x90, 0x7a, 0xe8,
+  0xb6, 0x95, 0xf5, 0xfc, 0xfa, 0x85, 0x98, 0xc4, 0x1c, 0x5a, 0xfb, 0x3d,
+  0xc5, 0xa1, 0x8f, 0x29, 0x66, 0x10, 0x93, 0x21, 0xd9, 0x4b, 0x70, 0x3f,
+  0x3c, 0x12, 0x41, 0x6d, 0x12, 0x16, 0x76, 0xa2, 0x34, 0x8f, 0x37, 0x67,
+  0xaa, 0xc0, 0x09, 0x14, 0xe9, 0x76, 0xb6, 0x48, 0x7a, 0xd6, 0xd5, 0xd2,
+  0xd1, 0x2b, 0xca, 0x67, 0x43, 0x49, 0x91, 0x6d, 0x73, 0x63, 0xdf, 0x50,
+  0x40, 0x25, 0x95, 0x1e, 0xe5, 0x21, 0x60, 0x01, 0xea, 0x3c, 0xa7, 0xc0,
+  0x54, 0xcc, 0x05, 0x5b, 0x2f, 0x50, 0xe0, 0x5d, 0x9a, 0x65, 0xa7, 0xd1,
+  0xc8, 0x1d, 0x8c, 0xb7, 0x10, 0x0a, 0x9a, 0xe6, 0x1d, 0x75, 0xe2, 0x95,
+  0x78, 0x1f, 0x66, 0xaa, 0x9a, 0xb4, 0xec, 0x8b, 0xe9, 0xd5, 0xbb, 0x23,
+  0xaf, 0xb2, 0x11, 0x69, 0xc3, 0xe4, 0xdc, 0xed, 0x4c, 0xa1, 0x9e, 0x46,
+  0x12, 0xe9, 0x51, 0x68, 0x92, 0x86, 0xfa, 0x73, 0x2c, 0xa4, 0xe8, 0x9e,
+  0x54, 0x95, 0x2b, 0x47, 0xd1, 0x48, 0x37, 0x34, 0x4c, 0x91, 0x2a, 0x6b,
+  0xa8, 0x8f, 0xe5, 0x51, 0xa2, 0x2f, 0x4e, 0x4f, 0xba, 0xca, 0x71, 0x29,
+  0x3e, 0x71, 0x1c, 0xfc, 0xfc, 0xe8, 0x42, 0x46, 0x87, 0x37, 0xbd, 0x27,
+  0xa2, 0x4a, 0x0f, 0x52, 0x48, 0x16, 0xeb, 0x8d, 0xa1, 0xd6, 0xd6, 0xdb,
+  0x89, 0x0a, 0x42, 0x81, 0x0a, 0x4a, 0xba, 0x82, 0x0f, 0x81, 0x07, 0xec,
+  0xa5, 0x17, 0x31, 0x1c, 0x26, 0xca, 0x91, 0x71, 0x9e, 0xdb, 0x48, 0x8d,
+  0x0c, 0x73, 0x36, 0x67, 0xcb, 0x52, 0xd8, 0x8c, 0x3d, 0x21, 0x2b, 0x57,
+  0x22, 0x40, 0xf0, 0x3e, 0x15, 0x55, 0xbf, 0x24, 0xf8, 0x78, 0x34, 0x5d,
+  0x2c, 0xf2, 0x32, 0x7e, 0x14, 0x5c, 0xec, 0x93, 0x16, 0xa9, 0x2e, 0xbf,
+  0x19, 0xe6, 0xa2, 0xc8, 0x74, 0xef, 0xb6, 0xe5, 0x24, 0xc7, 0x78, 0xfa,
+  0x49, 0xd3, 0x6a, 0x27, 0xc4, 0xee, 0x90, 0x7f, 0x06, 0x7b, 0xfa, 0xac,
+  0xee, 0x1e, 0x1c, 0x5c, 0x14, 0xa4, 0xb0, 0xa8, 0x2d, 0xde, 0xb1, 0xb5,
+  0xac, 0xec, 0x39, 0x01, 0xf1, 0xcc, 0xa6, 0x01, 0x3d, 0xea, 0x65, 0xc2,
+  0xa4, 0x7c, 0xde, 0x5f, 0x0a, 0x73, 0xb9, 0xe6, 0x17, 0x3c, 0x9a, 0x03,
+  0xf0, 0x78, 0x7d, 0x67, 0x93, 0x30, 0x3c, 0x92, 0xd2, 0x6f, 0x32, 0x47,
+  0x61, 0x09, 0xad, 0x82, 0x39, 0xd0, 0x55, 0xe7, 0xbb, 0xaf, 0xd4, 0x49,
+  0x1e, 0xba, 0x82, 0xe2, 0xa6, 0x0f, 0x2a, 0xd1, 0xc3, 0xfc, 0x76, 0xf3,
+  0x88, 0x23, 0xb7, 0xc8, 0x70, 0x26, 0xd1, 0x22, 0xdf, 0xe6, 0xf2, 0xaa,
+  0x63, 0x0d, 0xa0, 0x26, 0x43, 0x0a, 0xd7, 0xf5, 0x8d, 0x83, 0xd3, 0xf4,
+  0x80, 0xf4, 0xd1, 0xac, 0x12, 0x9e, 0x4b, 0x84, 0x51, 0x50, 0xf8, 0x6e,
+  0x45, 0x6c, 0xca, 0xf1, 0x6b, 0x6e, 0x47, 0x67, 0x7b, 0xb6, 0x81, 0x71,
+  0x8e, 0x99, 0x0c, 0xab, 0x5d, 0x74, 0xa1, 0xdc, 0x47, 0x82, 0x81, 0xe8,
+  0x47, 0x81, 0x06, 0xa6, 0x07, 0x75, 0x41, 0x21, 0x45, 0x14, 0x50, 0x08,
+  0x9c, 0x65, 0xf8, 0x96, 0x2f, 0xfb, 0x55, 0x6c, 0xfb, 0xf1, 0x4f, 0x74,
+  0x89, 0xc6, 0x5f, 0x89, 0x62, 0xff, 0x00, 0xb5, 0x56, 0xcf, 0xbf, 0x14,
+  0xf7, 0x40, 0x1e, 0x26, 0x8a, 0xf2, 0xa4, 0x82, 0x7a, 0xd1, 0x4c, 0x11,
+  0x94, 0x7a, 0xa4, 0xce, 0x38, 0xfc, 0x8f, 0x65, 0xdf, 0x44, 0x48, 0xfe,
+  0x03, 0x4e, 0x74, 0x99, 0xc7, 0x1f, 0x91, 0xec, 0xbb, 0xe8, 0x89, 0x1f,
+  0xc0, 0x68, 0x48, 0xdf, 0x1b, 0xe2, 0xed, 0xfc, 0xc1, 0xf6, 0x56, 0xca,
+  0xd7, 0x1b, 0xe2, 0xed, 0xfc, 0xc1, 0xf6, 0x56, 0xca, 0x00, 0xa8, 0xdc,
+  0xa2, 0xc9, 0x6e, 0xc8, 0xf1, 0xe9, 0xf6, 0x1b, 0xb3, 0x01, 0xf8, 0x37,
+  0x06, 0x17, 0x1d, 0xf6, 0xcf, 0x8a, 0x54, 0x34, 0x75, 0xe8, 0x23, 0xbc,
+  0x1f, 0x02, 0x05, 0x49, 0x50, 0x46, 0xe8, 0x0f, 0x98, 0x78, 0x35, 0x12,
+  0xe5, 0x6a, 0xbf, 0x5c, 0x71, 0xa9, 0x31, 0x5e, 0x93, 0x96, 0xe3, 0x4b,
+  0x6a, 0xd3, 0x3e, 0x40, 0x92, 0x1b, 0x4c, 0x8b, 0x5a, 0x52, 0xb7, 0x21,
+  0x4d, 0xe4, 0x57, 0xe5, 0x54, 0x01, 0x4b, 0x5b, 0x1d, 0x42, 0x4a, 0x7b,
+  0xf5, 0xd2, 0xea, 0xbe, 0x63, 0x16, 0x6c, 0xe6, 0x14, 0x2b, 0x84, 0x97,
+  0x26, 0x41, 0xb9, 0x45, 0x4a, 0x90, 0xc4, 0xe8, 0x2f, 0x76, 0x6f, 0xb4,
+  0x15, 0xae, 0x64, 0x83, 0xd5, 0x2a, 0x42, 0xb4, 0x0f, 0x2a, 0x82, 0x87,
+  0xab, 0x75, 0x5b, 0xfe, 0x14, 0x56, 0x24, 0x58, 0xe6, 0xc0, 0xe2, 0x9c,
+  0x78, 0x4b, 0x95, 0x12, 0x2b, 0x0a, 0xb4, 0xe5, 0x31, 0x5a, 0xe8, 0xa9,
+  0x76, 0xb7, 0xcf, 0x2a, 0x95, 0xd3, 0xbd, 0x4d, 0x28, 0xf3, 0x27, 0xd0,
+  0x48, 0x3e, 0x15, 0xd7, 0xc3, 0xec, 0xe2, 0x4d, 0x9b, 0x1a, 0xbd, 0x43,
+  0x9e, 0xfa, 0x27, 0xdc, 0xed, 0x2c, 0x37, 0xd9, 0xbe, 0x0e, 0xd1, 0x3d,
+  0x0e, 0x24, 0x2a, 0x24, 0x90, 0x7f, 0x45, 0xd4, 0xa9, 0x3c, 0xc7, 0xc1,
+  0x41, 0x60, 0xf7, 0x56, 0xf1, 0x7a, 0xa1, 0x8e, 0xab, 0x74, 0x63, 0x35,
+  0x89, 0xe7, 0xa3, 0xd9, 0x93, 0x33, 0xb8, 0x67, 0x8a, 0x42, 0x3e, 0xeb,
+  0xf1, 0x13, 0x25, 0x95, 0x7e, 0x65, 0xae, 0x8d, 0xb5, 0x73, 0x75, 0xb6,
+  0x22, 0x0d, 0x1d, 0x8d, 0xb0, 0xd8, 0x4a, 0x5d, 0x57, 0x41, 0xf0, 0xf9,
+  0xb6, 0x7b, 0x85, 0x4b, 0xff, 0x00, 0x29, 0x6e, 0x0e, 0x46, 0x6a, 0xdf,
+  0x88, 0x63, 0xed, 0x5b, 0xa1, 0x25, 0x01, 0x2c, 0x3b, 0x35, 0x82, 0xde,
+  0x93, 0xe1, 0xd9, 0xc5, 0x4e, 0x95, 0xad, 0x77, 0x73, 0x96, 0xfd, 0x84,
+  0x57, 0xa4, 0x5a, 0x62, 0xc1, 0x71, 0xe9, 0xf7, 0x29, 0x4d, 0xbd, 0x36,
+  0x1b, 0x7c, 0xf3, 0xaf, 0x52, 0x92, 0x14, 0xe3, 0x67, 0x5b, 0x28, 0x64,
+  0x11, 0xef, 0x69, 0xeb, 0xa0, 0x94, 0xf5, 0xf4, 0xec, 0x9d, 0x9e, 0xaf,
+  0x76, 0xcd, 0xa2, 0x3a, 0x1e, 0x8d, 0x8f, 0xad, 0xa6, 0x1d, 0x58, 0x4b,
+  0x66, 0x64, 0xa4, 0xb3, 0x26, 0x5a, 0xbf, 0x45, 0xa6, 0xc8, 0x25, 0x4a,
+  0xd0, 0xe8, 0x95, 0x14, 0x13, 0xd0, 0x55, 0x5a, 0x4b, 0x79, 0xee, 0xc9,
+  0x59, 0x7b, 0x43, 0x64, 0x29, 0xdd, 0xe2, 0x39, 0xee, 0xaa, 0xff, 0x00,
+  0x94, 0x88, 0xb8, 0xde, 0xa5, 0x44, 0x60, 0xcc, 0x71, 0x52, 0x92, 0x84,
+  0xb0, 0xc3, 0x69, 0x03, 0x65, 0xa6, 0xce, 0x9b, 0x2a, 0xea, 0x35, 0xa0,
+  0xa5, 0x6c, 0xe8, 0xa8, 0x1a, 0x67, 0xca, 0xd9, 0x66, 0xd2, 0x6c, 0x19,
+  0x33, 0x2b, 0x75, 0xd8, 0xd0, 0xa4, 0x28, 0x48, 0x52, 0x94, 0x4e, 0xda,
+  0x7d, 0x01, 0x1c, 0xe7, 0x7d, 0xc0, 0x1e, 0xcf, 0xd8, 0x37, 0x4c, 0xa1,
+  0x9b, 0x2e, 0x45, 0x0a, 0x15, 0xc1, 0x71, 0xa3, 0x4f, 0x8e, 0x42, 0x5f,
+  0x8c, 0xb7, 0x1b, 0xe6, 0xd6, 0xc7, 0x42, 0x37, 0xdd, 0xe1, 0xf5, 0x8f,
+  0x55, 0x73, 0xb1, 0x75, 0xc7, 0xb2, 0x36, 0xa4, 0xda, 0xdb, 0x9b, 0x1a,
+  0x62, 0x56, 0x1c, 0x61, 0xf8, 0xea, 0x24, 0x29, 0x40, 0x12, 0x85, 0x8e,
+  0x53, 0xa3, 0xae, 0xf1, 0xb1, 0xd3, 0xae, 0xf7, 0xdd, 0x51, 0xef, 0x1f,
+  0x1d, 0x0b, 0x7b, 0xb5, 0xf3, 0x35, 0x65, 0xad, 0x16, 0xf1, 0x07, 0xd3,
+  0x05, 0xa7, 0x54, 0xcb, 0x61, 0x0b, 0x5b, 0x4c, 0x13, 0xce, 0xe3, 0x01,
+  0x69, 0x53, 0x89, 0x4e, 0x8e, 0xf6, 0x50, 0x14, 0x06, 0xbb, 0xf7, 0xaa,
+  0x8f, 0x5e, 0x61, 0x8b, 0x5b, 0x61, 0x35, 0x16, 0xcd, 0xd9, 0xca, 0x5b,
+  0x9f, 0x90, 0x87, 0x01, 0xae, 0x65, 0xaf, 0xd8, 0x84, 0x8d, 0x8f, 0x6e,
+  0xb5, 0xe9, 0xae, 0x4c, 0x5a, 0xf6, 0xab, 0x03, 0xea, 0xc5, 0x6f, 0xcf,
+  0xab, 0xb6, 0x8a, 0x79, 0x22, 0xbe, 0xbe, 0x8a, 0x90, 0xcf, 0xe6, 0x2c,
+  0x0f, 0x1e, 0x9d, 0x0e, 0xbb, 0x94, 0x15, 0xe1, 0x5e, 0xae, 0x39, 0xde,
+  0x23, 0x64, 0x9c, 0xb8, 0x16, 0xe6, 0x0c, 0xfb, 0xb3, 0xbe, 0x71, 0x85,
+  0x6c, 0x8d, 0xda, 0x48, 0x70, 0xfa, 0x54, 0x94, 0x8d, 0x8f, 0x6a, 0xb4,
+  0x3d, 0x75, 0x3a, 0x1e, 0x73, 0x8c, 0x94, 0xd6, 0xb1, 0x8c, 0xe0, 0x9b,
+  0xc1, 0x21, 0x4f, 0x83, 0x8f, 0xa1, 0x8b, 0x83, 0x6d, 0xb0, 0xb2, 0xf3,
+  0xae, 0x37, 0x19, 0x27, 0x7d, 0x83, 0x6a, 0x59, 0x52, 0x5b, 0x27, 0xc7,
+  0x40, 0xeb, 0xd5, 0xdd, 0xd7, 0x5b, 0xa5, 0xb7, 0x33, 0x2c, 0x7b, 0x0f,
+  0xba, 0xdf, 0x20, 0x5c, 0x27, 0xb4, 0xdb, 0x1e, 0x54, 0x89, 0x11, 0x9a,
+  0x49, 0x2b, 0x5a, 0x94, 0xf2, 0x76, 0xb4, 0x21, 0x23, 0x65, 0x47, 0x9c,
+  0x29, 0x5a, 0x48, 0x27, 0xcf, 0xee, 0xa0, 0xc3, 0xe2, 0x0e, 0x57, 0xb3,
+  0x3a, 0x43, 0x78, 0x7d, 0xad, 0x47, 0x5d, 0x83, 0x1c, 0x92, 0x27, 0x38,
+  0x9f, 0x5a, 0xba, 0xb6, 0xd7, 0x4d, 0x78, 0x38, 0x7e, 0x6d, 0x6e, 0xb5,
+  0xc1, 0xc1, 0xb0, 0xc7, 0x1f, 0x55, 0xad, 0xa6, 0x27, 0x5f, 0x56, 0xb4,
+  0xb4, 0xe1, 0xf2, 0x84, 0xc8, 0xb8, 0x48, 0x5a, 0xb4, 0x90, 0x95, 0x29,
+  0x67, 0x98, 0x0e, 0x83, 0xa6, 0xc2, 0x40, 0xf0, 0x00, 0x55, 0x70, 0x97,
+  0x25, 0xd3, 0x6c, 0xd6, 0x9b, 0xd6, 0x7f, 0x92, 0x91, 0xee, 0x25, 0x8d,
+  0xbc, 0x76, 0x0a, 0xbb, 0xa6, 0x5e, 0x01, 0xed, 0x88, 0xf1, 0xe5, 0x8e,
+  0x93, 0xcd, 0xbf, 0x9e, 0x51, 0xec, 0xaf, 0x5f, 0xc8, 0x9b, 0x0d, 0xb9,
+  0xa5, 0xdf, 0xf3, 0x4b, 0x8b, 0xd9, 0x0c, 0x98, 0xa9, 0xed, 0x94, 0xfd,
+  0xcf, 0xce, 0x61, 0x92, 0x3c, 0x5b, 0x60, 0x0e, 0x40, 0x7c, 0x07, 0x45,
+  0x2b, 0x7d, 0xc4, 0x9a, 0xdd, 0x94, 0x5c, 0xf2, 0xf8, 0x56, 0xa5, 0x4b,
+  0x92, 0xc5, 0xba, 0x0c, 0x27, 0x56, 0xdb, 0x72, 0x1d, 0x8e, 0xea, 0x96,
+  0xf4, 0x06, 0x94, 0xb4, 0x85, 0x3a, 0x49, 0x01, 0x2b, 0xe5, 0x49, 0x3d,
+  0xc0, 0x68, 0xf5, 0xea, 0x07, 0x5d, 0x13, 0x2c, 0x38, 0xbd, 0xc9, 0x33,
+  0xa0, 0x59, 0xdc, 0x8c, 0x32, 0x0b, 0x7b, 0xe8, 0x70, 0x49, 0x92, 0xb5,
+  0x38, 0xf7, 0x6e, 0x8e, 0x57, 0x00, 0x75, 0x44, 0xf3, 0x29, 0xb3, 0xe6,
+  0xec, 0x77, 0x68, 0xf4, 0xd7, 0x4a, 0x8d, 0x4d, 0xf0, 0x4a, 0x8a, 0x5c,
+  0x9d, 0x97, 0xfc, 0x96, 0xfd, 0x0e, 0xc1, 0x26, 0xe5, 0x0f, 0x18, 0x71,
+  0x88, 0xa8, 0x48, 0x4a, 0x1c, 0x92, 0xf0, 0x0e, 0xb4, 0x0e, 0x87, 0x6a,
+  0xa6, 0x40, 0x3e, 0x62, 0x77, 0xcc, 0x41, 0x50, 0x56, 0x81, 0xe8, 0x3b,
+  0xab, 0x51, 0xb5, 0xc0, 0x98, 0x99, 0x5e, 0x45, 0x92, 0x4c, 0x7a, 0xfb,
+  0x15, 0x40, 0x26, 0x73, 0xb3, 0x09, 0x4a, 0x1e, 0xd0, 0x50, 0x4f, 0x66,
+  0x92, 0x1b, 0xe4, 0x3b, 0x00, 0xa4, 0x24, 0x74, 0x57, 0xac, 0x1a, 0x8f,
+  0xb4, 0x66, 0x37, 0x79, 0xee, 0xbe, 0xb5, 0xda, 0x44, 0xfb, 0x7c, 0xc8,
+  0xe8, 0x7d, 0x88, 0xe1, 0x87, 0x52, 0xe2, 0x02, 0xdb, 0x4e, 0xda, 0x59,
+  0x5a, 0x03, 0x3d, 0x9e, 0xf9, 0x8f, 0x69, 0xcf, 0xd4, 0x1f, 0x83, 0x50,
+  0x36, 0x9b, 0x6d, 0xbe, 0x3a, 0xa2, 0xa6, 0xdf, 0x7f, 0x85, 0x72, 0xbd,
+  0xba, 0xc3, 0x70, 0xd4, 0xd5, 0xa8, 0x36, 0x99, 0x0e, 0x04, 0xa3, 0xb8,
+  0xbe, 0x49, 0xf7, 0xb4, 0x84, 0xeb, 0xb5, 0xe5, 0xe7, 0x00, 0x00, 0x15,
+  0xbd, 0x26, 0xa3, 0x65, 0xc9, 0x3b, 0xbe, 0x0e, 0x1e, 0x0a, 0xdc, 0xc6,
+  0x23, 0x9f, 0xc9, 0xc2, 0xd6, 0xd7, 0x93, 0x58, 0xf2, 0x64, 0xbd, 0x79,
+  0xc7, 0xdb, 0xdf, 0x9b, 0x19, 0xf0, 0xa2, 0x26, 0xc2, 0x1e, 0x1a, 0x4b,
+  0x9b, 0x71, 0x3a, 0xd7, 0x9a, 0xaf, 0xee, 0xbd, 0x53, 0xdc, 0x2a, 0x92,
+  0xe3, 0x1e, 0x31, 0x90, 0xbb, 0x86, 0x5b, 0x1a, 0x81, 0x12, 0xd5, 0x0a,
+  0xe3, 0x68, 0x94, 0x89, 0x58, 0xf3, 0xf0, 0xb9, 0xcf, 0x92, 0x4c, 0x47,
+  0xe4, 0xda, 0x71, 0x4b, 0xea, 0xb4, 0x3c, 0x36, 0xd9, 0x3e, 0x6e, 0xd4,
+  0xb4, 0xec, 0x1d, 0xee, 0xac, 0x6e, 0x16, 0xe6, 0x50, 0x73, 0xcc, 0x12,
+  0xdb, 0x93, 0xc0, 0x41, 0x64, 0x49, 0x6f, 0x4f, 0xc7, 0x51, 0xf3, 0xe3,
+  0xbe, 0x93, 0xca, 0xe3, 0x4a, 0x1e, 0x05, 0x2a, 0x04, 0x75, 0xf0, 0xd1,
+  0xf1, 0xa8, 0x24, 0x68, 0xa2, 0x81, 0xdd, 0x45, 0x00, 0x89, 0xc6, 0x5f,
+  0x89, 0x62, 0xff, 0x00, 0xb5, 0x56, 0xcf, 0xbf, 0x14, 0xf7, 0x48, 0x9c,
+  0x65, 0xf8, 0x96, 0x2f, 0xfb, 0x55, 0x6c, 0xfb, 0xf1, 0x4f, 0x74, 0x07,
+  0x95, 0x10, 0x0f, 0x52, 0x07, 0xb6, 0x8a, 0xc9, 0x1d, 0x68, 0xa8, 0x18,
+  0x46, 0x69, 0x33, 0x8e, 0x3f, 0x23, 0xd9, 0x77, 0xd1, 0x12, 0x3f, 0x80,
+  0xd3, 0x9d, 0x26, 0x71, 0xc7, 0xe4, 0x7b, 0x2e, 0xfa, 0x22, 0x47, 0xf0,
+  0x1a, 0x90, 0x37, 0xc6, 0xf8, 0xbb, 0x7f, 0x30, 0x7d, 0x95, 0xb2, 0xb5,
+  0xc6, 0xf8, 0xbb, 0x7f, 0x30, 0x7d, 0x95, 0xb2, 0x80, 0x28, 0xa2, 0x8a,
+  0x03, 0x96, 0xe9, 0x0a, 0x2d, 0xca, 0xdf, 0x26, 0xdf, 0x39, 0x86, 0xe4,
+  0x45, 0x94, 0xd2, 0x99, 0x7d, 0xa5, 0x8d, 0xa5, 0xc4, 0x28, 0x10, 0xa4,
+  0x91, 0xe8, 0x20, 0x9a, 0xf8, 0xda, 0xe3, 0x06, 0xe1, 0x84, 0xca, 0xbd,
+  0xe2, 0x73, 0x24, 0x2f, 0xb4, 0xc5, 0xd8, 0x54, 0x54, 0xba, 0xb5, 0x12,
+  0x5e, 0xb1, 0x49, 0x73, 0x9e, 0x24, 0x8d, 0xf8, 0xf9, 0x2c, 0x92, 0x02,
+  0xbf, 0x55, 0xc5, 0x78, 0x26, 0xbe, 0xd3, 0xd5, 0x52, 0xff, 0x00, 0x84,
+  0xee, 0x3e, 0xfc, 0x7b, 0x7c, 0x0e, 0x26, 0x5a, 0x20, 0x26, 0x74, 0xfc,
+  0x68, 0x38, 0x9b, 0x8c, 0x32, 0x9e, 0x61, 0x70, 0xb5, 0x3a, 0x39, 0x65,
+  0x30, 0xa1, 0xe3, 0xe6, 0x92, 0xa1, 0xbe, 0xef, 0x38, 0xd4, 0xa7, 0x87,
+  0x92, 0x1a, 0xca, 0xc0, 0xd9, 0x8f, 0x4c, 0x63, 0x39, 0xc0, 0x24, 0xbd,
+  0x09, 0xc1, 0x1d, 0xeb, 0x83, 0x45, 0x44, 0xf7, 0x86, 0x24, 0x00, 0x02,
+  0x90, 0xaf, 0x5a, 0x1c, 0x49, 0x04, 0x7a, 0x3d, 0xbb, 0xa8, 0x35, 0xe3,
+  0xf7, 0x97, 0xef, 0x82, 0x5a, 0xec, 0x97, 0x17, 0xee, 0x4b, 0x5f, 0x94,
+  0x11, 0x2e, 0x7e, 0xed, 0xd1, 0x5d, 0x56, 0x8a, 0x96, 0x00, 0xf3, 0x97,
+  0xa2, 0x94, 0xe9, 0x1d, 0x7a, 0x01, 0xbd, 0x68, 0x6a, 0xbd, 0xe0, 0x62,
+  0xe7, 0x40, 0x99, 0x2e, 0xd9, 0x88, 0xdf, 0x18, 0x2f, 0xc6, 0xec, 0x96,
+  0xc3, 0x53, 0xb9, 0x95, 0x16, 0xef, 0x6f, 0x75, 0x3c, 0xd0, 0xe4, 0x12,
+  0x9f, 0x39, 0xb7, 0x83, 0x7e, 0xf4, 0xa7, 0x12, 0x0f, 0x9c, 0xce, 0x94,
+  0x09, 0xd6, 0xad, 0xe7, 0xa4, 0x71, 0x56, 0x6a, 0xfb, 0x36, 0xad, 0x18,
+  0xa5, 0xa9, 0x24, 0xf5, 0x7d, 0x77, 0x17, 0xa4, 0x94, 0x8f, 0x48, 0x40,
+  0x65, 0x1c, 0xc7, 0xda, 0xa4, 0xee, 0xb4, 0x97, 0x39, 0x7d, 0x4c, 0xa3,
+  0xc6, 0x17, 0x41, 0xaa, 0xdb, 0x1e, 0x2d, 0xa2, 0xd4, 0xdc, 0x65, 0xba,
+  0xda, 0x52, 0x9e, 0x75, 0x2d, 0x4a, 0x3c, 0xa9, 0x2a, 0x51, 0x2a, 0x5a,
+  0xb4, 0x4f, 0x40, 0x4a, 0x94, 0x75, 0xe1, 0xba, 0xae, 0x63, 0xdd, 0xf1,
+  0x96, 0xaf, 0x32, 0x15, 0x83, 0xd8, 0xe6, 0xe5, 0x77, 0x30, 0xf1, 0x2d,
+  0xba, 0xcf, 0x9d, 0x16, 0x0a, 0xb9, 0x74, 0xa4, 0x26, 0x42, 0xf4, 0x96,
+  0xd2, 0x76, 0x49, 0x4a, 0x49, 0x3b, 0x27, 0xa7, 0x85, 0x48, 0xdc, 0xb0,
+  0xfb, 0x5b, 0x4d, 0x0b, 0x8f, 0x10, 0xf2, 0x49, 0x57, 0xd4, 0x95, 0x84,
+  0x88, 0xee, 0x0e, 0xc2, 0x22, 0xd5, 0xde, 0x12, 0x23, 0xb7, 0xb2, 0xe9,
+  0xef, 0xf3, 0x54, 0x57, 0xbf, 0x01, 0x52, 0x3f, 0xca, 0x44, 0xf6, 0xf0,
+  0xf1, 0xbb, 0x05, 0xad, 0xcb, 0x5c, 0x97, 0x50, 0xa5, 0x23, 0xcb, 0x60,
+  0xa9, 0xa6, 0x63, 0xc6, 0x40, 0xf3, 0x9d, 0x08, 0x1a, 0x0a, 0x1b, 0x29,
+  0x48, 0x4e, 0xd2, 0x76, 0xa1, 0xbd, 0x78, 0xd3, 0xba, 0xbd, 0x4d, 0x31,
+  0x26, 0x45, 0x4e, 0xc3, 0x2e, 0xd9, 0x34, 0x65, 0x4a, 0xe2, 0x4d, 0xf6,
+  0x3b, 0x76, 0xe4, 0x12, 0xb3, 0x6c, 0xb7, 0x9e, 0xcd, 0x84, 0x27, 0xd0,
+  0xe4, 0x85, 0x0e, 0xd1, 0x5d, 0x3b, 0xca, 0x7b, 0x31, 0xed, 0xef, 0x3d,
+  0xb6, 0x6b, 0xbe, 0x19, 0x8f, 0x43, 0x62, 0xcb, 0x85, 0xdb, 0x61, 0xf6,
+  0xd2, 0x57, 0xd9, 0xc5, 0x89, 0x15, 0xae, 0xc1, 0x32, 0x08, 0x07, 0x6b,
+  0xed, 0x0a, 0x74, 0xb4, 0xa4, 0x02, 0x54, 0xb1, 0xcc, 0x40, 0x1e, 0x24,
+  0xea, 0x8c, 0x8e, 0xdb, 0x2e, 0x0c, 0xbb, 0x44, 0xeb, 0xcd, 0xdd, 0xfb,
+  0xbd, 0x99, 0x12, 0xd2, 0x27, 0x35, 0x21, 0xa6, 0x92, 0x84, 0x2d, 0x63,
+  0x91, 0xa7, 0x00, 0x4a, 0x53, 0xef, 0x69, 0x5a, 0x86, 0xc1, 0x27, 0x5d,
+  0x0f, 0x81, 0xdf, 0x1e, 0x53, 0x95, 0x44, 0xb8, 0x40, 0x76, 0x33, 0x31,
+  0xa6, 0xb1, 0x90, 0xdb, 0x66, 0x03, 0x09, 0xa5, 0xc7, 0x5b, 0x6e, 0x29,
+  0xe0, 0xa2, 0x11, 0xca, 0x08, 0x1c, 0xe8, 0x71, 0x3c, 0xc0, 0x94, 0xed,
+  0x3c, 0xaa, 0x3d, 0x7c, 0x43, 0x79, 0x0d, 0xa2, 0x75, 0xe5, 0x09, 0xc9,
+  0x9a, 0x89, 0x0d, 0xdb, 0xe4, 0xf8, 0x66, 0xce, 0xf4, 0x94, 0x22, 0xe8,
+  0x88, 0x0d, 0xad, 0xb5, 0xb0, 0xc9, 0xd8, 0x1a, 0x70, 0xaf, 0x6a, 0x6c,
+  0xa8, 0xa4, 0x2c, 0xe9, 0x27, 0x97, 0x64, 0x68, 0x6e, 0xb9, 0xae, 0x93,
+  0x71, 0x69, 0xf8, 0x9c, 0x89, 0xd6, 0x01, 0x12, 0x14, 0x8b, 0x13, 0x8e,
+  0x48, 0x8e, 0x52, 0xc0, 0x40, 0x8a, 0xfb, 0x64, 0x82, 0x85, 0x80, 0x07,
+  0x2f, 0x3e, 0x8a, 0x0a, 0x4f, 0x52, 0x15, 0xd0, 0x6f, 0xbb, 0x86, 0xea,
+  0xac, 0x95, 0x84, 0x5c, 0x2d, 0xd7, 0x69, 0x66, 0x34, 0x2b, 0xa2, 0xdd,
+  0x69, 0x84, 0x3e, 0xda, 0x1d, 0x7d, 0x28, 0x73, 0x7c, 0xe8, 0x69, 0xb6,
+  0x4a, 0x94, 0xf9, 0x01, 0x5e, 0x6a, 0x94, 0x11, 0xcb, 0xd3, 0x98, 0x2a,
+  0xb3, 0x1e, 0x1d, 0xae, 0x45, 0xfb, 0xc8, 0xa0, 0x44, 0x99, 0x6d, 0x7d,
+  0x96, 0xd3, 0x31, 0xf7, 0xef, 0x21, 0x6e, 0x96, 0x93, 0xbe, 0x46, 0xd4,
+  0xd2, 0x16, 0xa2, 0x85, 0x2c, 0xe8, 0x80, 0xb3, 0xcd, 0xc9, 0xa0, 0x35,
+  0xd4, 0x0a, 0x61, 0x2f, 0x52, 0x77, 0x61, 0x75, 0xbc, 0x65, 0x2b, 0x5d,
+  0xd3, 0xca, 0x9b, 0x44, 0x3b, 0x2c, 0xb6, 0x88, 0x6f, 0xdd, 0x56, 0x92,
+  0xc8, 0x8c, 0xb5, 0xa3, 0x45, 0x2a, 0x5f, 0x31, 0xed, 0x53, 0xde, 0x52,
+  0x84, 0x27, 0x98, 0x95, 0x00, 0x48, 0xd1, 0xad, 0x46, 0xd9, 0x69, 0x97,
+  0x39, 0x8b, 0x55, 0xad, 0xe9, 0x97, 0x5b, 0x9b, 0xd1, 0x42, 0x5c, 0x6e,
+  0xe0, 0xc9, 0x88, 0x83, 0x1d, 0xb4, 0x80, 0x16, 0xf2, 0x83, 0x49, 0x79,
+  0xe6, 0xb9, 0x88, 0xd2, 0x0a, 0x94, 0x92, 0x49, 0x04, 0xe8, 0x13, 0x5d,
+  0xf9, 0x63, 0xb3, 0x31, 0x0b, 0x94, 0x4c, 0x8e, 0x52, 0xee, 0x39, 0x2c,
+  0x34, 0x32, 0xb6, 0x63, 0xb6, 0xe2, 0x5a, 0x2e, 0xb0, 0xfa, 0x88, 0x25,
+  0x69, 0xe5, 0x4a, 0x76, 0x14, 0x84, 0xab, 0x43, 0x5b, 0xd8, 0xe5, 0x1f,
+  0x0c, 0x01, 0x9c, 0x9e, 0xe9, 0x6e, 0xca, 0xd8, 0xb6, 0x2b, 0x1e, 0x91,
+  0x2d, 0x37, 0x49, 0x0a, 0x53, 0x29, 0xec, 0x42, 0x98, 0x7d, 0x31, 0x5c,
+  0x1c, 0xae, 0xa9, 0x5b, 0x4e, 0xdb, 0x48, 0xe8, 0xa0, 0xa5, 0x27, 0xe1,
+  0xa1, 0x3a, 0x07, 0xb8, 0xc6, 0xfd, 0x42, 0xc6, 0x76, 0x3d, 0x64, 0xb1,
+  0xe7, 0x5a, 0x97, 0x6b, 0x39, 0x1c, 0x86, 0x6e, 0x78, 0xf2, 0x0a, 0xca,
+  0xe3, 0x46, 0x83, 0xc8, 0x90, 0xf2, 0x53, 0xef, 0x2d, 0xf2, 0x02, 0x79,
+  0x9b, 0x24, 0x10, 0x90, 0x7f, 0x3f, 0x90, 0x75, 0xde, 0x86, 0xcc, 0xc2,
+  0xe3, 0x68, 0xbb, 0xe1, 0xd0, 0x32, 0x4b, 0x1c, 0x94, 0xa2, 0x53, 0x0b,
+  0x47, 0xb9, 0x6e, 0xb2, 0x00, 0x52, 0xcb, 0xba, 0x4a, 0x99, 0x6f, 0xa6,
+  0x94, 0x54, 0x9d, 0x8d, 0x0e, 0xe2, 0x90, 0x7f, 0x36, 0xb8, 0x15, 0xee,
+  0xd0, 0xb6, 0x44, 0xc7, 0xf2, 0x89, 0x6e, 0x2c, 0x95, 0x36, 0xeb, 0xad,
+  0x36, 0x80, 0xf4, 0xd9, 0x49, 0x6d, 0x61, 0x49, 0x09, 0x6d, 0x91, 0xca,
+  0xda, 0x76, 0x9d, 0x15, 0x92, 0x77, 0xa3, 0xd1, 0x35, 0xd7, 0x60, 0xb7,
+  0xc4, 0xb9, 0xde, 0x64, 0x2e, 0xc0, 0xc3, 0xb6, 0x56, 0xe0, 0x14, 0xc7,
+  0x7a, 0x4c, 0xb6, 0xd4, 0xec, 0xd4, 0xb8, 0xa4, 0xf3, 0x29, 0xa6, 0xbb,
+  0x62, 0xa0, 0xd2, 0x42, 0x54, 0x36, 0x40, 0x21, 0x5b, 0xe9, 0xd0, 0x6c,
+  0xb6, 0x5c, 0x05, 0x97, 0xc9, 0xcf, 0x70, 0x99, 0x7b, 0x7b, 0x11, 0x36,
+  0x5c, 0x91, 0xf4, 0xc6, 0x0f, 0x28, 0x33, 0x26, 0xe5, 0x35, 0x86, 0xe3,
+  0x02, 0x90, 0xa1, 0xd1, 0x96, 0x50, 0xe2, 0xd4, 0xb7, 0x48, 0x1b, 0x04,
+  0x10, 0x90, 0x41, 0x23, 0xc0, 0x52, 0xde, 0x39, 0x78, 0xb7, 0xe1, 0x7c,
+  0x74, 0x90, 0xc4, 0x09, 0x04, 0xe2, 0xd9, 0xd3, 0xca, 0x5a, 0x02, 0x90,
+  0xa4, 0x08, 0x77, 0x94, 0x24, 0x17, 0x10, 0x52, 0xad, 0x29, 0x3d, 0xb3,
+  0x7a, 0x5f, 0x51, 0xd5, 0x43, 0xa7, 0x4a, 0x6d, 0x9c, 0x6e, 0x18, 0xbe,
+  0x47, 0x32, 0x53, 0xd1, 0x65, 0xe4, 0xd2, 0x9c, 0x8a, 0x85, 0xda, 0x82,
+  0x8b, 0x61, 0xfe, 0xc5, 0xb5, 0x7f, 0x38, 0x69, 0x04, 0x04, 0x82, 0xe0,
+  0x0b, 0xe7, 0x1d, 0x01, 0x58, 0xd2, 0x76, 0x4a, 0x77, 0x4b, 0xfc, 0x51,
+  0xb1, 0x46, 0xe2, 0x4c, 0x66, 0xad, 0xb6, 0xc4, 0x49, 0xb7, 0xde, 0x25,
+  0xc5, 0x53, 0xea, 0xed, 0x11, 0xca, 0xec, 0x07, 0x99, 0xdb, 0x91, 0x24,
+  0x38, 0x01, 0xf3, 0x16, 0x1c, 0xf3, 0x40, 0xef, 0x52, 0x1d, 0x5f, 0x78,
+  0x1d, 0x0f, 0x7d, 0xc2, 0xc7, 0x05, 0xcc, 0x93, 0xb1, 0xba, 0xcd, 0x23,
+  0xf0, 0x57, 0x34, 0x73, 0x36, 0xc1, 0x63, 0xcf, 0x9e, 0xcf, 0x92, 0xde,
+  0xa1, 0x2d, 0x50, 0x2f, 0x31, 0x08, 0xd2, 0x98, 0x9a, 0xd1, 0xe5, 0x71,
+  0x24, 0x78, 0x02, 0x7c, 0xe1, 0xea, 0x50, 0xf4, 0x53, 0xc0, 0xa8, 0x24,
+  0x44, 0xe3, 0x2f, 0xc4, 0xb1, 0x7f, 0xda, 0xab, 0x67, 0xdf, 0x8a, 0x7b,
+  0xa4, 0x4e, 0x32, 0xfc, 0x4b, 0x17, 0xfd, 0xaa, 0xb6, 0x7d, 0xf8, 0xa7,
+  0xba, 0x00, 0xa2, 0x8a, 0x28, 0x02, 0x93, 0x38, 0xe3, 0xf2, 0x3d, 0x97,
+  0x7d, 0x11, 0x23, 0xf8, 0x0d, 0x39, 0xd2, 0x67, 0x1c, 0x7e, 0x47, 0xb2,
+  0xef, 0xa2, 0x24, 0x7f, 0x01, 0xa0, 0x1b, 0xe3, 0x7c, 0x5d, 0xbf, 0x98,
+  0x3e, 0xca, 0xd9, 0x5a, 0xe3, 0x7c, 0x5d, 0xbf, 0x98, 0x3e, 0xca, 0xd9,
+  0x40, 0x14, 0x51, 0x45, 0x00, 0x56, 0xb9, 0x0d, 0xb4, 0xfb, 0x4e, 0x32,
+  0xf3, 0x68, 0x75, 0xb7, 0x12, 0x52, 0xb4, 0x28, 0x6c, 0x28, 0x11, 0xd4,
+  0x11, 0xe8, 0x22, 0xb6, 0x50, 0x46, 0xe8, 0x0f, 0x8d, 0xe5, 0x43, 0x93,
+  0xc2, 0x6e, 0x21, 0xcb, 0xb4, 0x27, 0xb7, 0xec, 0xf1, 0xc4, 0xae, 0x75,
+  0xb1, 0x5d, 0x49, 0x99, 0x8f, 0xbe, 0xef, 0x33, 0xec, 0x8e, 0xed, 0xae,
+  0x2b, 0xa7, 0xb6, 0x1f, 0xaa, 0x1d, 0xf0, 0xd5, 0x7d, 0x29, 0x22, 0xf4,
+  0xed, 0xd8, 0x5a, 0x62, 0xc4, 0xbb, 0xa2, 0xdf, 0x1e, 0x63, 0x2b, 0x71,
+  0xf9, 0x6d, 0xf2, 0xa9, 0x6a, 0xd1, 0x6d, 0x29, 0x43, 0x65, 0x5b, 0x00,
+  0xab, 0xb4, 0x07, 0x98, 0x82, 0x75, 0xad, 0x75, 0x3b, 0x0b, 0x5f, 0x84,
+  0xc6, 0x29, 0x2e, 0xed, 0x89, 0xc7, 0xcb, 0x2c, 0x31, 0x9b, 0x7b, 0x23,
+  0xc5, 0x5c, 0x55, 0xc2, 0x23, 0x6b, 0x40, 0x50, 0x94, 0xc7, 0x2e, 0xa4,
+  0x46, 0x50, 0xf1, 0x43, 0x8d, 0xf3, 0x02, 0x9f, 0x1d, 0x6b, 0xc6, 0xab,
+  0xbe, 0x0f, 0x3f, 0x65, 0xc8, 0xac, 0xab, 0xc1, 0x9e, 0x90, 0xe2, 0xed,
+  0x6a, 0x8e, 0xdd, 0xc7, 0x1e, 0x92, 0xb5, 0xed, 0xc1, 0x01, 0xd5, 0x1e,
+  0xcd, 0x25, 0x43, 0x47, 0x99, 0x87, 0x02, 0x98, 0x5e, 0x88, 0x20, 0xa1,
+  0x27, 0x7d, 0xc6, 0xb5, 0x87, 0x7a, 0x3a, 0x4c, 0xa7, 0xdd, 0x96, 0xaf,
+  0xcc, 0xb5, 0xf3, 0x08, 0xa7, 0x0b, 0x76, 0x26, 0x59, 0x1d, 0x37, 0x0b,
+  0xac, 0x78, 0xad, 0xad, 0x87, 0xe3, 0x48, 0x96, 0xb7, 0x8a, 0x14, 0xe1,
+  0x48, 0x4b, 0xc8, 0x2e, 0x12, 0x42, 0xb6, 0x02, 0x08, 0x04, 0x0d, 0x2f,
+  0x7a, 0x1a, 0x3b, 0xf5, 0x93, 0xdd, 0x6d, 0x19, 0x44, 0x68, 0x11, 0xec,
+  0xaa, 0x71, 0xfb, 0xa0, 0x79, 0xb5, 0x32, 0x1a, 0x0a, 0x4a, 0x98, 0x69,
+  0x7a, 0x4b, 0xa5, 0xc2, 0x9e, 0xad, 0xa0, 0xb4, 0xa5, 0x8e, 0xba, 0x24,
+  0x81, 0xad, 0x90, 0x35, 0xc9, 0x0a, 0xc9, 0x72, 0x6a, 0x5a, 0x2c, 0xad,
+  0xca, 0x7a, 0xfc, 0x6d, 0xa5, 0x0b, 0x59, 0x94, 0xe2, 0x9a, 0x8a, 0xd3,
+  0x9a, 0xe6, 0x41, 0x74, 0xa8, 0xad, 0xc7, 0xdc, 0xd6, 0x94, 0x13, 0xbe,
+  0x51, 0xb0, 0x4e, 0x8e, 0xb5, 0xee, 0x0a, 0x2d, 0xe6, 0xf5, 0x22, 0xd3,
+  0x96, 0x08, 0x76, 0xce, 0x49, 0x0d, 0x31, 0x0a, 0xd9, 0x11, 0xc2, 0xd4,
+  0x59, 0x5c, 0xe8, 0x2a, 0x0e, 0xe8, 0x04, 0x95, 0x95, 0x14, 0x38, 0x9e,
+  0x53, 0xb0, 0x9e, 0xcc, 0x8e, 0xbb, 0xd9, 0xcf, 0x2b, 0x84, 0x69, 0xbf,
+  0x2c, 0xe7, 0x72, 0xdf, 0x77, 0x65, 0x11, 0xb1, 0xdb, 0xc2, 0x9c, 0xba,
+  0x3e, 0x5b, 0x42, 0x9f, 0x62, 0x22, 0xbb, 0x67, 0xe5, 0x34, 0x95, 0x12,
+  0x90, 0xeb, 0xab, 0x4b, 0x6d, 0xb2, 0xd9, 0x29, 0x00, 0xe8, 0x6d, 0x5a,
+  0x3a, 0x3d, 0xf5, 0xd1, 0x6f, 0x66, 0x12, 0xf2, 0x09, 0x76, 0xf5, 0x5b,
+  0x93, 0x88, 0x88, 0xec, 0xb6, 0xb9, 0x09, 0x8d, 0xd9, 0x87, 0xe5, 0x17,
+  0x56, 0xae, 0x50, 0xdb, 0xa9, 0xea, 0x1a, 0xf3, 0x34, 0x79, 0x79, 0x4f,
+  0x31, 0xd6, 0xc6, 0xba, 0xe9, 0xbf, 0x2d, 0x78, 0x54, 0xe9, 0x0e, 0x63,
+  0x22, 0x0a, 0x18, 0xba, 0x21, 0x12, 0x5a, 0x43, 0xc5, 0x7d, 0x92, 0x0b,
+  0x2b, 0x42, 0x5d, 0x68, 0x29, 0x29, 0x57, 0x66, 0x85, 0x25, 0xcd, 0xa5,
+  0x5a, 0x29, 0x42, 0x81, 0xd8, 0x00, 0xf4, 0x32, 0x26, 0x1a, 0xce, 0x13,
+  0x01, 0xe9, 0x2d, 0xb5, 0x02, 0x23, 0x1c, 0xe1, 0xdb, 0x83, 0xe9, 0x53,
+  0x4d, 0xad, 0x4a, 0xe5, 0x28, 0x6d, 0xad, 0xa9, 0x0a, 0x59, 0x0b, 0x4a,
+  0x55, 0xce, 0x92, 0x91, 0xe6, 0x8e, 0x52, 0x77, 0x53, 0xcf, 0x21, 0x7a,
+  0x1b, 0x72, 0x36, 0x64, 0xe1, 0x73, 0xdd, 0xba, 0x59, 0x48, 0x96, 0x99,
+  0x90, 0xcc, 0x78, 0x88, 0x9f, 0x35, 0x4a, 0x4c, 0x77, 0x9b, 0x25, 0xd5,
+  0x36, 0x97, 0x1c, 0x3d, 0x03, 0x88, 0x0b, 0xd6, 0xce, 0x82, 0xd0, 0x91,
+  0xd0, 0x1e, 0x9a, 0x72, 0x67, 0xd9, 0xcf, 0x1a, 0x83, 0x12, 0x04, 0x1e,
+  0x69, 0x6b, 0x49, 0x4c, 0xa1, 0xdb, 0x10, 0x18, 0x8e, 0xb4, 0x12, 0xa4,
+  0x3c, 0xb4, 0x6c, 0x21, 0x5c, 0xe9, 0x6d, 0x49, 0x48, 0x25, 0x41, 0x48,
+  0x0a, 0xd6, 0x87, 0x5e, 0xeb, 0x5c, 0x2b, 0x8c, 0x9b, 0x82, 0x9e, 0x87,
+  0x1d, 0xab, 0xc1, 0x82, 0xa7, 0x18, 0x44, 0x89, 0x4a, 0xf2, 0x58, 0x2d,
+  0x2f, 0x5c, 0xae, 0x06, 0x9a, 0x48, 0x52, 0x9c, 0x57, 0x52, 0x92, 0xb5,
+  0x6f, 0xf3, 0x82, 0x4f, 0x78, 0xad, 0x56, 0x85, 0xda, 0x2e, 0x4b, 0x2c,
+  0xe4, 0xea, 0x4c, 0x17, 0x55, 0x31, 0xf8, 0x91, 0xec, 0xa8, 0x7f, 0xb3,
+  0x8e, 0xc1, 0x6b, 0x44, 0xec, 0x23, 0x41, 0xc2, 0x52, 0x52, 0xbe, 0x65,
+  0x7e, 0x6a, 0xc6, 0x80, 0xa8, 0xf4, 0x43, 0x18, 0xdd, 0x9e, 0x11, 0x1e,
+  0x43, 0x92, 0x23, 0x59, 0x27, 0x34, 0xe5, 0xe0, 0x5b, 0x56, 0x97, 0x15,
+  0x02, 0x17, 0xbe, 0x6d, 0xc0, 0x9f, 0x35, 0x72, 0xa4, 0x3a, 0x10, 0x92,
+  0xad, 0x1e, 0x60, 0x80, 0x12, 0x49, 0xd1, 0xea, 0x3a, 0x57, 0x45, 0x85,
+  0x16, 0xfb, 0x83, 0xaf, 0xb6, 0xe1, 0x56, 0x35, 0x08, 0x4f, 0x30, 0xda,
+  0xb5, 0x45, 0xe4, 0x88, 0xe3, 0xaf, 0x21, 0x1c, 0xca, 0xed, 0x16, 0xd9,
+  0xd9, 0x24, 0x12, 0x52, 0x10, 0xa0, 0x39, 0x00, 0x3e, 0x76, 0xfa, 0x46,
+  0x48, 0xbb, 0xcb, 0xc2, 0x2e, 0x09, 0xb5, 0xdb, 0x5c, 0x81, 0x22, 0x02,
+  0xe5, 0x19, 0xc9, 0x12, 0xa5, 0x76, 0x6b, 0x7a, 0x3b, 0xdc, 0xc1, 0x49,
+  0xed, 0x57, 0xb1, 0xce, 0xda, 0xd3, 0xd0, 0x28, 0xf9, 0xe8, 0x20, 0x03,
+  0xb4, 0x9a, 0xd3, 0x92, 0xa6, 0xdd, 0x7e, 0x9a, 0xf5, 0xc6, 0xe8, 0x20,
+  0x43, 0xb7, 0x4a, 0x69, 0xa4, 0xa5, 0xb9, 0xb0, 0x9c, 0x71, 0x73, 0x9e,
+  0x6d, 0x4b, 0xe5, 0x75, 0x96, 0x92, 0xa4, 0xbd, 0xb4, 0xa5, 0x5a, 0x0b,
+  0x1a, 0x2a, 0xde, 0x80, 0x29, 0xd1, 0xa9, 0xf5, 0x61, 0x3e, 0x88, 0x90,
+  0x7e, 0x65, 0xc3, 0x0d, 0xbb, 0xdc, 0x59, 0x86, 0xca, 0x2f, 0x0e, 0xca,
+  0x71, 0xb9, 0x6d, 0x2a, 0x54, 0xb0, 0x97, 0xde, 0x8a, 0x90, 0x1b, 0x53,
+  0x08, 0x5a, 0xf4, 0x14, 0xe3, 0x6a, 0x01, 0x40, 0x28, 0xf9, 0xc9, 0x5f,
+  0x53, 0xbe, 0xfe, 0x6b, 0xec, 0x37, 0x33, 0x5b, 0xda, 0x24, 0x58, 0x5b,
+  0x7e, 0x32, 0xd2, 0xca, 0x57, 0x2e, 0x43, 0x72, 0x43, 0x69, 0x6d, 0xf6,
+  0xd6, 0x92, 0xc8, 0x0e, 0xa5, 0x2b, 0x47, 0x6c, 0x02, 0x9d, 0x49, 0xd0,
+  0x58, 0x01, 0x5a, 0x3f, 0x9b, 0xae, 0xeb, 0x65, 0xb6, 0xec, 0x51, 0x22,
+  0x6f, 0xf2, 0x69, 0x37, 0x2e, 0x66, 0x12, 0x82, 0x6e, 0xce, 0xa1, 0x82,
+  0xe3, 0x60, 0xf3, 0x76, 0x4c, 0xb0, 0x94, 0xa8, 0x36, 0x36, 0x01, 0xf3,
+  0xc8, 0x24, 0xeb, 0x98, 0x9d, 0x74, 0xf3, 0x61, 0x56, 0x35, 0x77, 0x66,
+  0xdc, 0x9b, 0xf4, 0xe5, 0xbd, 0x71, 0x9b, 0x0d, 0x52, 0xd9, 0x88, 0x1d,
+  0x5b, 0x4c, 0xc4, 0x6c, 0x1e, 0x55, 0x21, 0xb4, 0x20, 0x84, 0xa4, 0xb6,
+  0x4f, 0x29, 0x3d, 0x55, 0xb4, 0xf7, 0xd1, 0x79, 0x24, 0x1e, 0xdb, 0xb3,
+  0xc3, 0x71, 0xdd, 0xb9, 0xcd, 0xd4, 0xfb, 0x5b, 0x99, 0x2f, 0x90, 0xa5,
+  0x6c, 0x25, 0x86, 0x02, 0x53, 0x15, 0x85, 0x13, 0xa7, 0x09, 0x75, 0xd2,
+  0x0b, 0xce, 0xf4, 0xd7, 0x9a, 0x00, 0x4f, 0x51, 0xa4, 0x9a, 0xdf, 0x89,
+  0x37, 0x6f, 0xbb, 0xc7, 0x42, 0x3c, 0xb1, 0xfb, 0x2b, 0x4f, 0x17, 0x9c,
+  0x62, 0xcf, 0x0b, 0xf9, 0xa2, 0xda, 0x4a, 0x16, 0x5b, 0x2a, 0x78, 0xa7,
+  0xcf, 0x53, 0x9b, 0x1e, 0x77, 0x50, 0x90, 0x7a, 0x10, 0x7b, 0xcc, 0x6d,
+  0xbf, 0x2c, 0x95, 0x88, 0xcf, 0x67, 0x19, 0x7a, 0x33, 0x52, 0x60, 0xc2,
+  0x0b, 0x60, 0xcb, 0x0b, 0xf3, 0xc9, 0x3c, 0xae, 0x34, 0xe2, 0x81, 0xea,
+  0xbd, 0xa1, 0x7a, 0x50, 0x47, 0x32, 0xf9, 0x82, 0x8f, 0x2e, 0x88, 0xae,
+  0x94, 0x61, 0xf2, 0xb2, 0x0b, 0xf3, 0xd9, 0x2a, 0xa1, 0xb1, 0x6c, 0x25,
+  0xd4, 0xb9, 0x19, 0x32, 0x59, 0x74, 0x39, 0xbe, 0x44, 0x87, 0x1c, 0x28,
+  0x6d, 0xd4, 0x68, 0x28, 0xa1, 0x3e, 0xf6, 0xe7, 0x36, 0xf9, 0x41, 0x20,
+  0x12, 0x45, 0x31, 0xd5, 0x8c, 0xf4, 0x42, 0x54, 0x59, 0xb2, 0x78, 0x6b,
+  0xc7, 0x74, 0xcc, 0x9a, 0xe9, 0x5d, 0x9b, 0x27, 0x71, 0x9b, 0x6d, 0xd5,
+  0xfe, 0x81, 0x02, 0x61, 0x49, 0xf2, 0x39, 0x67, 0xb8, 0x02, 0xea, 0x12,
+  0xa6, 0x96, 0x75, 0xd5, 0x6d, 0x95, 0x78, 0x81, 0x5f, 0x42, 0x27, 0xaa,
+  0x77, 0x55, 0xf6, 0x4d, 0x82, 0xda, 0x72, 0x0b, 0x15, 0xdf, 0x11, 0xb9,
+  0xba, 0xec, 0xd7, 0x2f, 0x11, 0xb9, 0xe5, 0xce, 0x70, 0x8e, 0xd5, 0xb7,
+  0x11, 0xae, 0xc9, 0x68, 0x4a, 0x40, 0x08, 0x08, 0x57, 0x54, 0x81, 0xad,
+  0x7a, 0xce, 0xc9, 0xcf, 0x00, 0xb2, 0x4b, 0xae, 0x43, 0xc3, 0xe4, 0x35,
+  0x90, 0x68, 0xdf, 0x6c, 0xb2, 0xdf, 0xb3, 0xdd, 0x17, 0xbd, 0x87, 0x24,
+  0x47, 0x57, 0x21, 0x5e, 0xff, 0x00, 0x58, 0x72, 0xa8, 0xfa, 0xc9, 0xa8,
+  0x69, 0xa0, 0x9a, 0x66, 0xee, 0x32, 0xfc, 0x4b, 0x17, 0xfd, 0xaa, 0xb6,
+  0x7d, 0xf8, 0xa7, 0xba, 0x44, 0xe3, 0x27, 0xc4, 0x71, 0x7f, 0xda, 0xab,
+  0x67, 0xdf, 0x8a, 0x7b, 0xa8, 0x24, 0x28, 0xac, 0x6f, 0x47, 0xa9, 0x14,
+  0x50, 0x19, 0xa4, 0xce, 0x38, 0xfc, 0x8f, 0x65, 0xdf, 0x44, 0x48, 0xfe,
+  0x03, 0x4e, 0x74, 0x99, 0xc7, 0x1f, 0x91, 0xec, 0xbb, 0xe8, 0x89, 0x1f,
+  0xc0, 0x68, 0x06, 0xf8, 0xdf, 0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x56,
+  0xb8, 0xdf, 0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x50, 0x05, 0x14, 0x51,
+  0x40, 0x14, 0x51, 0x45, 0x01, 0xe5, 0x40, 0x6f, 0x64, 0x6f, 0xd1, 0x5f,
+  0x22, 0x66, 0x56, 0x29, 0x9c, 0x37, 0xe2, 0x5c, 0xbb, 0x55, 0xa9, 0x82,
+  0x5b, 0x8c, 0xb7, 0xf2, 0x4c, 0x5d, 0xa1, 0xd0, 0x48, 0x8c, 0xa1, 0xfe,
+  0x93, 0xb6, 0xa7, 0xfe, 0x11, 0xdb, 0x20, 0x78, 0x14, 0x0e, 0xf2, 0xaa,
+  0xfa, 0xf7, 0x5d, 0x77, 0x55, 0xa7, 0xe1, 0x11, 0x88, 0x4f, 0xc9, 0xb0,
+  0x74, 0xdc, 0x71, 0xef, 0x33, 0x28, 0xc7, 0xa4, 0x26, 0xeb, 0x65, 0x74,
+  0x0d, 0xab, 0xb6, 0x6f, 0xaa, 0x9b, 0xf5, 0x85, 0xa4, 0x14, 0xeb, 0xb8,
+  0x9d, 0x6e, 0xa5, 0x3c, 0x3c, 0xa2, 0x1a, 0xca, 0xc3, 0x39, 0x58, 0xbc,
+  0x5c, 0x6e, 0xb6, 0x06, 0xb2, 0x1c, 0x4e, 0x63, 0xef, 0xa2, 0x77, 0x93,
+  0xcb, 0x0e, 0x34, 0xc7, 0x6c, 0x95, 0x72, 0xa4, 0x75, 0x5a, 0x01, 0xe6,
+  0x28, 0x71, 0xbd, 0x24, 0x94, 0xed, 0x49, 0x52, 0x47, 0x4e, 0xfa, 0xd3,
+  0x96, 0x47, 0xb7, 0x64, 0x13, 0xe3, 0x9c, 0xae, 0xe2, 0xdd, 0x99, 0xb8,
+  0xcc, 0xa8, 0x30, 0xdb, 0xaa, 0x6f, 0xca, 0x9c, 0x25, 0x6d, 0xac, 0x38,
+  0xe2, 0x13, 0xcc, 0x1a, 0x6d, 0x1d, 0x98, 0xd1, 0xde, 0xf6, 0x49, 0x25,
+  0x3d, 0xc5, 0x03, 0xf0, 0x78, 0xcc, 0xa0, 0xc7, 0xb8, 0xb7, 0x12, 0x22,
+  0x15, 0x12, 0xcd, 0x7a, 0x4b, 0x97, 0x2b, 0x43, 0x24, 0x79, 0xb1, 0xce,
+  0xff, 0x00, 0x9e, 0xc2, 0xf5, 0x16, 0x5e, 0x25, 0x49, 0x4f, 0xe8, 0x2d,
+  0x26, 0xad, 0x7c, 0x66, 0xfd, 0x6a, 0xb2, 0x3b, 0x02, 0xc3, 0x36, 0xdd,
+  0x26, 0x3c, 0xc9, 0xcd, 0x6d, 0xd9, 0x4b, 0x68, 0xac, 0x4b, 0x94, 0x14,
+  0xa0, 0xe2, 0x54, 0xb1, 0xf0, 0x96, 0x48, 0xe6, 0xd1, 0xef, 0x4a, 0x86,
+  0xba, 0x77, 0x6b, 0x35, 0x9c, 0x38, 0xf5, 0x32, 0x83, 0x4b, 0x2a, 0x5d,
+  0x0f, 0x78, 0xcc, 0x5b, 0xbc, 0x80, 0x6f, 0x96, 0x64, 0x44, 0x58, 0x7d,
+  0xae, 0x56, 0x27, 0x5d, 0x54, 0xa7, 0x1e, 0x92, 0xd7, 0x7a, 0x42, 0x10,
+  0xdf, 0x2a, 0x18, 0x69, 0x47, 0x44, 0x72, 0xef, 0x7d, 0x09, 0x4e, 0xc5,
+  0x73, 0xe3, 0x32, 0xb1, 0xb9, 0x8e, 0xc6, 0x56, 0x4d, 0xe4, 0xf2, 0x32,
+  0x19, 0xa2, 0x40, 0x75, 0xb9, 0xa9, 0x0b, 0x0c, 0xa9, 0xa5, 0x00, 0xeb,
+  0x0d, 0x85, 0x0d, 0x24, 0x24, 0x29, 0x3d, 0xc3, 0x6a, 0x1a, 0x51, 0xde,
+  0xf7, 0x51, 0x96, 0xd5, 0x5e, 0xe3, 0xde, 0x55, 0xfc, 0x9a, 0x7e, 0x74,
+  0xcb, 0x04, 0x27, 0x9d, 0x8b, 0x1d, 0x2d, 0x21, 0xa5, 0x32, 0xa6, 0xb9,
+  0x42, 0xf4, 0x87, 0x16, 0xe2, 0x79, 0x3b, 0x35, 0xa9, 0x48, 0xe7, 0xd2,
+  0xd2, 0x52, 0x90, 0x06, 0x94, 0x9e, 0xba, 0xe7, 0x2b, 0x1d, 0x94, 0xd4,
+  0xab, 0xcd, 0xf6, 0x6b, 0xd2, 0xa6, 0x2e, 0x68, 0x7d, 0x84, 0x5b, 0x3b,
+  0x43, 0x19, 0x2f, 0x04, 0x25, 0xb6, 0x9a, 0x43, 0xfc, 0xbc, 0x85, 0xd2,
+  0x12, 0x91, 0xce, 0x0a, 0x4e, 0xce, 0x86, 0x87, 0x4a, 0xc9, 0x63, 0x93,
+  0x5d, 0xfa, 0x1b, 0x99, 0x99, 0x79, 0xc7, 0xee, 0xc6, 0xcf, 0x8c, 0x29,
+  0x32, 0x6d, 0x96, 0xd7, 0xc8, 0xf2, 0x61, 0x15, 0xd7, 0x90, 0x58, 0x7c,
+  0x07, 0x12, 0x9e, 0x66, 0xc2, 0x8a, 0x5d, 0x41, 0xe6, 0xd7, 0x30, 0xe5,
+  0x52, 0x14, 0x01, 0x20, 0xf5, 0x39, 0xbd, 0xc6, 0x6a, 0xeb, 0x75, 0x91,
+  0x26, 0xe6, 0x86, 0xd8, 0x9a, 0xe9, 0x8e, 0xa6, 0x2d, 0x6d, 0xc2, 0x6a,
+  0x74, 0x82, 0xa6, 0x82, 0xf9, 0x5e, 0x71, 0x07, 0x61, 0xa5, 0xf9, 0xe3,
+  0x4a, 0xe6, 0x00, 0x04, 0xf5, 0x27, 0xc2, 0x55, 0xfb, 0x06, 0x4f, 0x1b,
+  0x17, 0x96, 0xcd, 0x9a, 0xe1, 0x02, 0xdf, 0x24, 0x36, 0xa5, 0x26, 0xdb,
+  0x0d, 0x80, 0x5b, 0x20, 0xef, 0x69, 0x53, 0xaa, 0x3c, 0xea, 0x75, 0x49,
+  0xfe, 0x93, 0xcd, 0xf3, 0xba, 0x90, 0x6b, 0x7c, 0x0c, 0xab, 0x1e, 0xb2,
+  0xdb, 0x10, 0xa8, 0x16, 0x0b, 0xb3, 0x76, 0xf7, 0x58, 0x4c, 0x96, 0x5c,
+  0x85, 0x6c, 0x75, 0xf4, 0x39, 0xcc, 0x3c, 0xee, 0x65, 0x36, 0x93, 0xca,
+  0xe0, 0x20, 0x85, 0x73, 0x90, 0x7a, 0x6f, 0x7a, 0xeb, 0x4c, 0x92, 0x92,
+  0x36, 0x58, 0xf1, 0xfb, 0xe8, 0x71, 0xe7, 0xd7, 0x2c, 0x5a, 0xd7, 0x2b,
+  0x97, 0xb7, 0x79, 0x4b, 0x12, 0x67, 0x3a, 0x90, 0x4e, 0x92, 0x56, 0x40,
+  0x69, 0xa0, 0x37, 0xf0, 0x50, 0x82, 0x91, 0xb3, 0xae, 0xbb, 0x35, 0x3f,
+  0x6c, 0xb4, 0xda, 0x2c, 0x85, 0xd7, 0xd9, 0x6c, 0x99, 0x2b, 0x47, 0xbf,
+  0x49, 0x79, 0x6a, 0x75, 0xf7, 0x40, 0xfd, 0x25, 0x2b, 0x6a, 0x23, 0xd5,
+  0xdd, 0xe8, 0x14, 0x82, 0xac, 0xc3, 0x3a, 0xcb, 0xd6, 0x23, 0xe1, 0xf6,
+  0x2f, 0x72, 0x20, 0x13, 0xa5, 0x5c, 0x66, 0x29, 0x0e, 0xb8, 0x47, 0x4f,
+  0x82, 0x06, 0xda, 0x49, 0xf5, 0xed, 0xd2, 0x3c, 0x51, 0xba, 0x9b, 0xc6,
+  0xb8, 0x7e, 0x98, 0xf1, 0x94, 0x6f, 0xf7, 0x17, 0xee, 0x2e, 0x3e, 0x42,
+  0xa4, 0x36, 0x1d, 0x51, 0x4b, 0xe7, 0xfd, 0xaa, 0xcf, 0x9e, 0xe8, 0xfd,
+  0x52, 0x43, 0x7e, 0x84, 0x01, 0xa1, 0x50, 0x49, 0x2e, 0xac, 0xba, 0xd9,
+  0x21, 0x45, 0x8b, 0x33, 0x32, 0xaf, 0x32, 0x47, 0x9a, 0x5a, 0x88, 0xdf,
+  0x44, 0x1f, 0xd7, 0x5a, 0xb4, 0x94, 0x7b, 0x14, 0x77, 0xea, 0xa8, 0x36,
+  0x30, 0x69, 0x97, 0x15, 0x22, 0x7d, 0xd6, 0x44, 0x68, 0x72, 0x7c, 0xbd,
+  0xc9, 0xcd, 0xc7, 0x66, 0x3b, 0x72, 0x04, 0x45, 0x2f, 0x5f, 0x93, 0x71,
+  0xc4, 0xed, 0x2b, 0x3a, 0xda, 0xba, 0x14, 0xec, 0x9e, 0x9e, 0x25, 0xbd,
+  0xd9, 0x16, 0xbb, 0x34, 0x34, 0x30, 0x90, 0xcc, 0x66, 0x90, 0x34, 0xdb,
+  0x2d, 0x20, 0x0d, 0x7a, 0x82, 0x45, 0x25, 0x66, 0xbc, 0x47, 0xb7, 0x59,
+  0x5b, 0x6c, 0x4a, 0x96, 0x88, 0x21, 0xf3, 0xca, 0xc3, 0x41, 0x25, 0xd9,
+  0x2f, 0x9f, 0x43, 0x6d, 0xa7, 0x6a, 0x51, 0xf5, 0x24, 0x13, 0xec, 0xad,
+  0x69, 0xd1, 0x94, 0xf7, 0x5c, 0x79, 0x98, 0xce, 0xb4, 0x61, 0xb7, 0x51,
+  0xb6, 0x0c, 0x6b, 0x46, 0x37, 0x01, 0x4d, 0xa5, 0xd5, 0x24, 0xb8, 0xe1,
+  0x75, 0xd7, 0x1e, 0x70, 0xb8, 0xf3, 0xee, 0x10, 0x01, 0x5a, 0x89, 0xea,
+  0xa5, 0x74, 0x03, 0xd0, 0x00, 0x00, 0x68, 0x00, 0x2a, 0x26, 0xe5, 0x92,
+  0x3c, 0xf7, 0xbd, 0x42, 0x41, 0x65, 0x04, 0xeb, 0x9c, 0x80, 0x54, 0x7d,
+  0x9e, 0x03, 0xed, 0xaa, 0xba, 0xff, 0x00, 0x94, 0x5c, 0xa3, 0x34, 0xdd,
+  0xeb, 0x2c, 0x9f, 0x17, 0x03, 0xc7, 0xcf, 0x9c, 0xa9, 0x17, 0x87, 0x02,
+  0xee, 0x72, 0x87, 0xa1, 0x98, 0xe9, 0x27, 0x93, 0x7d, 0xdb, 0x57, 0x31,
+  0xd7, 0xe6, 0x8a, 0x81, 0xfc, 0x6e, 0x66, 0x19, 0xb3, 0x6e, 0xc3, 0xe0,
+  0x16, 0x07, 0x22, 0x5b, 0x68, 0xf3, 0x1e, 0xc8, 0xaf, 0x49, 0x4b, 0x4c,
+  0xa3, 0xae, 0xbd, 0xed, 0x2a, 0x20, 0x28, 0xf8, 0xf5, 0x3b, 0xfd, 0x4a,
+  0xd5, 0x7b, 0xaa, 0x5b, 0xbe, 0xf3, 0xfd, 0x0c, 0xa4, 0xab, 0x55, 0xf4,
+  0x45, 0xb9, 0x75, 0xc9, 0x2c, 0x7c, 0x3c, 0xc5, 0xa7, 0x65, 0x59, 0x7d,
+  0xc1, 0xb8, 0x2c, 0x84, 0x79, 0x89, 0x71, 0x5e, 0xfa, 0xf1, 0xd7, 0x44,
+  0x21, 0x3d, 0xea, 0x52, 0x8e, 0xb4, 0x3c, 0x3b, 0xfb, 0xb6, 0x6b, 0x9b,
+  0xf0, 0x6f, 0xb3, 0x5c, 0xed, 0xbc, 0x37, 0x17, 0x5b, 0xdb, 0x45, 0x9b,
+  0xae, 0x47, 0x3a, 0x45, 0xf2, 0x63, 0x47, 0xbd, 0xb5, 0x49, 0x5f, 0x3a,
+  0x52, 0x7d, 0x61, 0x1c, 0x80, 0x8f, 0x03, 0xb1, 0x4b, 0xdc, 0x3b, 0xe0,
+  0x44, 0x66, 0xae, 0x4d, 0x65, 0x9c, 0x54, 0xba, 0x39, 0x9c, 0x65, 0x9b,
+  0xe6, 0x4b, 0x93, 0x09, 0x5c, 0x48, 0x7d, 0x76, 0x12, 0xcb, 0x47, 0xcd,
+  0xe9, 0xd3, 0xa9, 0x1a, 0xd8, 0xd8, 0x02, 0xae, 0xc0, 0x3a, 0x77, 0x56,
+  0x15, 0x26, 0xe7, 0x27, 0x26, 0x6f, 0x4e, 0x0a, 0x11, 0xd2, 0x84, 0x5e,
+  0x32, 0x7c, 0x47, 0x17, 0xfd, 0xaa, 0xb6, 0x7d, 0xf8, 0xa7, 0xba, 0x44,
+  0xe3, 0x20, 0xd4, 0x1c, 0x5c, 0x7f, 0xf7, 0x55, 0xb3, 0xef, 0xc5, 0x3d,
+  0xd5, 0x0b, 0x9e, 0x57, 0xdf, 0xd0, 0x91, 0x45, 0x64, 0x8d, 0x9a, 0x28,
+  0x43, 0xc9, 0x9a, 0x4c, 0xe3, 0x8f, 0xc8, 0xf6, 0x5d, 0xf4, 0x44, 0x8f,
+  0xe0, 0x34, 0xe7, 0x50, 0x1c, 0x45, 0xb2, 0xc8, 0xc9, 0x30, 0x5b, 0xe6,
+  0x3f, 0x11, 0xd6, 0xd9, 0x91, 0x70, 0x82, 0xec, 0x66, 0x9c, 0x73, 0x7c,
+  0x89, 0x52, 0xd2, 0x40, 0x2a, 0xd7, 0x5d, 0x6e, 0x84, 0x93, 0x71, 0xbe,
+  0x2e, 0xdf, 0xcc, 0x1f, 0x65, 0x6c, 0xaa, 0xfd, 0xbf, 0xc7, 0x2a, 0x1b,
+  0x4a, 0x03, 0x58, 0x11, 0x09, 0x1a, 0xdf, 0x69, 0x2f, 0xaf, 0xfd, 0x35,
+  0xeb, 0x9b, 0x8c, 0xbf, 0xd4, 0xe0, 0x3f, 0xbd, 0x97, 0xfe, 0x5a, 0x01,
+  0xfa, 0x8a, 0x41, 0xe7, 0xe3, 0x2f, 0xf5, 0x58, 0x0f, 0xef, 0x65, 0xff,
+  0x00, 0x96, 0x8e, 0x6e, 0x32, 0xff, 0x00, 0x53, 0x80, 0xfe, 0xf6, 0x5f,
+  0xf9, 0x68, 0x07, 0xea, 0x29, 0x07, 0x9b, 0x8c, 0xbf, 0xd4, 0xe0, 0x3f,
+  0xbd, 0x97, 0xfe, 0x5a, 0x39, 0xf8, 0xcb, 0xfd, 0x56, 0x03, 0xfb, 0xd9,
+  0x7f, 0xe5, 0xa0, 0x1f, 0xa8, 0x23, 0x74, 0x83, 0xcf, 0xc6, 0x5f, 0xea,
+  0xb0, 0x1f, 0xde, 0x4b, 0xff, 0x00, 0x2d, 0x1c, 0xfc, 0x65, 0xfe, 0xab,
+  0x01, 0xfd, 0xe4, 0xbf, 0xf2, 0xd0, 0x14, 0x97, 0x15, 0x71, 0x49, 0x58,
+  0x87, 0x12, 0xe5, 0x5a, 0xac, 0xc8, 0x4b, 0x31, 0xf2, 0x49, 0x26, 0xfd,
+  0x8b, 0x2f, 0x5a, 0x44, 0x7b, 0xdb, 0x29, 0xf7, 0xf8, 0xbb, 0xee, 0x4a,
+  0x24, 0xb5, 0xb4, 0xf5, 0xe8, 0x49, 0x00, 0x7c, 0x1a, 0xb3, 0x2c, 0x37,
+  0x9b, 0x06, 0x55, 0x83, 0xc5, 0xc8, 0x5a, 0xb7, 0x31, 0x29, 0xf9, 0x4c,
+  0x33, 0xe4, 0xe2, 0x43, 0x8a, 0x42, 0x3c, 0xe5, 0xa5, 0x1c, 0x8f, 0x80,
+  0x47, 0x30, 0x6d, 0x44, 0xec, 0x1f, 0xd1, 0x23, 0xa5, 0x70, 0x71, 0x73,
+  0x0c, 0xe2, 0xb6, 0x77, 0x88, 0xb9, 0x6b, 0x94, 0x30, 0xc8, 0xf2, 0xa3,
+  0x3c, 0xdc, 0xdb, 0x7c, 0x98, 0xae, 0xc9, 0x0f, 0x47, 0x92, 0xd2, 0xb9,
+  0x90, 0xb4, 0x15, 0x27, 0x5b, 0xef, 0x1d, 0x7a, 0x75, 0x35, 0x5f, 0xf0,
+  0xb7, 0x26, 0x8e, 0xbb, 0x82, 0x15, 0x36, 0x30, 0x8d, 0x6b, 0xcb, 0x5f,
+  0x75, 0x46, 0x3a, 0xba, 0x22, 0x05, 0xe9, 0x03, 0x53, 0xa1, 0x11, 0xde,
+  0x8e, 0xd0, 0xe9, 0xe4, 0x0e, 0x9b, 0xe6, 0x20, 0x75, 0xad, 0xa9, 0x62,
+  0x59, 0x83, 0xeb, 0xf5, 0x32, 0xab, 0x98, 0xe2, 0x6b, 0xa7, 0xd0, 0xbb,
+  0xaf, 0xd8, 0xcc, 0xc7, 0xf1, 0xc7, 0x84, 0x6b, 0xf4, 0xab, 0x84, 0x86,
+  0x39, 0x43, 0x90, 0x92, 0x50, 0xd4, 0x57, 0xd0, 0x85, 0x02, 0xa8, 0xdd,
+  0x92, 0x46, 0x90, 0x14, 0x01, 0x47, 0x7f, 0x30, 0xd8, 0xd9, 0x22, 0xb5,
+  0x8c, 0xaa, 0xd7, 0x7a, 0xb5, 0xcf, 0x85, 0x75, 0xb7, 0xaa, 0x1d, 0x95,
+  0xc4, 0x21, 0x31, 0xe5, 0x1f, 0x35, 0x0f, 0x34, 0xb4, 0x05, 0x20, 0xb4,
+  0x40, 0x3b, 0x75, 0x2a, 0xf3, 0x79, 0x13, 0xe7, 0x25, 0x43, 0xbb, 0xbb,
+  0x7a, 0x2d, 0x38, 0xeb, 0x8e, 0x4f, 0x9d, 0x2e, 0x35, 0xf2, 0x34, 0x06,
+  0x27, 0xbc, 0x1f, 0x7c, 0xb4, 0x55, 0xdb, 0x73, 0x84, 0xf2, 0xa9, 0x49,
+  0x42, 0xd4, 0x5b, 0x6d, 0x64, 0x6b, 0x99, 0x41, 0x24, 0x12, 0x37, 0xa0,
+  0x69, 0x86, 0x1c, 0x3c, 0x36, 0xc4, 0x96, 0x97, 0x0a, 0x0d, 0xbd, 0x0f,
+  0x32, 0xd8, 0x6d, 0x0e, 0x34, 0xca, 0x54, 0xe9, 0x00, 0x6b, 0xaa, 0xb5,
+  0xb2, 0x75, 0xe2, 0x4d, 0x46, 0x86, 0x9e, 0x31, 0xb8, 0xf7, 0x89, 0xac,
+  0xb7, 0xb0, 0xaf, 0x8b, 0xd8, 0xf3, 0x56, 0xe7, 0xfb, 0xae, 0x97, 0x0c,
+  0x65, 0xdc, 0x63, 0xb2, 0xf4, 0xc6, 0xe5, 0xc8, 0x05, 0xae, 0xdc, 0x34,
+  0x84, 0x17, 0x0b, 0x49, 0x6c, 0x2c, 0x2f, 0x49, 0x1b, 0x6f, 0x9c, 0x27,
+  0x7b, 0x3b, 0x1b, 0xd5, 0x34, 0xda, 0xb0, 0x7c, 0x7a, 0x24, 0x66, 0x53,
+  0x2e, 0x13, 0x57, 0x09, 0x28, 0xda, 0xdd, 0x7d, 0xf4, 0x03, 0xdb, 0x38,
+  0x54, 0x54, 0xa5, 0xa9, 0x3f, 0x07, 0x7b, 0x51, 0xd7, 0x4e, 0x9d, 0x00,
+  0xee, 0xa2, 0x46, 0x54, 0x80, 0x9d, 0x45, 0x8a, 0x48, 0x00, 0xf9, 0xce,
+  0x2b, 0xa0, 0xf6, 0xeb, 0xff, 0x00, 0x35, 0x5d, 0x5d, 0xb8, 0xb3, 0x06,
+  0xe5, 0x70, 0x55, 0xaa, 0xc2, 0xec, 0xdc, 0xa2, 0xe2, 0x09, 0x06, 0x05,
+  0x81, 0xae, 0xdf, 0x93, 0xc3, 0xdf, 0x1c, 0x04, 0x36, 0xd8, 0xdf, 0x8a,
+  0xd6, 0x2b, 0x4f, 0xb3, 0xcf, 0x99, 0xec, 0x67, 0xf6, 0x88, 0x7e, 0x0d,
+  0xcb, 0x66, 0x7d, 0xe2, 0xdd, 0x01, 0x1d, 0x99, 0x70, 0x2d, 0x69, 0xee,
+  0x6d, 0xbe, 0xba, 0xff, 0x00, 0xb0, 0xa4, 0x1c, 0xd7, 0x89, 0x96, 0xfb,
+  0x4b, 0xad, 0xc4, 0x93, 0x38, 0x31, 0x2a, 0x47, 0x48, 0xf0, 0x22, 0xb6,
+  0xa7, 0xe6, 0x3e, 0x7c, 0x39, 0x5b, 0x40, 0x2b, 0x3f, 0xdc, 0x07, 0xaf,
+  0xc6, 0xa9, 0x0e, 0x23, 0x71, 0x3d, 0x16, 0x82, 0xa8, 0xd9, 0x4e, 0x55,
+  0x1e, 0xc8, 0xe9, 0x25, 0x3e, 0xe0, 0x62, 0xee, 0x22, 0x75, 0xcd, 0x5d,
+  0xfe, 0x63, 0xd2, 0xcf, 0xbd, 0x47, 0x3b, 0xef, 0xe4, 0x05, 0x5d, 0x7a,
+  0x1a, 0xe3, 0xe1, 0xe5, 0x87, 0x8c, 0xb9, 0x84, 0x59, 0x3f, 0x8b, 0xfc,
+  0x5e, 0x17, 0x0a, 0xec, 0x32, 0x92, 0xa5, 0x2a, 0xeb, 0x24, 0x2d, 0xcb,
+  0x8c, 0xde, 0xa3, 0x5d, 0xa3, 0xee, 0x6d, 0xe5, 0x6f, 0x5b, 0xda, 0x42,
+  0x53, 0x4d, 0x54, 0xe9, 0xf8, 0x56, 0x5f, 0x9b, 0x1a, 0x2a, 0x54, 0xf1,
+  0x3c, 0x21, 0xcb, 0x39, 0xce, 0xa5, 0x5b, 0x23, 0x2e, 0x5e, 0x53, 0x7d,
+  0x87, 0xc3, 0xd8, 0x4b, 0x47, 0x3a, 0x1a, 0x92, 0x53, 0x32, 0xfb, 0x21,
+  0x3d, 0x3a, 0xa2, 0x32, 0x49, 0x43, 0x3b, 0xde, 0xb9, 0x96, 0x54, 0x47,
+  0x88, 0x14, 0x85, 0x88, 0x5d, 0xf8, 0x8b, 0x9a, 0xce, 0x77, 0xf1, 0x29,
+  0x83, 0x39, 0x61, 0x8d, 0x23, 0x68, 0x7f, 0x31, 0xbf, 0xab, 0xb7, 0x9c,
+  0xfa, 0x77, 0xa3, 0xa7, 0x9c, 0x05, 0x29, 0x1f, 0xa8, 0xd8, 0x56, 0xb5,
+  0xd3, 0x54, 0xcf, 0x80, 0xfe, 0x0b, 0xd7, 0xcc, 0x76, 0xf0, 0x6f, 0x77,
+  0xa4, 0xe2, 0xb9, 0x75, 0xd7, 0xb5, 0xed, 0x43, 0xd7, 0x79, 0x12, 0x94,
+  0xdf, 0x30, 0x3b, 0x0a, 0x2d, 0x84, 0xe9, 0x67, 0xe7, 0x95, 0x0a, 0xbc,
+  0x59, 0x6f, 0x8c, 0x0c, 0x34, 0x86, 0x99, 0x8d, 0xc3, 0xf6, 0xdb, 0x6d,
+  0x21, 0x28, 0x4a, 0x57, 0x2d, 0x21, 0x29, 0x1d, 0xc0, 0x00, 0x9e, 0x83,
+  0xa7, 0x75, 0x65, 0x3a, 0xb2, 0x9f, 0x2c, 0xda, 0x14, 0xa3, 0x0e, 0x0a,
+  0xfb, 0x02, 0xfc, 0x18, 0xf1, 0xd8, 0xd7, 0x04, 0xe4, 0x1c, 0x4a, 0xbb,
+  0x4e, 0xce, 0xef, 0xeb, 0x57, 0x3b, 0x8b, 0x9c, 0xea, 0x8c, 0x60, 0xae,
+  0x9d, 0x39, 0x09, 0x25, 0x7a, 0x3d, 0x34, 0xa2, 0x53, 0xa1, 0xf0, 0x45,
+  0x5f, 0x70, 0xe1, 0xc5, 0x87, 0x11, 0xa8, 0x90, 0xe3, 0xb5, 0x1a, 0x3b,
+  0x29, 0x08, 0x6d, 0xa6, 0x90, 0x10, 0x94, 0x24, 0x78, 0x00, 0x3a, 0x01,
+  0xec, 0xa4, 0x7d, 0xf1, 0x93, 0xfa, 0xac, 0x07, 0xf7, 0x92, 0xff, 0x00,
+  0xcb, 0x59, 0x0a, 0xe3, 0x2f, 0xf5, 0x38, 0x0f, 0xef, 0x65, 0xff, 0x00,
+  0x96, 0xb3, 0x2e, 0x3e, 0xe8, 0x56, 0x47, 0x4a, 0x41, 0xe7, 0xe3, 0x2f,
+  0xf5, 0x58, 0x0f, 0xef, 0x65, 0xff, 0x00, 0x96, 0x8e, 0x7e, 0x32, 0xff,
+  0x00, 0x55, 0x80, 0xfe, 0xf2, 0x5f, 0xf9, 0x68, 0x0f, 0x7c, 0x65, 0xf8,
+  0x96, 0x2f, 0xfb, 0x55, 0x6c, 0xfb, 0xf1, 0x4f, 0x75, 0x58, 0xdd, 0xac,
+  0x5c, 0x4d, 0xc8, 0x66, 0x59, 0x5a, 0xbe, 0xaf, 0x10, 0x62, 0x04, 0x1b,
+  0xb4, 0x6b, 0x83, 0xa6, 0x12, 0xa4, 0x17, 0x54, 0x19, 0x58, 0x57, 0x2a,
+  0x42, 0xc6, 0xba, 0xea, 0xac, 0xea, 0x00, 0xa2, 0xb0, 0x49, 0xf0, 0xa2,
+  0x80, 0xcd, 0x1a, 0xeb, 0x45, 0x14, 0x01, 0x45, 0x14, 0x50, 0x05, 0x14,
+  0x51, 0x40, 0x14, 0x51, 0x45, 0x00, 0x51, 0x45, 0x14, 0x01, 0x5f, 0x2b,
+  0x7e, 0x11, 0x38, 0x75, 0xcf, 0x0a, 0xc9, 0xef, 0x79, 0x7c, 0x1c, 0x7d,
+  0xeb, 0xf6, 0x09, 0x91, 0x86, 0x9c, 0xc8, 0xe0, 0x43, 0x51, 0x4c, 0xa8,
+  0x12, 0xdb, 0xdf, 0x24, 0xe6, 0x08, 0xf8, 0x0b, 0x1f, 0x0b, 0x98, 0x74,
+  0xdf, 0x30, 0x57, 0x42, 0x0d, 0x7d, 0x53, 0x58, 0x52, 0x42, 0xba, 0x28,
+  0x6c, 0x1e, 0x84, 0x50, 0x1f, 0x19, 0xe3, 0x3c, 0x46, 0xe2, 0x5c, 0x7b,
+  0x12, 0x2e, 0x96, 0x9b, 0x64, 0x1e, 0x28, 0x63, 0xcd, 0x68, 0x79, 0x75,
+  0xad, 0x65, 0xab, 0x93, 0x49, 0xf0, 0x12, 0x23, 0x8d, 0xa9, 0x0e, 0x01,
+  0xde, 0x42, 0x08, 0xdf, 0xe7, 0x10, 0x76, 0x58, 0xec, 0xdc, 0x52, 0xcb,
+  0xb2, 0x08, 0xcb, 0x7e, 0xd5, 0xc3, 0x29, 0x76, 0x88, 0x6d, 0x90, 0x97,
+  0xae, 0x99, 0x1c, 0xe4, 0xdb, 0xe1, 0x32, 0x77, 0xd4, 0xa9, 0x6a, 0x4e,
+  0xd5, 0xeb, 0x09, 0xd9, 0xf5, 0x55, 0x8d, 0xc4, 0x0f, 0xc1, 0xd7, 0x05,
+  0xc8, 0xee, 0xc6, 0xfb, 0x65, 0x72, 0xe3, 0x87, 0xde, 0xf7, 0xbf, 0x2d,
+  0xb1, 0xbd, 0xe4, 0xfc, 0xc7, 0xd2, 0xa4, 0x01, 0xad, 0xf8, 0xec, 0x68,
+  0x93, 0xd4, 0x9a, 0xe6, 0xb4, 0x7e, 0x0d, 0xb8, 0x6a, 0xee, 0xcd, 0xdd,
+  0xf3, 0x4b, 0xce, 0x49, 0x9c, 0xce, 0x6c, 0x0e, 0x53, 0x7c, 0xb8, 0x29,
+  0xd6, 0xc6, 0xbf, 0x50, 0x6b, 0x63, 0xa0, 0xe8, 0x49, 0x1e, 0xaa, 0xdd,
+  0x5c, 0xd4, 0x4b, 0x19, 0x30, 0x76, 0xd4, 0xdb, 0xcb, 0x45, 0x4d, 0x17,
+  0x3f, 0x72, 0x6d, 0xc3, 0xdc, 0xeb, 0x42, 0x2e, 0x9c, 0x5e, 0xc9, 0x04,
+  0x80, 0xf0, 0x62, 0xcc, 0xca, 0xe1, 0x59, 0xa0, 0x10, 0x85, 0x23, 0xb3,
+  0x2b, 0xef, 0x79, 0x1e, 0x79, 0x27, 0x9f, 0xcd, 0x3a, 0x1d, 0xd4, 0xe9,
+  0x03, 0x83, 0xfc, 0x55, 0xcc, 0xed, 0xcd, 0xc3, 0xcd, 0xf2, 0xe8, 0x18,
+  0x56, 0x3c, 0x47, 0xfa, 0xb7, 0x8a, 0x47, 0x0d, 0x23, 0x93, 0xa7, 0x9a,
+  0xb7, 0x3b, 0xbc, 0x07, 0x7f, 0x38, 0xaf, 0xa1, 0x6c, 0xf6, 0x9b, 0x5d,
+  0x9a, 0x0a, 0x60, 0x5a, 0x2d, 0xd1, 0x2d, 0xf1, 0x11, 0xf0, 0x59, 0x8a,
+  0xca, 0x5a, 0x40, 0xf6, 0x25, 0x20, 0x0a, 0xec, 0x00, 0x0a, 0xca, 0x53,
+  0x94, 0xb9, 0x35, 0x8c, 0x23, 0x1e, 0x11, 0x5f, 0x70, 0xe3, 0x82, 0xfc,
+  0x36, 0xc0, 0x43, 0x4e, 0xe3, 0xd8, 0xcc, 0x51, 0x35, 0xb1, 0xf1, 0xe9,
+  0x43, 0xb7, 0x92, 0x4f, 0xa7, 0x9d, 0x7b, 0xe5, 0x3f, 0x37, 0x43, 0xd5,
+  0x56, 0x0f, 0x28, 0xac, 0x81, 0xae, 0xea, 0x2a, 0xa5, 0x8c, 0x68, 0x56,
+  0x68, 0xa2, 0x80, 0x28, 0xa2, 0x8a, 0x00, 0xa2, 0x8a, 0x28, 0x03, 0x42,
+  0x8a, 0x28, 0xa0, 0x30, 0x52, 0x0f, 0x7d, 0x15, 0x9a, 0x28, 0x02, 0x8a,
+  0x28, 0xa0, 0x0a, 0x28, 0xa2, 0x80, 0x28, 0xa2, 0x8a, 0x00, 0xa2, 0x8a,
+  0x28, 0x02, 0x8a, 0x28, 0xa0, 0x0a, 0x28, 0xa2, 0x80, 0x35, 0x45, 0x14,
+  0x50, 0x05, 0x14, 0x51, 0x40, 0x14, 0x51, 0x45, 0x00, 0x51, 0x45, 0x14,
+  0x01, 0x45, 0x14, 0x50, 0x05, 0x14, 0x51, 0x40, 0x14, 0x51, 0x45, 0x00,
+  0x51, 0x45, 0x14, 0x07, 0xff, 0xd9
+};
diff --git a/camera/libcameraservice/FakeCamera.cpp b/camera/libcameraservice/FakeCamera.cpp
new file mode 100644
index 0000000..3592eab
--- /dev/null
+++ b/camera/libcameraservice/FakeCamera.cpp
@@ -0,0 +1,404 @@
+#define LOG_TAG "FakeCamera"
+#include <utils/Log.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include "FakeCamera.h"
+
+namespace android {
+
+static int tables_initialized = 0;
+uint8_t *gYTable, *gCbTable, *gCrTable;
+
+static int
+clamp(int  x)
+{
+    if (x > 255) return 255;
+    if (x < 0)   return 0;
+    return x;
+}
+
+/* the equation used by the video code to translate YUV to RGB looks like this
+ *
+ *    Y  = (Y0 - 16)*k0
+ *    Cb = Cb0 - 128
+ *    Cr = Cr0 - 128
+ *
+ *    G = ( Y - k1*Cr - k2*Cb )
+ *    R = ( Y + k3*Cr )
+ *    B = ( Y + k4*Cb )
+ *
+ */
+
+static const double  k0 = 1.164;
+static const double  k1 = 0.813;
+static const double  k2 = 0.391;
+static const double  k3 = 1.596;
+static const double  k4 = 2.018;
+
+/* let's try to extract the value of Y
+ *
+ *   G + k1/k3*R + k2/k4*B = Y*( 1 + k1/k3 + k2/k4 )
+ *
+ *   Y  = ( G + k1/k3*R + k2/k4*B ) / (1 + k1/k3 + k2/k4)
+ *   Y0 = ( G0 + k1/k3*R0 + k2/k4*B0 ) / ((1 + k1/k3 + k2/k4)*k0) + 16
+ *
+ * let define:
+ *   kYr = k1/k3
+ *   kYb = k2/k4
+ *   kYy = k0 * ( 1 + kYr + kYb )
+ *
+ * we have:
+ *    Y  = ( G + kYr*R + kYb*B )
+ *    Y0 = clamp[ Y/kYy + 16 ]
+ */
+
+static const double kYr = k1/k3;
+static const double kYb = k2/k4;
+static const double kYy = k0*( 1. + kYr + kYb );
+
+static void
+initYtab( void )
+{
+    const  int imax = (int)( (kYr + kYb)*(31 << 2) + (61 << 3) + 0.1 );
+    int    i;
+
+    gYTable = (uint8_t *)malloc(imax);
+
+    for(i=0; i<imax; i++) {
+        int  x = (int)(i/kYy + 16.5);
+        if (x < 16) x = 16;
+        else if (x > 235) x = 235;
+        gYTable[i] = (uint8_t) x;
+    }
+}
+
+/*
+ *   the source is RGB565, so adjust for 8-bit range of input values:
+ *
+ *   G = (pixels >> 3) & 0xFC;
+ *   R = (pixels >> 8) & 0xF8;
+ *   B = (pixels & 0x1f) << 3;
+ *
+ *   R2 = (pixels >> 11)      R = R2*8
+ *   B2 = (pixels & 0x1f)     B = B2*8
+ *
+ *   kYr*R = kYr2*R2 =>  kYr2 = kYr*8
+ *   kYb*B = kYb2*B2 =>  kYb2 = kYb*8
+ *
+ *   we want to use integer multiplications:
+ *
+ *   SHIFT1 = 9
+ *
+ *   (ALPHA*R2) >> SHIFT1 == R*kYr  =>  ALPHA = kYr*8*(1 << SHIFT1)
+ *
+ *   ALPHA = kYr*(1 << (SHIFT1+3))
+ *   BETA  = kYb*(1 << (SHIFT1+3))
+ */
+
+static const int  SHIFT1  = 9;
+static const int  ALPHA   = (int)( kYr*(1 << (SHIFT1+3)) + 0.5 );
+static const int  BETA    = (int)( kYb*(1 << (SHIFT1+3)) + 0.5 );
+
+/*
+ *  now let's try to get the values of Cb and Cr
+ *
+ *  R-B = (k3*Cr - k4*Cb)
+ *
+ *    k3*Cr = k4*Cb + (R-B)
+ *    k4*Cb = k3*Cr - (R-B)
+ *
+ *  R-G = (k1+k3)*Cr + k2*Cb
+ *      = (k1+k3)*Cr + k2/k4*(k3*Cr - (R-B)/k0)
+ *      = (k1 + k3 + k2*k3/k4)*Cr - k2/k4*(R-B)
+ *
+ *  kRr*Cr = (R-G) + kYb*(R-B)
+ *
+ *  Cr  = ((R-G) + kYb*(R-B))/kRr
+ *  Cr0 = clamp(Cr + 128)
+ */
+
+static const double  kRr = (k1 + k3 + k2*k3/k4);
+
+static void
+initCrtab( void )
+{
+    uint8_t *pTable;
+    int i;
+
+    gCrTable = (uint8_t *)malloc(768*2);
+
+    pTable = gCrTable + 384;
+    for(i=-384; i<384; i++)
+        pTable[i] = (uint8_t) clamp( i/kRr + 128.5 );
+}
+
+/*
+ *  B-G = (k2 + k4)*Cb + k1*Cr
+ *      = (k2 + k4)*Cb + k1/k3*(k4*Cb + (R-B))
+ *      = (k2 + k4 + k1*k4/k3)*Cb + k1/k3*(R-B)
+ *
+ *  kBb*Cb = (B-G) - kYr*(R-B)
+ *
+ *  Cb   = ((B-G) - kYr*(R-B))/kBb
+ *  Cb0  = clamp(Cb + 128)
+ *
+ */
+
+static const double  kBb = (k2 + k4 + k1*k4/k3);
+
+static void
+initCbtab( void )
+{
+    uint8_t *pTable;
+    int i;
+
+    gCbTable = (uint8_t *)malloc(768*2);
+
+    pTable = gCbTable + 384;
+    for(i=-384; i<384; i++)
+        pTable[i] = (uint8_t) clamp( i/kBb + 128.5 );
+}
+
+/*
+ *   SHIFT2 = 16
+ *
+ *   DELTA = kYb*(1 << SHIFT2)
+ *   GAMMA = kYr*(1 << SHIFT2)
+ */
+
+static const int  SHIFT2 = 16;
+static const int  DELTA  = kYb*(1 << SHIFT2);
+static const int  GAMMA  = kYr*(1 << SHIFT2);
+
+int32_t ccrgb16toyuv_wo_colorkey(uint8_t *rgb16,uint8_t *yuv422,uint32_t *param,uint8_t *table[])
+{
+    uint16_t *inputRGB = (uint16_t*)rgb16;
+    uint8_t *outYUV =  yuv422;
+    int32_t width_dst = param[0];
+    int32_t height_dst = param[1];
+    int32_t pitch_dst = param[2];
+    int32_t mheight_dst = param[3];
+    int32_t pitch_src = param[4];
+    uint8_t *y_tab = table[0];
+    uint8_t *cb_tab = table[1];
+    uint8_t *cr_tab = table[2];
+
+    int32_t size16 = pitch_dst*mheight_dst;
+    int32_t i,j,count;
+    int32_t ilimit,jlimit;
+    uint8_t *tempY,*tempU,*tempV;
+    uint16_t pixels;
+    int   tmp;
+uint32_t temp;
+
+    tempY = outYUV;
+    tempU = outYUV + (height_dst * pitch_dst);
+    tempV = tempU + 1;
+
+    jlimit = height_dst;
+    ilimit = width_dst;
+
+    for(j=0; j<jlimit; j+=1)
+    {
+        for (i=0; i<ilimit; i+=2)
+        {
+            int32_t   G_ds = 0, B_ds = 0, R_ds = 0;
+            uint8_t   y0, y1, u, v;
+
+            pixels =  inputRGB[i];
+            temp = (ALPHA*(pixels & 0x001F) + BETA*(pixels>>11) );
+            y0   = y_tab[(temp>>SHIFT1) + ((pixels>>3) & 0x00FC)];
+
+            G_ds    += (pixels>>1) & 0x03E0;
+            B_ds    += (pixels<<5) & 0x03E0;
+            R_ds    += (pixels>>6) & 0x03E0;
+
+            pixels =  inputRGB[i+1];
+            temp = (ALPHA*(pixels & 0x001F) + BETA*(pixels>>11) );
+            y1   = y_tab[(temp>>SHIFT1) + ((pixels>>3) & 0x00FC)];
+
+            G_ds    += (pixels>>1) & 0x03E0;
+            B_ds    += (pixels<<5) & 0x03E0;
+            R_ds    += (pixels>>6) & 0x03E0;
+
+            R_ds >>= 1;
+            B_ds >>= 1;
+            G_ds >>= 1;
+
+            tmp = R_ds - B_ds;
+
+            u = cb_tab[(((R_ds-G_ds)<<SHIFT2) + DELTA*tmp)>>(SHIFT2+2)];
+            v = cr_tab[(((B_ds-G_ds)<<SHIFT2) - GAMMA*tmp)>>(SHIFT2+2)];
+
+            tempY[0] = y0;
+            tempY[1] = y1;
+            tempU[0] = u;
+            tempV[0] = v;
+
+            tempY += 2;
+            tempU += 2;
+            tempV += 2;
+        }
+
+        inputRGB += pitch_src;
+    }
+
+    return 1;
+}
+
+#define min(a,b) ((a)<(b)?(a):(b))
+#define max(a,b) ((a)>(b)?(a):(b))
+
+static void convert_rgb16_to_yuv422(uint8_t *rgb, uint8_t *yuv, int width, int height)
+{
+    if (!tables_initialized) {
+        initYtab();
+        initCrtab();
+        initCbtab();
+        tables_initialized = 1;
+    }
+
+    uint32_t param[6];
+    param[0] = (uint32_t) width;
+    param[1] = (uint32_t) height;
+    param[2] = (uint32_t) width;
+    param[3] = (uint32_t) height;
+    param[4] = (uint32_t) width;
+    param[5] = (uint32_t) 0;
+
+    uint8_t *table[3];
+    table[0] = gYTable;
+    table[1] = gCbTable + 384;
+    table[2] = gCrTable + 384;
+
+    ccrgb16toyuv_wo_colorkey(rgb, yuv, param, table);
+}
+
+const int FakeCamera::kRed;
+const int FakeCamera::kGreen;
+const int FakeCamera::kBlue;
+
+FakeCamera::FakeCamera(int width, int height)
+          : mTmpRgb16Buffer(0)
+{
+    setSize(width, height);
+}
+
+FakeCamera::~FakeCamera()
+{
+    delete[] mTmpRgb16Buffer;
+}
+
+void FakeCamera::setSize(int width, int height)
+{
+    mWidth = width;
+    mHeight = height;
+    mCounter = 0;
+    mCheckX = 0;
+    mCheckY = 0;
+
+    // This will cause it to be reallocated on the next call
+    // to getNextFrameAsYuv422().
+    delete[] mTmpRgb16Buffer;
+    mTmpRgb16Buffer = 0;
+}
+
+void FakeCamera::getNextFrameAsRgb565(uint16_t *buffer)
+{
+    int size = mWidth / 10;
+
+    drawCheckerboard(buffer, size);
+
+    int x = ((mCounter*3)&255);
+    if(x>128) x = 255 - x;
+    int y = ((mCounter*5)&255);
+    if(y>128) y = 255 - y;
+
+    drawSquare(buffer, x*size/32, y*size/32, (size*5)>>1, (mCounter&0x100)?kRed:kGreen, kBlue);
+
+    mCounter++;
+}
+
+void FakeCamera::getNextFrameAsYuv422(uint8_t *buffer)
+{
+    if (mTmpRgb16Buffer == 0)
+        mTmpRgb16Buffer = new uint16_t[mWidth * mHeight];
+
+    getNextFrameAsRgb565(mTmpRgb16Buffer);
+    convert_rgb16_to_yuv422((uint8_t*)mTmpRgb16Buffer, buffer, mWidth, mHeight);
+}
+
+void FakeCamera::drawSquare(uint16_t *dst, int x, int y, int size, int color, int shadow)
+{
+    int square_xstop, square_ystop, shadow_xstop, shadow_ystop;
+
+    square_xstop = min(mWidth, x+size);
+    square_ystop = min(mHeight, y+size);
+    shadow_xstop = min(mWidth, x+size+(size/4));
+    shadow_ystop = min(mHeight, y+size+(size/4));
+
+    // Do the shadow.
+    uint16_t *sh = &dst[(y+(size/4))*mWidth];
+    for (int j = y + (size/4); j < shadow_ystop; j++) {
+        for (int i = x + (size/4); i < shadow_xstop; i++) {
+            sh[i] &= shadow;
+        }
+        sh += mWidth;
+    }
+
+    // Draw the square.
+    uint16_t *sq = &dst[y*mWidth];
+    for (int j = y; j < square_ystop; j++) {
+        for (int i = x; i < square_xstop; i++) {
+            sq[i] = color;
+        }
+        sq += mWidth;
+    }
+}
+
+void FakeCamera::drawCheckerboard(uint16_t *dst, int size)
+{
+    bool black = true;
+
+    if((mCheckX/size)&1)
+        black = false;
+    if((mCheckY/size)&1)
+        black = !black;
+
+    int county = mCheckY%size;
+    int checkxremainder = mCheckX%size;
+
+    for(int y=0;y<mHeight;y++) {
+        int countx = checkxremainder;
+        bool current = black;
+        for(int x=0;x<mWidth;x++) {
+            dst[y*mWidth+x] = current?0:0xffff;
+            if(countx++ >= size) {
+                countx=0;
+                current = !current;
+            }
+        }
+        if(county++ >= size) {
+            county=0;
+            black = !black;
+        }
+    }
+    mCheckX += 3;
+    mCheckY++;
+}
+
+
+status_t FakeCamera::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, 255, " width x height (%d x %d), counter (%d), check x-y coordinate(%d, %d)\n", mWidth, mHeight, mCounter, mCheckX, mCheckY);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+
+}; // namespace android
diff --git a/camera/libcameraservice/FakeCamera.h b/camera/libcameraservice/FakeCamera.h
new file mode 100644
index 0000000..77c994c
--- /dev/null
+++ b/camera/libcameraservice/FakeCamera.h
@@ -0,0 +1,51 @@
+/*
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_HARDWARE_FAKECAMERA_H
+#define ANDROID_HARDWARE_FAKECAMERA_H
+
+#include <ui/CameraHardwareInterface.h>
+
+namespace android {
+
+class FakeCamera {
+public:
+    FakeCamera(int width, int height);
+    ~FakeCamera();
+
+    void setSize(int width, int height);
+    void getNextFrameAsRgb565(uint16_t *buffer);
+    void getNextFrameAsYuv422(uint8_t *buffer);
+    status_t dump(int fd, const Vector<String16>& args);
+
+private:
+    void drawSquare(uint16_t *buffer, int x, int y, int size, int color, int shadow);
+    void drawCheckerboard(uint16_t *buffer, int size);
+
+    static const int kRed = 0xf800;
+    static const int kGreen = 0x07c0;
+    static const int kBlue = 0x003e;
+
+    int         mWidth, mHeight;
+    int         mCounter;
+    int         mCheckX, mCheckY;
+    uint16_t    *mTmpRgb16Buffer;
+};
+
+}; // namespace android
+
+#endif // ANDROID_HARDWARE_FAKECAMERA_H
diff --git a/cmds/runtime/Android.mk b/cmds/runtime/Android.mk
new file mode 100644
index 0000000..521eb2b
--- /dev/null
+++ b/cmds/runtime/Android.mk
@@ -0,0 +1,29 @@
+ifeq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	ServiceManager.cpp \
+	SignalHandler.cpp \
+	main_runtime.cpp 
+
+LOCAL_SHARED_LIBRARIES := \
+	libutils \
+	libandroid_runtime \
+	libcutils \
+	libui \
+	libsystem_server \
+	libhardware_legacy
+
+LOCAL_C_INCLUDES := \
+	$(JNI_H_INCLUDE)
+
+ifeq ($(TARGET_OS),linux)
+	LOCAL_CFLAGS += -DXP_UNIX
+endif
+
+LOCAL_MODULE:= runtime
+
+include $(BUILD_EXECUTABLE)
+endif
diff --git a/cmds/runtime/MODULE_LICENSE_APACHE2 b/cmds/runtime/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/runtime/MODULE_LICENSE_APACHE2
diff --git a/cmds/runtime/NOTICE b/cmds/runtime/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/cmds/runtime/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/cmds/runtime/ServiceManager.cpp b/cmds/runtime/ServiceManager.cpp
new file mode 100644
index 0000000..758a95c
--- /dev/null
+++ b/cmds/runtime/ServiceManager.cpp
@@ -0,0 +1,74 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+
+#define LOG_TAG "ServiceManager"
+
+#include "ServiceManager.h"
+#include "SignalHandler.h"
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <utils/String8.h>
+#include <utils/ProcessState.h>
+
+#include <private/utils/Static.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+namespace android {
+
+BServiceManager::BServiceManager()
+{
+}
+
+sp<IBinder> BServiceManager::getService(const String16& name) const
+{
+    AutoMutex _l(mLock);
+    ssize_t i = mServices.indexOfKey(name);
+    LOGV("ServiceManager: getService(%s) -> %d\n", String8(name).string(), i);
+    if (i >= 0) return mServices.valueAt(i);
+    return NULL;
+}
+
+sp<IBinder> BServiceManager::checkService(const String16& name) const
+{
+    AutoMutex _l(mLock);
+    ssize_t i = mServices.indexOfKey(name);
+    LOGV("ServiceManager: getService(%s) -> %d\n", String8(name).string(), i);
+    if (i >= 0) return mServices.valueAt(i);
+    return NULL;
+}
+
+status_t BServiceManager::addService(const String16& name, const sp<IBinder>& service)
+{
+    AutoMutex _l(mLock);
+    LOGI("ServiceManager: addService(%s, %p)\n", String8(name).string(), service.get());
+    const ssize_t res = mServices.add(name, service);
+    if (res >= NO_ERROR) {
+        mChanged.broadcast();
+        return NO_ERROR;
+    }
+    return res;
+}
+
+Vector<String16> BServiceManager::listServices()
+{
+    Vector<String16> res;
+
+    AutoMutex _l(mLock);
+    const size_t N = mServices.size();
+    for (size_t i=0; i<N; i++) {
+        res.add(mServices.keyAt(i));
+    }
+
+    return res;
+}
+
+}; // namespace android
diff --git a/cmds/runtime/ServiceManager.h b/cmds/runtime/ServiceManager.h
new file mode 100644
index 0000000..d09cec8
--- /dev/null
+++ b/cmds/runtime/ServiceManager.h
@@ -0,0 +1,38 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+#ifndef ANDROID_SERVICE_MANAGER_H
+#define ANDROID_SERVICE_MANAGER_H
+
+#include <utils/IServiceManager.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BServiceManager : public BnServiceManager
+{
+public:
+                                BServiceManager();
+    
+    virtual sp<IBinder>         getService( const String16& name) const;
+    virtual sp<IBinder>         checkService( const String16& name) const;
+    virtual status_t            addService( const String16& name,
+                                            const sp<IBinder>& service);
+    virtual Vector<String16>    listServices();
+
+    
+private:
+    mutable Mutex               mLock;
+    mutable Condition           mChanged;
+    sp<IPermissionController>   mPermissionController;
+    KeyedVector<String16, sp<IBinder> > mServices;
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_SERVICE_MANAGER_H
diff --git a/cmds/runtime/SignalHandler.cpp b/cmds/runtime/SignalHandler.cpp
new file mode 100644
index 0000000..cccaabf
--- /dev/null
+++ b/cmds/runtime/SignalHandler.cpp
@@ -0,0 +1,249 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+
+#define LOG_TAG "SignalHandler"
+
+#include "SignalHandler.h"
+
+#include <utils/Atomic.h>
+#include <utils/Debug.h>
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+namespace android {
+
+class SignalHandler::ProcessThread : public Thread
+{
+public:
+    ProcessThread(SignalHandler& sh)
+        : Thread(false)
+        , mOwner(sh)
+    {
+    }
+
+    virtual bool threadLoop()
+    {
+        char buffer[32];
+        read(mOwner.mAvailMsg[0], buffer, sizeof(buffer));
+
+        LOGV("Signal command processing thread woke up!");
+
+        if (mOwner.mLostCommands) {
+            LOGE("Lost %d signals!", mOwner.mLostCommands);
+            mOwner.mLostCommands = 0;
+        }
+
+        int cur;
+        while ((cur=mOwner.mCommandBottom) != mOwner.mCommandTop) {
+            if (mOwner.mCommands[cur].filled == 0) {
+                LOGV("Command at %d is not yet filled", cur);
+                break;
+            }
+
+            LOGV("Processing command at %d, top is %d",
+                 cur, mOwner.mCommandTop);
+            processCommand(mOwner.mCommands[cur]);
+            mOwner.mCommands[cur].filled = 0;
+
+            int next = mOwner.mCommandBottom+1;
+            if (next >= COMMAND_QUEUE_SIZE) {
+                next = 0;
+            }
+
+            mOwner.mCommandBottom = next;
+        }
+
+        return true;
+    }
+
+    void processCommand(const CommandEntry& entry)
+    {
+        switch (entry.signum) {
+        case SIGCHLD: {
+            mOwner.mLock.lock();
+            ssize_t i = mOwner.mChildHandlers.indexOfKey(entry.info.si_pid);
+            ChildHandler ch;
+            if (i >= 0) {
+                ch = mOwner.mChildHandlers.valueAt(i);
+                mOwner.mChildHandlers.removeItemsAt(i);
+            }
+            mOwner.mLock.unlock();
+
+            LOGD("SIGCHLD: pid=%d, handle index=%d", entry.info.si_pid, i);
+
+            if (i >= 0) {
+                int res = waitpid(entry.info.si_pid, NULL, WNOHANG);
+                LOGW_IF(res == 0,
+                        "Received SIGCHLD, but pid %d is not yet stopped",
+                        entry.info.si_pid);
+                if (ch.handler) {
+                    ch.handler(entry.info.si_pid, ch.userData);
+                }
+            } else {
+                LOGW("Unhandled SIGCHLD for pid %d", entry.info.si_pid);
+            }
+        } break;
+        }
+    }
+
+    SignalHandler& mOwner;
+};
+
+
+Mutex SignalHandler::mInstanceLock;
+SignalHandler* SignalHandler::mInstance = NULL;
+
+status_t SignalHandler::setChildHandler(pid_t childPid,
+                                        int tag,
+                                        child_callback_t handler,
+                                        void* userData)
+{
+    SignalHandler* const self = getInstance();
+
+    self->mLock.lock();
+
+    // First make sure this child hasn't already exited.
+    pid_t res = waitpid(childPid, NULL, WNOHANG);
+    if (res != 0) {
+        if (res < 0) {
+            LOGW("setChildHandler waitpid of %d failed: %d (%s)",
+                 childPid, res, strerror(errno));
+        } else {
+            LOGW("setChildHandler waitpid of %d said %d already dead",
+                 childPid, res);
+        }
+
+        // Some kind of error...  just handle the exit now.
+        self->mLock.unlock();
+
+        if (handler) {
+            handler(childPid, userData);
+        }
+
+        // Return an error code -- 0 means it already exited.
+        return (status_t)res;
+    }
+
+    ChildHandler entry;
+    entry.childPid = childPid;
+    entry.tag = tag;
+    entry.handler = handler;
+    entry.userData = userData;
+
+    // Note: this replaces an existing entry for this pid, if there already
+    // is one.  This is the required behavior.
+    LOGD("setChildHandler adding pid %d, tag %d, handler %p, data %p",
+         childPid, tag, handler, userData);
+    self->mChildHandlers.add(childPid, entry);
+
+    self->mLock.unlock();
+
+    return NO_ERROR;
+}
+
+void SignalHandler::killAllChildren(int tag)
+{
+    SignalHandler* const self = getInstance();
+
+    AutoMutex _l (self->mLock);
+    const size_t N = self->mChildHandlers.size();
+    for (size_t i=0; i<N; i++) {
+        const ChildHandler& ch(self->mChildHandlers.valueAt(i));
+        if (tag == 0 || ch.tag == tag) {
+            const pid_t pid = ch.childPid;
+            LOGI("Killing child %d (tag %d)\n", pid, ch.tag);
+            kill(pid, SIGKILL);
+        }
+    }
+}
+
+SignalHandler::SignalHandler()
+    : mCommandTop(0)
+    , mCommandBottom(0)
+    , mLostCommands(0)
+{
+    memset(mCommands, 0, sizeof(mCommands));
+
+    int res = pipe(mAvailMsg);
+    LOGE_IF(res != 0, "Unable to create signal handler pipe: %s", strerror(errno));
+
+    mProcessThread = new ProcessThread(*this);
+    mProcessThread->run("SignalHandler", PRIORITY_HIGHEST);
+
+    struct sigaction sa;
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_sigaction = sigAction;
+    sa.sa_flags = SA_NOCLDSTOP|SA_SIGINFO;
+    sigaction(SIGCHLD, &sa, NULL);
+}
+
+SignalHandler::~SignalHandler()
+{
+}
+
+SignalHandler* SignalHandler::getInstance()
+{
+    AutoMutex _l(mInstanceLock);
+    if (mInstance == NULL) {
+        mInstance = new SignalHandler();
+    }
+    return mInstance;
+}
+
+void SignalHandler::sigAction(int signum, siginfo_t* info, void*)
+{
+    static const char wakeupMsg[1] = { 0xff };
+
+    // If our signal handler is being called, then we know we have
+    // already initialized the SignalHandler class and thus mInstance
+    // is valid.
+    SignalHandler* const self = mInstance;
+
+    // XXX This is not safe!
+    #if 0
+    LOGV("Signal %d: signo=%d, errno=%d, code=%d, pid=%d\n",
+           signum,
+           info->si_signo, info->si_errno, info->si_code,
+           info->si_pid);
+    #endif
+
+    int32_t oldTop, newTop;
+
+    // Find the next command slot...
+    do {
+        oldTop = self->mCommandTop;
+
+        newTop = oldTop + 1;
+        if (newTop >= COMMAND_QUEUE_SIZE) {
+            newTop = 0;
+        }
+
+        if (newTop == self->mCommandBottom) {
+            // The buffer is filled up!  Ouch!
+            // XXX This is not safe!
+            #if 0
+            LOGE("Command buffer overflow!  newTop=%d\n", newTop);
+            #endif
+            android_atomic_add(1, &self->mLostCommands);
+            write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
+            return;
+        }
+    } while(android_atomic_cmpxchg(oldTop, newTop, &(self->mCommandTop)));
+
+    // Fill in the command data...
+    self->mCommands[oldTop].signum = signum;
+    self->mCommands[oldTop].info = *info;
+
+    // And now make this command available.
+    self->mCommands[oldTop].filled = 1;
+
+    // Wake up the processing thread.
+    write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
+}
+
+}; // namespace android
+
diff --git a/cmds/runtime/SignalHandler.h b/cmds/runtime/SignalHandler.h
new file mode 100644
index 0000000..7f4ef8e
--- /dev/null
+++ b/cmds/runtime/SignalHandler.h
@@ -0,0 +1,137 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+#ifndef ANDROID_SIGNAL_HANDLER_H
+#define ANDROID_SIGNAL_HANDLER_H
+
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+#include <signal.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+enum {
+    DEFAULT_PROCESS_TAG = 1
+};
+
+class SignalHandler
+{
+public:
+    typedef void (*child_callback_t)(pid_t child, void* userData);
+
+    /**
+     * Set a handler for when a child process exits.  By calling
+     * this, a waitpid() will be done when the child exits to remove
+     * it from the zombie state.  You can also optionally specify a
+     * handler to be called when the child exits.
+     * 
+     * If there is already a handler for this child process, it is
+     * replaced by this new handler.  In this case the old handler's
+     * function is not called.
+     * 
+     * @param childPid Process ID of child to watch.
+     * @param childTag User-defined tag for this child.  Must be
+     *                 greater than zero.
+     * @param handler If non-NULL, this will be called when the
+     *                child exits.  It may be called in either a
+     *                separate signal handling thread, or
+     *                immediately if the child has already exited.
+     * @param userData Propageted as-is to handler.
+     * 
+     * @return status_t NO_ERROR if all is well.
+     */
+    static status_t             setChildHandler(pid_t childPid,
+                                                int childTag = DEFAULT_PROCESS_TAG,
+                                                child_callback_t handler = NULL,
+                                                void* userData = NULL);
+
+    /**
+     * Kill all of the child processes for which we have a waiting
+     * handler, whose tag is the given value.  If tag is 0, all
+     * children are killed.
+     * 
+     * @param tag
+     */
+    static void                 killAllChildren(int tag = 0);
+
+private:
+                                SignalHandler();
+                                ~SignalHandler();
+
+    static SignalHandler*       getInstance();
+
+    static void                 sigAction(int, siginfo_t*, void*);
+
+    // --------------------------------------------------
+    // Shared state...  all of this is protected by mLock.
+    // --------------------------------------------------
+
+    mutable Mutex                       mLock;
+
+    struct ChildHandler
+    {
+        pid_t childPid;
+        int tag;
+        child_callback_t handler;
+        void* userData;
+    };
+    KeyedVector<pid_t, ChildHandler>    mChildHandlers;
+
+    // --------------------------------------------------
+    // Commmand queue...  data is inserted by the signal
+    // handler using atomic ops, and retrieved by the
+    // signal processing thread.  Because these are touched
+    // by the signal handler, no lock is used.
+    // --------------------------------------------------
+
+    enum {
+        COMMAND_QUEUE_SIZE = 64
+    };
+    struct CommandEntry
+    {
+        int filled;
+        int signum;
+        siginfo_t info;
+    };
+
+    // The top of the queue.  This is incremented atomically by the
+    // signal handler before placing a command in the queue.
+    volatile int32_t                    mCommandTop;
+
+    // The bottom of the queue.  Only modified by the processing
+    // thread; the signal handler reads it only to determine if the
+    // queue is full.
+    int32_t                             mCommandBottom;
+
+    // Incremented each time we receive a signal and don't have room
+    // for it on the command queue.
+    volatile int32_t                    mLostCommands;
+
+    // The command processing thread.
+    class ProcessThread;
+    sp<Thread>                          mProcessThread;
+
+    // Pipe used to tell command processing thread when new commands.
+    // are available.  The thread blocks on the read end, the signal
+    // handler writes when it enqueues new commands.
+    int                                 mAvailMsg[2];
+
+    // The commands.
+    CommandEntry                        mCommands[COMMAND_QUEUE_SIZE];
+
+    // --------------------------------------------------
+    // Singleton.
+    // --------------------------------------------------
+
+    static Mutex                        mInstanceLock;
+    static SignalHandler*               mInstance;
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_SIGNAL_HANDLER_H
diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp
new file mode 100644
index 0000000..1531a9e
--- /dev/null
+++ b/cmds/runtime/main_runtime.cpp
@@ -0,0 +1,514 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+// Main entry point for runtime.
+//
+
+#include "ServiceManager.h"
+#include "SignalHandler.h"
+
+#include <utils.h>
+#include <utils/IPCThreadState.h>
+#include <utils/ProcessState.h>
+#include <utils/Log.h>  
+#include <cutils/zygote.h>
+
+#include <cutils/properties.h>
+
+#include <private/utils/Static.h>
+
+#include <ui/ISurfaceComposer.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <linux/capability.h>
+#include <linux/ioctl.h>
+#ifdef HAVE_ANDROID_OS
+# include <linux/android_alarm.h>
+#endif
+
+#undef LOG_TAG
+#define LOG_TAG "runtime"
+
+static const char* ZYGOTE_ARGV[] = { 
+    "--setuid=1000",
+    "--setgid=1000",
+    "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
+    /* CAP_SYS_TTY_CONFIG & CAP_SYS_RESOURCE & CAP_NET_BROADCAST &
+     * CAP_NET_ADMIN & CAP_NET_RAW & CAP_NET_BIND_SERVICE  & CAP_KILL &
+     * CAP_SYS_BOOT
+     */
+    "--capabilities=88161312,88161312",
+    "--runtime-init",
+    "--nice-name=system_server",
+    "com.android.server.SystemServer"
+};
+
+using namespace android;
+
+extern "C" status_t system_init();
+
+enum {
+    SYSTEM_PROCESS_TAG = DEFAULT_PROCESS_TAG+1
+};
+
+extern Mutex gEventQMutex;
+extern Condition gEventQCondition;
+
+namespace android {
+
+extern status_t app_init(const char* className);
+extern void set_finish_init_func(void (*func)());
+
+
+/**
+ * This class is used to kill this process (runtime) when the system_server dies.
+ */
+class GrimReaper : public IBinder::DeathRecipient {
+public: 
+    GrimReaper() { }
+
+    virtual void binderDied(const wp<IBinder>& who)
+    {
+        LOGI("Grim Reaper killing runtime...");
+        kill(getpid(), SIGKILL);
+    }
+};
+
+extern void QuickTests();
+
+/*
+ * Print usage info.
+ */
+static void usage(const char* argv0)
+{
+    fprintf(stderr,
+        "Usage: runtime [-g gamma] [-l logfile] [-n] [-s]\n"
+        "               [-j app-component] [-v app-verb] [-d app-data]\n"
+        "\n"
+        "-l: File to send log messages to\n"
+        "-n: Don't print to stdout/stderr\n"
+        "-s: Force single-process mode\n"
+        "-j: Custom home app component name\n"
+        "-v: Custom home app intent verb\n"
+        "-d: Custom home app intent data\n"
+    );
+    exit(1);
+}
+
+// Selected application to run.
+static const char* gInitialApplication = NULL;
+static const char* gInitialVerb = NULL;
+static const char* gInitialData = NULL;
+
+static void writeStringToParcel(Parcel& parcel, const char* str)
+{
+    if (str) {
+        parcel.writeString16(String16(str));
+    } else {
+        parcel.writeString16(NULL, 0);
+    }
+}
+
+/*
+ * Starting point for program logic.
+ *
+ * Returns with an exit status code (0 on success, nonzero on error).
+ */
+static int run(sp<ProcessState>& proc)
+{
+    // Temporary hack to call startRunning() on the activity manager.
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> am;
+    while ((am = sm->getService(String16("activity"))) == NULL) {
+        LOGI("Waiting for activity manager...");
+    }
+    Parcel data, reply;
+    // XXX Need to also supply a package name for this to work again.
+    // IActivityManager::getInterfaceDescriptor() is the token for invoking on this interface;
+    // hardcoding it here avoids having to link with the full Activity Manager library
+    data.writeInterfaceToken(String16("android.app.IActivityManager"));
+    writeStringToParcel(data, NULL);
+    writeStringToParcel(data, gInitialApplication);
+    writeStringToParcel(data, gInitialVerb);
+    writeStringToParcel(data, gInitialData);
+LOGI("run() sending FIRST_CALL_TRANSACTION to activity manager");
+    am->transact(IBinder::FIRST_CALL_TRANSACTION, data, &reply);
+
+    if (proc->supportsProcesses()) {
+        // Now we link to the Activity Manager waiting for it to die. If it does kill ourself.
+        // initd will restart this process and bring the system back up.
+        sp<GrimReaper> grim = new GrimReaper();
+        am->linkToDeath(grim, grim.get(), 0);
+
+        // Now join the thread pool. Note this is needed so that the message enqueued in the driver
+        // for the linkToDeath gets processed.
+        IPCThreadState::self()->joinThreadPool();
+    } else {
+        // Keep this thread running forever...
+        while (1) {
+            usleep(100000);
+        }
+    }
+    return 1;
+}
+
+
+};  // namespace android
+
+
+/*
+ * Post-system-process initialization.
+ * 
+ * This function continues initialization after the system process
+ * has been initialized.  It needs to be separate because the system
+ * initialization needs to care of starting the Android runtime if it is not
+ * running in its own process, which doesn't return until the runtime is
+ * being shut down.  So it will call back to here from inside of Dalvik,
+ * to allow us to continue booting up.
+ */
+static void finish_system_init(sp<ProcessState>& proc)
+{
+    // If we are running multiprocess, we now need to have the
+    // thread pool started here.  We don't do this in boot_init()
+    // because when running single process we need to start the
+    // thread pool after the Android runtime has been started (so
+    // the pool uses Dalvik threads).
+    if (proc->supportsProcesses()) {
+        proc->startThreadPool();
+    }
+}
+
+
+// This function can be used to enforce security to different
+// root contexts.  For now, we just give every access.
+static bool contextChecker(
+    const String16& name, const sp<IBinder>& caller, void* userData)
+{
+    return true;
+}
+
+/*
+ * Initialization of boot services.
+ *
+ * This is where we perform initialization of all of our low-level
+ * boot services.  Most importantly, here we become the context
+ * manager and use that to publish the service manager that will provide
+ * access to all other services.
+ */
+static void boot_init()
+{
+    LOGI("Entered boot_init()!\n");
+    
+    sp<ProcessState> proc(ProcessState::self());
+    LOGD("ProcessState: %p\n", proc.get());
+    proc->becomeContextManager(contextChecker, NULL);
+    
+    if (proc->supportsProcesses()) {
+        LOGI("Binder driver opened.  Multiprocess enabled.\n");
+    } else {
+        LOGI("Binder driver not found.  Processes not supported.\n");
+    }
+    
+    sp<BServiceManager> sm = new BServiceManager;
+    proc->setContextObject(sm);
+}
+
+/*
+ * Redirect stdin/stdout/stderr to /dev/null.
+ */
+static void redirectStdFds(void)
+{
+    int fd = open("/dev/null", O_RDWR, 0);
+    if (fd < 0) {
+        LOGW("Unable to open /dev/null: %s\n", strerror(errno));
+    } else {
+        dup2(fd, 0);
+        dup2(fd, 1);
+        dup2(fd, 2);
+        close(fd);
+    }
+}
+
+static int hasDir(const char* dir)
+{
+    struct stat s;
+    int res = stat(dir, &s);
+    if (res == 0) {
+        return S_ISDIR(s.st_mode);
+    }
+    return 0;
+}
+
+static void validateTime()
+{
+#if HAVE_ANDROID_OS
+    int fd;
+    int res;
+    time_t min_time = 1167652800; // jan 1 2007, type 'date -ud "1/1 12:00" +%s' to get value for current year
+    struct timespec ts;
+    
+    fd = open("/dev/alarm", O_RDWR);
+    if(fd < 0) {
+        LOGW("Unable to open alarm driver: %s\n", strerror(errno));
+        return;
+    }
+    res = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_RTC_WAKEUP), &ts);
+    if(res < 0) {
+        LOGW("Unable to read rtc, %s\n", strerror(errno));
+    }
+    else if(ts.tv_sec >= min_time) {
+        goto done;
+    }
+    LOGW("Invalid time detected, %ld set to %ld\n", ts.tv_sec, min_time);
+    ts.tv_sec = min_time;
+    ts.tv_nsec = 0;
+    res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
+    if(res < 0) {
+        LOGW("Unable to set rtc to %ld: %s\n", ts.tv_sec, strerror(errno));
+    }
+done:
+    close(fd);
+#endif
+}
+
+#ifndef HAVE_ANDROID_OS
+class QuickRuntime : public AndroidRuntime
+{
+public:
+    QuickRuntime() {}
+
+    virtual void onStarted()
+    {
+        printf("QuickRuntime: onStarted\n");
+    }
+};
+#endif
+
+static status_t start_process(const char* name);
+
+static void restart_me(pid_t child, void* userData)
+{
+    start_process((const char*)userData);
+}
+
+static status_t start_process(const char* name)
+{
+    String8 path(name);
+    Vector<const char*> args;
+    String8 leaf(path.getPathLeaf());
+    String8 parentDir(path.getPathDir());
+    args.insertAt(leaf.string(), 0);
+    args.add(parentDir.string());
+    args.add(NULL);
+    pid_t child = fork();
+    if (child < 0) {
+        status_t err = errno;
+        LOGE("*** fork of child %s failed: %s", leaf.string(), strerror(err));
+        return -errno;
+    } else if (child == 0) {
+        LOGI("Executing: %s", path.string());
+        execv(path.string(), const_cast<char**>(args.array()));
+        int err = errno;
+        LOGE("Exec failed: %s\n", strerror(err));
+        _exit(err);
+    } else {
+        SignalHandler::setChildHandler(child, DEFAULT_PROCESS_TAG,
+                restart_me, (void*)name);
+    }
+    return -errno;
+}
+
+/*
+ * Application entry point.
+ *
+ * Parse arguments, set some values, and pass control off to Run().
+ *
+ * This is redefined to "SDL_main" on SDL simulator builds, and
+ * "runtime_main" on wxWidgets builds.
+ */
+extern "C"
+int main(int argc, char* const argv[])
+{
+    bool singleProcess = false;
+    const char* logFile = NULL;
+    int ic;
+    int result = 1;
+    pid_t systemPid;
+    
+    sp<ProcessState> proc;
+
+#ifndef HAVE_ANDROID_OS
+    /* Set stdout/stderr to unbuffered for MinGW/MSYS. */
+    //setvbuf(stdout, NULL, _IONBF, 0);
+    //setvbuf(stderr, NULL, _IONBF, 0);
+    
+    LOGI("commandline args:\n");
+    for (int i = 0; i < argc; i++)
+        LOGI("  %2d: '%s'\n", i, argv[i]);
+#endif
+
+    while (1) {
+        ic = getopt(argc, argv, "g:j:v:d:l:ns");
+        if (ic < 0)
+            break;
+
+        switch (ic) {
+        case 'g':
+            break;
+        case 'j':
+            gInitialApplication = optarg;
+            break;
+        case 'v':
+            gInitialVerb = optarg;
+            break;
+        case 'd':
+            gInitialData = optarg;
+            break;
+        case 'l':
+            logFile = optarg;
+            break;
+        case 'n':
+            redirectStdFds();
+            break;
+        case 's':
+            singleProcess = true;
+            break;
+        case '?':
+        default:
+            LOGE("runtime: unrecognized flag -%c\n", ic);
+            usage(argv[0]);
+            break;
+        }
+    }
+    if (optind < argc) {
+        LOGE("runtime: extra stuff: %s\n", argv[optind]);
+        usage(argv[0]);
+    }
+
+    if (singleProcess) {
+        ProcessState::setSingleProcess(true);
+    }
+
+    if (logFile != NULL) {
+        android_logToFile(NULL, logFile);
+    }
+
+    /*
+     * Set up ANDROID_* environment variables.
+     *
+     * TODO: the use of $ANDROID_PRODUCT_OUT will go away soon.
+     */
+    static const char* kSystemDir = "/system";
+    static const char* kDataDir = "/data";
+    static const char* kAppSubdir = "/app";
+    const char* out = NULL;
+#ifndef HAVE_ANDROID_OS
+    //out = getenv("ANDROID_PRODUCT_OUT");
+#endif
+    if (out == NULL)
+        out = "";
+
+    char* systemDir = (char*) malloc(strlen(out) + strlen(kSystemDir) +1);
+    char* dataDir = (char*) malloc(strlen(out) + strlen(kDataDir) +1);
+
+    sprintf(systemDir, "%s%s", out, kSystemDir);
+    sprintf(dataDir, "%s%s", out, kDataDir);
+    setenv("ANDROID_ROOT", systemDir, 1);
+    setenv("ANDROID_DATA", dataDir, 1);
+
+    char* assetDir = (char*) malloc(strlen(systemDir) + strlen(kAppSubdir) +1);
+    sprintf(assetDir, "%s%s", systemDir, kAppSubdir);
+
+    LOGI("Startup: sys='%s' asset='%s' data='%s'\n",
+        systemDir, assetDir, dataDir);
+    free(systemDir);
+    free(dataDir);
+
+#ifdef HAVE_ANDROID_OS
+    /* set up a process group for easier killing on the device */
+    setpgid(0, getpid());
+#endif
+
+    // Change to asset dir.  This is only necessary if we've changed to
+    // a different directory, but there's little harm in doing it regardless.
+    //
+    // Expecting assets to live in the current dir is not a great idea,
+    // because some of our code or one of our libraries could change the
+    // directory out from under us.  Preserve the behavior for now.
+    if (chdir(assetDir) != 0) {
+        LOGW("WARNING: could not change dir to '%s': %s\n",
+             assetDir, strerror(errno));
+    }
+    free(assetDir);
+
+#if 0
+    // Hack to keep libc from beating the filesystem to death.  It's
+    // hitting /etc/localtime frequently, 
+    //
+    // This statement locks us into Pacific time.  We could do better,
+    // but there's not much point until we're sure that the library
+    // can't be changed to do more along the lines of what we want.
+#ifndef XP_WIN
+    setenv("TZ", "PST+8PDT,M4.1.0/2,M10.5.0/2", true);
+#endif
+#endif
+
+    /* track our progress through the boot sequence */
+    const int LOG_BOOT_PROGRESS_START = 3000;
+    LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, 
+        ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+
+    validateTime();
+
+    proc = ProcessState::self();
+    
+    boot_init();
+    
+    /* If we are in multiprocess mode, have zygote spawn the system
+     * server process and call system_init(). If we are running in
+     * single process mode just call system_init() directly.
+     */
+    if (proc->supportsProcesses()) {
+        // If stdio logging is on, system_server should not inherit our stdio
+        // The dalvikvm instance will copy stdio to the log on its own
+        char propBuf[PROPERTY_VALUE_MAX];
+        bool logStdio = false;
+        property_get("log.redirect-stdio", propBuf, "");
+        logStdio = (strcmp(propBuf, "true") == 0);
+
+        zygote_run_oneshot((int)(!logStdio), 
+                sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]), 
+                ZYGOTE_ARGV);
+
+        //start_process("/system/bin/mediaserver");
+
+    } else {
+#ifndef HAVE_ANDROID_OS
+        QuickRuntime* runt = new QuickRuntime();
+        runt->start("com/android/server/SystemServer", 
+                    false /* spontaneously fork system server from zygote */);
+#endif
+    }
+
+    //printf("+++ post-zygote\n");
+
+    finish_system_init(proc);
+    run(proc);
+    
+bail:
+    if (proc != NULL) {
+        proc->setContextObject(NULL);
+    }
+    
+    return 0;
+}
diff --git a/cmds/surfaceflinger/Android.mk b/cmds/surfaceflinger/Android.mk
new file mode 100644
index 0000000..37c3d94
--- /dev/null
+++ b/cmds/surfaceflinger/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	main_surfaceflinger.cpp 
+
+LOCAL_SHARED_LIBRARIES := \
+	libsurfaceflinger \
+	libutils
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/../../libs/surfaceflinger
+
+LOCAL_MODULE:= surfaceflinger
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp
new file mode 100644
index 0000000..7c89578
--- /dev/null
+++ b/cmds/surfaceflinger/main_surfaceflinger.cpp
@@ -0,0 +1,18 @@
+#include <utils/IPCThreadState.h>
+#include <utils/ProcessState.h>
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <SurfaceFlinger.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+    sp<ProcessState> proc(ProcessState::self());
+    sp<IServiceManager> sm = defaultServiceManager();
+    LOGI("ServiceManager: %p", sm.get());
+    SurfaceFlinger::instantiate();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+}
diff --git a/im/java/android/im/BrandingResourceIDs.java b/im/java/android/im/BrandingResourceIDs.java
new file mode 100644
index 0000000..9960722
--- /dev/null
+++ b/im/java/android/im/BrandingResourceIDs.java
@@ -0,0 +1,52 @@
+/*
+ * 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 android.im;
+
+/**
+ * @hide
+ * Defines the IDs of branding resources.
+ */
+public interface BrandingResourceIDs {
+    /**
+     * The logo icon of the provider which is displayed in the landing page.
+     */
+    public static final int DRAWABLE_LOGO                = 100;
+    /**
+     * The icon of online presence status.
+     */
+    public static final int DRAWABLE_PRESENCE_ONLINE     = 102;
+    /**
+     * The icon of busy presence status.
+     */
+    public static final int DRAWABLE_PRESENCE_BUSY       = 103;
+    /**
+     * The icon of away presence status.
+     */
+    public static final int DRAWABLE_PRESENCE_AWAY       = 104;
+    /**
+     * The icon of invisible presence status.
+     */
+    public static final int DRAWABLE_PRESENCE_INVISIBLE  = 105;
+    /**
+     * The icon of offline presence status.
+     */
+    public static final int DRAWABLE_PRESENCE_OFFLINE    = 106;
+    /**
+     * The label of the menu to go to the contact list screen.
+     */
+    public static final int STRING_MENU_CONTACT_LIST     = 107;
+
+}
diff --git a/im/java/android/im/IImPlugin.aidl b/im/java/android/im/IImPlugin.aidl
new file mode 100644
index 0000000..229cd0e
--- /dev/null
+++ b/im/java/android/im/IImPlugin.aidl
@@ -0,0 +1,69 @@
+/*
+ * 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 android.im;
+
+/**
+ * @hide
+ */
+interface IImPlugin {
+    /**
+     * Notify the plugin the front door activity is created. This gives the plugin a chance to
+     * start its own servics, etc.
+     */
+    void onStart();
+    
+    /**
+     * Notify the plugin the front door activity is stopping.
+     */
+    void onStop();
+
+    /**
+     * Sign in to the service for the account passed in.
+     *
+     * @param account the account id for the accont to be signed into.
+     */
+    void signIn(long account);
+
+    /**
+     * Sign out of the service for the account passed in.
+     *
+     * @param account the account id for the accont to be signed out of.
+     */
+    void signOut(long account);
+
+    /**
+     * Returns the package name used to load the resources for the given provider name.
+     *
+     * @return The package name to load the resourcs for the given provider.
+     */
+    String getResourcePackageNameForProvider(String providerName);
+
+    /**
+     * Returns a map of branding resources for the given provider. The keys are defined
+     * in {@link android.im.BrandingResourceIDs}. The values are the resource identifiers generated
+     * by the aapt tool.
+     *
+     * @return The map of branding resources for the given provider.
+     */
+    Map getResourceMapForProvider(String providerName);
+
+    /*
+     * Returns a list of supported IM providers.
+     *
+     * @return a List of supported providers.
+     */
+    List getSupportedProviders();
+}
diff --git a/im/java/android/im/ImPluginConsts.java b/im/java/android/im/ImPluginConsts.java
new file mode 100644
index 0000000..416493f
--- /dev/null
+++ b/im/java/android/im/ImPluginConsts.java
@@ -0,0 +1,27 @@
+/*
+ * 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 android.im;
+
+/**
+ * @hide
+ */
+public class ImPluginConsts {
+    /**
+     * The intent action name for the plugin service.
+     */
+    public static final String PLUGIN_ACTION_NAME = "android.im.plugin";
+}
\ No newline at end of file
diff --git a/include/pim/EventRecurrence.h b/include/pim/EventRecurrence.h
new file mode 100644
index 0000000..1ceda41
--- /dev/null
+++ b/include/pim/EventRecurrence.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+//
+#ifndef _PIM_EVENT_RECURRENCE_H
+#define _PIM_EVENT_RECURRENCE_H
+
+#include <utils/String16.h>
+
+namespace android {
+
+struct EventRecurrence
+{
+public:
+                EventRecurrence();
+                ~EventRecurrence();
+    
+    status_t    parse(const String16&);
+
+
+    enum freq_t {
+        SECONDLY = 1,
+        MINUTELY = 2,
+        HOURLY = 3,
+        DAILY = 4,
+        WEEKLY = 5,
+        MONTHLY = 6,
+        YEARLY = 7
+    };
+
+    enum {
+        SU = 0x00010000,
+        MO = 0x00020000,
+        TU = 0x00040000,
+        WE = 0x00080000,
+        TH = 0x00100000,
+        FR = 0x00200000,
+        SA = 0x00400000
+    };
+    
+    freq_t    freq;
+    String16  until;
+    int       count;
+    int       interval;
+    int*      bysecond;
+    int       bysecondCount;
+    int*      byminute;
+    int       byminuteCount;
+    int*      byhour;
+    int       byhourCount;
+    int*      byday;
+    int*      bydayNum;
+    int       bydayCount;   
+    int*      bymonthday;
+    int       bymonthdayCount;
+    int*      byyearday;
+    int       byyeardayCount;
+    int*      byweekno;
+    int       byweeknoCount;
+    int*      bymonth;
+    int       bymonthCount;
+    int*      bysetpos;
+    int       bysetposCount;
+    int       wkst;
+};
+
+}; // namespace android
+
+#endif // _PIM_EVENT_RECURRENCE_H
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
new file mode 100644
index 0000000..0c7ad46
--- /dev/null
+++ b/include/private/opengles/gl_context.h
@@ -0,0 +1,632 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_OPENGLES_CONTEXT_H
+#define ANDROID_OPENGLES_CONTEXT_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <pthread.h>
+#ifdef HAVE_ANDROID_OS
+#include <bionic_tls.h>
+#endif
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+namespace android {
+
+const unsigned int OGLES_NUM_COMPRESSED_TEXTURE_FORMATS = 10;
+
+class EGLTextureObject;
+class EGLSurfaceManager;
+class EGLBufferObjectManager;
+
+namespace gl {
+ 
+struct ogles_context_t;
+struct matrixx_t;
+struct transform_t;
+struct buffer_t;
+
+ogles_context_t* getGlContext();
+
+template<typename T>
+static inline void swap(T& a, T& b) {
+    T t(a); a = b; b = t;
+}
+template<typename T>
+inline T max(T a, T b) {
+    return a<b ? b : a;
+}
+template<typename T>
+inline T max(T a, T b, T c) {
+    return max(a, max(b, c));
+}
+template<typename T>
+inline T min(T a, T b) {
+    return a<b ? a : b;
+}
+template<typename T>
+inline T min(T a, T b, T c) {
+    return min(a, min(b, c));
+}
+template<typename T>
+inline T min(T a, T b, T c, T d) {
+    return min(min(a,b), min(c,d));
+}
+
+// ----------------------------------------------------------------------------
+// vertices
+// ----------------------------------------------------------------------------
+
+struct vec3_t {
+    union {
+        struct { GLfixed x, y, z; };
+        struct { GLfixed r, g, b; };
+        struct { GLfixed S, T, R; };
+        GLfixed v[3];
+    };
+};
+
+struct vec4_t {
+    union {
+        struct { GLfixed x, y, z, w; };
+        struct { GLfixed r, g, b, a; };
+        struct { GLfixed S, T, R, Q; };
+        GLfixed v[4];
+    };
+};
+
+struct vertex_t {
+    enum {
+        // these constant matter for our clipping 
+        CLIP_L          = 0x0001,   // clipping flags
+        CLIP_R          = 0x0002,
+        CLIP_B          = 0x0004,
+        CLIP_T          = 0x0008,
+        CLIP_N          = 0x0010,
+        CLIP_F          = 0x0020,
+
+        EYE             = 0x0040,
+        RESERVED        = 0x0080,
+        
+        USER_CLIP_0     = 0x0100,   // user clipping flags
+        USER_CLIP_1     = 0x0200,
+        USER_CLIP_2     = 0x0400,
+        USER_CLIP_3     = 0x0800,
+        USER_CLIP_4     = 0x1000,
+        USER_CLIP_5     = 0x2000,
+
+        LIT             = 0x4000,   // lighting has been applied
+        TT              = 0x8000,   // texture coords transformed
+
+        FRUSTUM_CLIP_ALL= 0x003F,
+        USER_CLIP_ALL   = 0x3F00,
+        CLIP_ALL        = 0x3F3F,
+    };
+    
+    // the fields below are arranged to minimize d-cache usage
+    // we group together, by cache-line, the fields most likely to be used
+
+    union {
+    vec4_t          obj;
+    vec4_t          eye;
+    };
+    vec4_t          clip;
+    
+    uint32_t        flags;
+    size_t          index;  // cache tag, and vertex index
+    GLfixed         fog;
+    uint8_t         locked;
+    uint8_t         mru;
+    uint8_t         reserved[2];
+    vec4_t          window;
+
+    vec4_t          color;
+    vec4_t          texture[GGL_TEXTURE_UNIT_COUNT];
+    uint32_t        reserved1[4];
+    
+    inline void clear() {
+        flags = index = locked = mru = 0;
+    }
+};
+
+struct point_size_t {
+    GGLcoord    size;
+    GLboolean   smooth;
+};
+
+struct line_width_t {
+    GGLcoord    width;
+    GLboolean   smooth;
+};
+
+struct polygon_offset_t {
+    GLfixed     factor;
+    GLfixed     units;
+    GLboolean   enable;
+};
+
+// ----------------------------------------------------------------------------
+// arrays
+// ----------------------------------------------------------------------------
+
+struct array_t {
+    typedef void (*fetcher_t)(ogles_context_t*, GLfixed*, const GLvoid*);
+    fetcher_t       fetch;
+    GLvoid const*   physical_pointer;
+    GLint           size;
+    GLsizei         stride;
+    GLvoid const*   pointer;
+    buffer_t const* bo;
+    uint16_t        type;
+    GLboolean       enable;
+    GLboolean       pad;
+    GLsizei         bounds;
+    void init(GLint, GLenum, GLsizei, const GLvoid *, const buffer_t*, GLsizei);
+    inline void resolve();
+    inline const GLubyte* element(GLint i) const {
+        return (const GLubyte*)physical_pointer + i * stride;
+    }
+};
+
+struct array_machine_t {
+    array_t         vertex;
+    array_t         normal;
+    array_t         color;
+    array_t         texture[GGL_TEXTURE_UNIT_COUNT];
+    uint8_t         activeTexture;
+    uint8_t         tmu;
+    uint16_t        cull;
+    uint32_t        flags;
+    GLenum          indicesType;
+    buffer_t const* array_buffer;
+    buffer_t const* element_array_buffer;
+    
+    void (*compileElements)(ogles_context_t*, vertex_t*, GLint, GLsizei);
+    void (*compileElement)(ogles_context_t*, vertex_t*, GLint);
+
+    void (*mvp_transform)(transform_t const*, vec4_t*, vec4_t const*);
+    void (*mv_transform)(transform_t const*, vec4_t*, vec4_t const*);
+    void (*tex_transform[2])(transform_t const*, vec4_t*, vec4_t const*);
+    void (*perspective)(ogles_context_t*c, vertex_t* v);
+    void (*clipVertex)(ogles_context_t* c, vertex_t* nv,
+            GGLfixed t, const vertex_t* s, const vertex_t* p);
+    void (*clipEye)(ogles_context_t* c, vertex_t* nv,
+            GGLfixed t, const vertex_t* s, const vertex_t* p);
+};
+
+struct vertex_cache_t {
+    enum {
+        // must be at least 4
+        // 3 vertice for triangles
+        // or 2 + 2 for indexed triangles w/ cache contention
+        VERTEX_BUFFER_SIZE  = 8,
+        // must be a power of two and at least 3
+        VERTEX_CACHE_SIZE   = 64,   // 8 KB
+
+        INDEX_BITS      = 16,
+        INDEX_MASK      = ((1LU<<INDEX_BITS)-1),
+        INDEX_SEQ       = 1LU<<INDEX_BITS,
+    };
+    vertex_t*       vBuffer;
+    vertex_t*       vCache;
+    uint32_t        sequence;
+    void*           base;
+    uint32_t        total;
+    uint32_t        misses;
+    int64_t         startTime;
+    void init();
+    void uninit();
+    void clear();
+    void dump_stats(GLenum mode);
+};
+
+// ----------------------------------------------------------------------------
+// fog
+// ----------------------------------------------------------------------------
+
+struct fog_t {
+    GLfixed     density;
+    GLfixed     start;
+    GLfixed     end;
+    GLfixed     invEndMinusStart;
+    GLenum      mode;
+    GLfixed     (*fog)(ogles_context_t* c, GLfixed z);
+};
+
+// ----------------------------------------------------------------------------
+// user clip planes
+// ----------------------------------------------------------------------------
+
+const unsigned int OGLES_MAX_CLIP_PLANES = 6;
+
+struct clip_plane_t {
+    vec4_t      equation;
+};
+
+struct user_clip_planes_t {
+    clip_plane_t    plane[OGLES_MAX_CLIP_PLANES];
+    uint32_t        enable;
+};
+
+// ----------------------------------------------------------------------------
+// lighting
+// ----------------------------------------------------------------------------
+
+const unsigned int OGLES_MAX_LIGHTS = 8;
+
+struct light_t {
+    vec4_t      ambient;
+    vec4_t      diffuse;
+    vec4_t      specular;
+    vec4_t      implicitAmbient;
+    vec4_t      implicitDiffuse;
+    vec4_t      implicitSpecular;
+    vec4_t      position;       // position in eye space
+    vec4_t      objPosition;
+    vec4_t      normalizedObjPosition;
+    vec4_t      spotDir;
+    vec4_t      normalizedSpotDir;
+    GLfixed     spotExp;
+    GLfixed     spotCutoff;
+    GLfixed     spotCutoffCosine;
+    GLfixed     attenuation[3];
+    GLfixed     rConstAttenuation;
+    GLboolean   enable;
+};
+
+struct material_t {
+    vec4_t      ambient;
+    vec4_t      diffuse;
+    vec4_t      specular;
+    vec4_t      emission;
+    GLfixed     shininess;
+};
+
+struct light_model_t {
+    vec4_t      ambient;
+    GLboolean   twoSide;
+};
+
+struct color_material_t {
+    GLenum      face;
+    GLenum      mode;
+    GLboolean   enable;
+};
+
+struct lighting_t {
+    light_t             lights[OGLES_MAX_LIGHTS];
+    material_t          front;
+    light_model_t       lightModel;
+    color_material_t    colorMaterial;
+    uint32_t            enabledLights;
+    GLboolean           enable;
+    vec4_t              implicitSceneEmissionAndAmbient;
+    GLenum              shadeModel;
+    typedef void (*light_fct_t)(ogles_context_t*, vertex_t*);
+    void (*lightVertex)(ogles_context_t* c, vertex_t* v);
+    void (*lightTriangle)(ogles_context_t* c,
+            vertex_t* v0, vertex_t* v1, vertex_t* v2);
+};
+
+struct culling_t {
+    GLenum      cullFace;
+    GLenum      frontFace;
+    GLboolean   enable;
+};
+
+// ----------------------------------------------------------------------------
+// textures
+// ----------------------------------------------------------------------------
+
+struct texture_unit_t {
+    GLuint              name;
+    EGLTextureObject*   texture;
+    uint8_t             dirty;
+};
+
+struct texture_state_t
+{
+    texture_unit_t      tmu[GGL_TEXTURE_UNIT_COUNT];
+    int                 active;     // active tmu
+    EGLTextureObject*   defaultTexture;
+    GGLContext*         ggl;
+    uint8_t             packAlignment;
+    uint8_t             unpackAlignment;
+};
+
+// ----------------------------------------------------------------------------
+// transformation and matrices
+// ----------------------------------------------------------------------------
+
+struct matrixf_t;
+
+struct matrixx_t {
+    GLfixed m[16];
+    void load(const matrixf_t& rhs);
+};
+
+struct matrix_stack_t;
+
+
+struct matrixf_t {
+    void loadIdentity();
+    void load(const matrixf_t& rhs);
+
+    inline GLfloat* editElements() { return m; }
+    inline GLfloat const* elements() const { return m; }
+
+    void set(const GLfixed* rhs);
+    void set(const GLfloat* rhs);
+
+    static void multiply(matrixf_t& r,
+            const matrixf_t& lhs, const matrixf_t& rhs);
+
+    void dump(const char* what);
+
+private:
+    friend struct matrix_stack_t;
+    GLfloat     m[16];
+    void load(const GLfixed* rhs);
+    void load(const GLfloat* rhs);
+    void multiply(const matrixf_t& rhs);
+    void translate(GLfloat x, GLfloat y, GLfloat z);
+    void scale(GLfloat x, GLfloat y, GLfloat z);
+    void rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z);
+};
+
+enum {
+    OP_IDENTITY         = 0x00,
+    OP_TRANSLATE        = 0x01,
+    OP_UNIFORM_SCALE    = 0x02,
+    OP_SCALE            = 0x05,
+    OP_ROTATE           = 0x08,
+    OP_SKEW             = 0x10,
+    OP_ALL              = 0x1F
+};
+
+struct transform_t {
+    enum {
+        FLAGS_2D_PROJECTION = 0x1
+    };
+    matrixx_t       matrix;
+    uint32_t        flags;
+    uint32_t        ops;
+    
+    union {
+        struct {
+            void (*point2)(transform_t const* t, vec4_t*, vec4_t const*);
+            void (*point3)(transform_t const* t, vec4_t*, vec4_t const*);
+            void (*point4)(transform_t const* t, vec4_t*, vec4_t const*);
+        };
+        void (*pointv[3])(transform_t const* t, vec4_t*, vec4_t const*);
+    };
+
+    void loadIdentity();
+    void picker();
+    void dump(const char* what);
+};
+
+struct mvui_transform_t : public transform_t
+{
+    void picker();
+};
+
+struct matrix_stack_t {
+    enum {
+        DO_PICKER           = 0x1,
+        DO_FLOAT_TO_FIXED   = 0x2
+    };
+    transform_t     transform;
+    uint8_t         maxDepth;
+    uint8_t         depth;
+    uint8_t         dirty;
+    uint8_t         reserved;
+    matrixf_t       *stack;
+    uint8_t         *ops;
+    void init(int depth);
+    void uninit();
+    void loadIdentity();
+    void load(const GLfixed* rhs);
+    void load(const GLfloat* rhs);
+    void multiply(const matrixf_t& rhs);
+    void translate(GLfloat x, GLfloat y, GLfloat z);
+    void scale(GLfloat x, GLfloat y, GLfloat z);
+    void rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z);
+    GLint push();
+    GLint pop();
+    void validate();
+    matrixf_t& top() { return stack[depth]; }
+    const matrixf_t& top() const { return stack[depth]; }
+    const uint32_t top_ops() const { return ops[depth]; }
+    inline bool isRigidBody() const {
+        return !(ops[depth] & ~(OP_TRANSLATE|OP_UNIFORM_SCALE|OP_ROTATE));
+    }
+};
+
+struct vp_transform_t {
+    transform_t     transform;
+    matrixf_t       matrix;
+    GLfloat         zNear;
+    GLfloat         zFar;
+    void loadIdentity();
+};
+
+struct transform_state_t {
+    enum {
+        MODELVIEW           = 0x01,
+        PROJECTION          = 0x02,
+        VIEWPORT            = 0x04,
+        TEXTURE             = 0x08,
+        MVUI                = 0x10,
+        MVIT                = 0x20,
+        MVP                 = 0x40,
+    };
+    matrix_stack_t      *current;
+    matrix_stack_t      modelview;
+    matrix_stack_t      projection;
+    matrix_stack_t      texture[GGL_TEXTURE_UNIT_COUNT];
+
+    // modelview * projection
+    transform_t         mvp     __attribute__((aligned(32)));
+    // viewport transformation
+    vp_transform_t      vpt     __attribute__((aligned(32)));
+    // same for 4-D vertices
+    transform_t         mvp4;
+    // full modelview inverse transpose
+    transform_t         mvit4;
+    // upper 3x3 of mv-inverse-transpose (for normals)
+    mvui_transform_t    mvui;
+
+    GLenum              matrixMode;
+    GLenum              rescaleNormals;
+    uint32_t            dirty;
+    void invalidate();
+    void update_mvp();
+    void update_mvit();
+    void update_mvui();
+};
+
+struct viewport_t {
+    GLint       x;
+    GLint       y;
+    GLsizei     w;
+    GLsizei     h; 
+    struct {
+        GLint       x;
+        GLint       y;
+    } surfaceport;  
+    struct {
+        GLint       x;
+        GLint       y;
+        GLsizei     w;
+        GLsizei     h; 
+    } scissor;  
+};
+
+// ----------------------------------------------------------------------------
+// Lerping
+// ----------------------------------------------------------------------------
+
+struct compute_iterators_t
+{
+    void initTriangle(
+            vertex_t const* v0,
+            vertex_t const* v1,
+            vertex_t const* v2);
+
+    void initLine(
+            vertex_t const* v0,
+            vertex_t const* v1);
+
+    inline void initLerp(vertex_t const* v0, uint32_t enables);
+
+    int iteratorsScale(int32_t it[3],
+            int32_t c0, int32_t c1, int32_t c2) const;
+
+    void iterators1616(GGLfixed it[3],
+            GGLfixed c0, GGLfixed c1, GGLfixed c2) const;
+
+    void iterators0032(int32_t it[3],
+            int32_t c0, int32_t c1, int32_t c2) const;
+
+    void iterators0032(int64_t it[3],
+            int32_t c0, int32_t c1, int32_t c2) const;
+
+    GGLcoord area() const { return m_area; }
+
+private:
+    // don't change order of members here -- used by iterators.S
+    GGLcoord m_dx01, m_dy10, m_dx20, m_dy02;
+    GGLcoord m_x0, m_y0;
+    GGLcoord m_area;
+    uint8_t m_scale;
+    uint8_t m_area_scale;
+    uint8_t m_reserved[2];
+
+};
+
+// ----------------------------------------------------------------------------
+// state
+// ----------------------------------------------------------------------------
+
+#ifdef HAVE_ANDROID_OS
+    // We have a dedicated TLS slot in bionic
+    inline void setGlThreadSpecific(ogles_context_t *value) {
+        ((uint32_t *)__get_tls())[TLS_SLOT_OPENGL] = (uint32_t)value;
+    }
+    inline ogles_context_t* getGlThreadSpecific() {
+        return (ogles_context_t *)(((unsigned *)__get_tls())[TLS_SLOT_OPENGL]);
+    }
+#else
+    extern pthread_key_t gGLKey;
+    inline void setGlThreadSpecific(ogles_context_t *value) {
+        pthread_setspecific(gGLKey, value);
+    }
+    inline ogles_context_t* getGlThreadSpecific() {
+        return static_cast<ogles_context_t*>(pthread_getspecific(gGLKey));
+    }
+#endif
+
+
+struct prims_t {
+    typedef ogles_context_t* GL;
+    void (*renderPoint)(GL, vertex_t*);
+    void (*renderLine)(GL, vertex_t*, vertex_t*);
+    void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*);
+};
+
+struct ogles_context_t {
+    context_t               rasterizer;
+    array_machine_t         arrays         __attribute__((aligned(32)));
+    texture_state_t         textures;
+    transform_state_t       transforms;
+    vertex_cache_t          vc;
+    prims_t                 prims;
+    culling_t               cull;
+    lighting_t              lighting;
+    user_clip_planes_t      clipPlanes;
+    compute_iterators_t     lerp;           __attribute__((aligned(32)));
+    vertex_t                current;
+    vec4_t                  currentColorClamped;
+    vec3_t                  currentNormal;
+    viewport_t              viewport;
+    point_size_t            point;
+    line_width_t            line;
+    polygon_offset_t        polygonOffset;
+    fog_t                   fog;
+    uint32_t                perspective : 1;
+    uint32_t                transformTextures : 1;
+    EGLSurfaceManager*      surfaceManager;
+    EGLBufferObjectManager* bufferObjectManager;
+    GLenum                  error;
+
+    static inline ogles_context_t* get() {
+        return getGlThreadSpecific();
+    }
+
+};
+
+}; // namespace gl
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_CONTEXT_H
+
diff --git a/include/private/ui/LayerState.h b/include/private/ui/LayerState.h
new file mode 100644
index 0000000..b6fcd80
--- /dev/null
+++ b/include/private/ui/LayerState.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_COMPOSER_LAYER_STATE_H
+#define ANDROID_COMPOSER_LAYER_STATE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <ui/ISurfaceFlingerClient.h>
+#include <ui/Region.h>
+
+#include <private/ui/SharedState.h>
+
+namespace android {
+
+class Parcel;
+
+struct layer_state_t {
+
+    layer_state_t()
+        :   surface(0), what(0),
+            x(0), y(0), z(0), w(0), h(0),
+            alpha(0), tint(0), flags(0), mask(0),
+            reserved(0)
+    {
+        matrix.dsdx = matrix.dtdy = 1.0f;
+        matrix.dsdy = matrix.dtdx = 0.0f;
+    }
+
+    status_t    write(Parcel& output) const;
+    status_t    read(const Parcel& input);
+
+            struct matrix22_t {
+                float   dsdx;
+                float   dtdx;
+                float   dsdy;
+                float   dtdy;
+            };
+            SurfaceID       surface;
+            uint32_t        what;
+            int32_t         x;
+            int32_t         y;
+            uint32_t        z;
+            uint32_t        w;
+            uint32_t        h;
+            float           alpha;
+            uint32_t        tint;
+            uint8_t         flags;
+            uint8_t         mask;
+            uint8_t         reserved;
+            matrix22_t      matrix;
+            // non POD must be last. see write/read
+            Region          transparentRegion;
+};
+
+}; // namespace android
+
+#endif // ANDROID_COMPOSER_LAYER_STATE_H
+
diff --git a/include/private/ui/SharedState.h b/include/private/ui/SharedState.h
new file mode 100644
index 0000000..546d0ad
--- /dev/null
+++ b/include/private/ui/SharedState.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_UI_SHARED_STATE_H
+#define ANDROID_UI_SHARED_STATE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+namespace android {
+
+/*
+ * These structures are shared between the composer process and its clients
+ */
+
+// ---------------------------------------------------------------------------
+
+struct surface_info_t { // 4 longs, 16 bytes
+    enum {
+        eBufferDirty    = 0x01
+    };
+    uint16_t    w;
+    uint16_t    h;
+    uint16_t    stride;
+    uint16_t    bpr;
+    uint16_t    reserved;
+    uint8_t     format;
+    uint8_t     flags;
+    ssize_t     bits_offset;
+};
+
+// ---------------------------------------------------------------------------
+
+const uint32_t NUM_LAYERS_MAX = 31;
+
+enum { // layer_cblk_t swapState
+    eIndex              = 0x00000001,
+    eFlipRequested      = 0x00000002,
+    
+    eResizeBuffer0      = 0x00000004,
+    eResizeBuffer1      = 0x00000008,    
+    eResizeRequested    = eResizeBuffer0 | eResizeBuffer1,
+    
+    eBusy               = 0x00000010,
+    eLocked             = 0x00000020,
+    eNextFlipPending    = 0x00000040,    
+    eInvalidSurface     = 0x00000080
+};
+
+enum { // layer_cblk_t flags
+    eLayerNotPosted     = 0x00000001,
+    eNoCopyBack         = 0x00000002,
+    eReserved           = 0x0000007C,
+    eBufferIndexShift   = 7,
+    eBufferIndex        = 1<<eBufferIndexShift,
+};
+
+struct flat_region_t    // 40 bytes
+{
+    int32_t     count;
+    int16_t     l;
+    int16_t     t;
+    int16_t     r;
+    int16_t     b;
+    uint16_t    runs[14];
+};
+
+struct layer_cblk_t     // (128 bytes)
+{
+    volatile    int32_t             swapState;      //  4
+    volatile    int32_t             flags;          //  4
+    volatile    int32_t             identity;       //  4
+                int32_t             reserved;       //  4
+                surface_info_t      surface[2];     // 32
+                flat_region_t       region[2];      // 80
+
+    static inline int backBuffer(uint32_t state) {
+        return ((state & eIndex) ^ ((state & eFlipRequested)>>1));
+    }
+    static inline int frontBuffer(uint32_t state) {
+        return 1 - backBuffer(state);
+    }
+};
+
+// ---------------------------------------------------------------------------
+
+struct per_client_cblk_t   // 4KB max
+{
+                Mutex           lock;
+                Condition       cv;
+                layer_cblk_t    layers[NUM_LAYERS_MAX] __attribute__((aligned(32)));
+
+    enum {
+        BLOCKING = 0x00000001,
+        INSPECT  = 0x00000002
+    };
+
+    per_client_cblk_t();
+
+    // these functions are used by the clients
+    status_t validate(size_t i) const;
+    int32_t lock_layer(size_t i, uint32_t flags);
+    uint32_t unlock_layer_and_post(size_t i);
+    void unlock_layer(size_t i);
+};
+// ---------------------------------------------------------------------------
+
+const uint32_t NUM_DISPLAY_MAX = 4;
+
+struct display_cblk_t
+{
+    uint16_t    w;
+    uint16_t    h;
+    uint8_t     format;
+    uint8_t     orientation;
+    uint8_t     reserved[2];
+    float       fps;
+    float       density;
+    float       xdpi;
+    float       ydpi;
+    uint32_t    pad[2];
+};
+
+struct surface_flinger_cblk_t   // 4KB max
+{
+    surface_flinger_cblk_t();
+    
+    uint8_t         connected;
+    uint8_t         reserved[3];
+    uint32_t        pad[7];
+ 
+    display_cblk_t  displays[NUM_DISPLAY_MAX];
+};
+
+// ---------------------------------------------------------------------------
+
+template<bool> struct CTA;
+template<> struct CTA<true> { };
+
+// compile-time assertions. just to avoid catastrophes.
+inline void compile_time_asserts() {
+    CTA<sizeof(layer_cblk_t) == 128> sizeof__layer_cblk_t__eq_128;
+    (void)sizeof__layer_cblk_t__eq_128; // we don't want a warning
+    CTA<sizeof(per_client_cblk_t) <= 4096> sizeof__per_client_cblk_t__le_4096;
+    (void)sizeof__per_client_cblk_t__le_4096;  // we don't want a warning
+    CTA<sizeof(surface_flinger_cblk_t) <= 4096> sizeof__surface_flinger_cblk_t__le_4096;
+    (void)sizeof__surface_flinger_cblk_t__le_4096;  // we don't want a warning
+}
+
+}; // namespace android
+
+#endif // ANDROID_UI_SHARED_STATE_H
+
diff --git a/include/private/ui/SurfaceFlingerSynchro.h b/include/private/ui/SurfaceFlingerSynchro.h
new file mode 100644
index 0000000..ff91b61
--- /dev/null
+++ b/include/private/ui/SurfaceFlingerSynchro.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+
+#ifndef ANDROID_SURFACE_FLINGER_SYNCHRO_H
+#define ANDROID_SURFACE_FLINGER_SYNCHRO_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <ui/ISurfaceComposer.h>
+
+namespace android {
+
+class SurfaceFlinger;
+
+class SurfaceFlingerSynchro
+{
+public:
+
+                // client constructor
+                SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger);
+                ~SurfaceFlingerSynchro();
+    
+                // signal surfaceflinger for some work
+    status_t    signal();
+    
+private:
+    class Barrier {
+    public:
+        Barrier();
+        ~Barrier();
+        void open();
+        void close();
+        void waitAndClose();
+        status_t waitAndClose(nsecs_t timeout);
+    private:
+        enum { OPENED, CLOSED };
+        mutable     Mutex       lock;
+        mutable     Condition   cv;
+        volatile    int         state;
+    };
+
+    friend class SurfaceFlinger;
+
+                // server constructor
+                SurfaceFlingerSynchro();
+                
+    void        open();
+    
+                // wait until there is some work to do
+    status_t    wait();
+    status_t    wait(nsecs_t timeout);
+    
+    sp<ISurfaceComposer> mSurfaceComposer;
+    Barrier              mBarrier;
+};
+
+}; // namespace android
+
+#endif // ANDROID_SURFACE_FLINGER_SYNCHRO_H
+
diff --git a/include/private/utils/Static.h b/include/private/utils/Static.h
new file mode 100644
index 0000000..f1439b7
--- /dev/null
+++ b/include/private/utils/Static.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+// All static variables go here, to control initialization and
+// destruction order in the library.
+
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+#ifndef LIBUTILS_NATIVE
+#include <utils/IBinder.h>
+#include <utils/IMemory.h>
+#include <utils/ProcessState.h>
+#include <utils/IPermissionController.h>
+#include <utils/IServiceManager.h>
+#endif
+
+namespace android {
+// For TextStream.cpp
+extern Vector<int32_t> gTextBuffers;
+
+// For String8.cpp
+extern void initialize_string8();
+extern void terminate_string8();
+
+// For String16.cpp
+extern void initialize_string16();
+extern void terminate_string16();
+
+
+
+#ifndef LIBUTILS_NATIVE
+
+// For ProcessState.cpp
+extern Mutex gProcessMutex;
+extern sp<ProcessState> gProcess;
+
+// For ServiceManager.cpp
+extern Mutex gDefaultServiceManagerLock;
+extern sp<IServiceManager> gDefaultServiceManager;
+extern sp<IPermissionController> gPermissionController;
+
+#endif
+
+}   // namespace android
diff --git a/include/private/utils/binder_module.h b/include/private/utils/binder_module.h
new file mode 100644
index 0000000..fdf327e
--- /dev/null
+++ b/include/private/utils/binder_module.h
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+#ifndef _BINDER_MODULE_H_
+#define _BINDER_MODULE_H_
+
+#ifdef __cplusplus
+namespace android {
+#endif
+
+#if defined(HAVE_ANDROID_OS)
+
+/* obtain structures and constants from the kernel header */
+
+#include <sys/ioctl.h>
+#include <linux/binder.h>
+
+#else
+
+/* Some parts of the simulator need fake versions of this 
+ * stuff in order to compile.  Really this should go away
+ * entirely...
+ */
+
+#define BINDER_CURRENT_PROTOCOL_VERSION 7
+
+#define BINDER_TYPE_BINDER 1
+#define BINDER_TYPE_WEAK_BINDER 2
+#define BINDER_TYPE_HANDLE 3
+#define BINDER_TYPE_WEAK_HANDLE 4
+#define BINDER_TYPE_FD 5
+
+struct flat_binder_object {
+    unsigned long type;
+    unsigned long flags;
+    union {
+        void *binder;
+        signed long handle;
+    };
+    void *cookie;
+};
+
+struct binder_write_read {
+    signed long write_size;
+    signed long write_consumed;
+    unsigned long write_buffer;
+    signed long read_size;
+    signed long read_consumed;
+    unsigned long read_buffer;
+};
+
+struct binder_transaction_data {
+    union {
+        size_t handle;
+        void *ptr;
+    } target;
+    void *cookie;
+    unsigned int code;
+    
+    unsigned int flags;
+    pid_t sender_pid;
+    uid_t sender_euid;
+    size_t data_size;
+    size_t offsets_size;
+    
+    union {
+        struct {
+            const void *buffer;
+            const void *offsets;
+        } ptr;
+        uint8_t buf[8];
+    } data;
+};
+
+enum transaction_flags {
+    TF_ONE_WAY = 0x01,
+    TF_ROOT_OBJECT = 0x04,
+    TF_STATUS_CODE = 0x08,
+    TF_ACCEPT_FDS = 0x10,
+};
+
+
+enum {
+    FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
+    FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
+};
+
+enum BinderDriverReturnProtocol {
+    BR_ERROR,
+    BR_OK,
+    BR_TRANSACTION,
+    BR_REPLY,
+    BR_ACQUIRE_RESULT,
+    BR_DEAD_REPLY,
+    BR_TRANSACTION_COMPLETE,
+    BR_INCREFS,
+    BR_ACQUIRE,
+    BR_RELEASE,
+    BR_DECREFS,
+    BR_ATTEMPT_ACQUIRE,
+    BR_NOOP,
+    BR_SPAWN_LOOPER,
+    BR_FINISHED,
+    BR_DEAD_BINDER,
+    BR_CLEAR_DEATH_NOTIFICATION_DONE,
+    BR_FAILED_REPLY,
+};
+
+enum BinderDriverCommandProtocol {
+    BC_TRANSACTION,
+    BC_REPLY,
+    BC_ACQUIRE_RESULT,
+    BC_FREE_BUFFER,
+    BC_INCREFS,
+    BC_ACQUIRE,
+    BC_RELEASE,
+    BC_DECREFS,
+    BC_INCREFS_DONE,
+    BC_ACQUIRE_DONE,
+    BC_ATTEMPT_ACQUIRE,
+    BC_REGISTER_LOOPER,
+    BC_ENTER_LOOPER,
+    BC_EXIT_LOOPER,
+    BC_REQUEST_DEATH_NOTIFICATION,
+    BC_CLEAR_DEATH_NOTIFICATION,
+    BC_DEAD_BINDER_DONE,
+};
+
+#endif
+
+#ifdef __cplusplus
+}   // namespace android
+#endif
+
+#endif // _BINDER_MODULE_H_
diff --git a/include/private/utils/futex_synchro.h b/include/private/utils/futex_synchro.h
new file mode 100644
index 0000000..ac2ab1995
--- /dev/null
+++ b/include/private/utils/futex_synchro.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef _FUTEX_SYNCHRO_H
+#define _FUTEX_SYNCHRO_H
+
+#ifndef HAVE_FUTEX
+#error "HAVE_FUTEX not defined"
+#endif
+
+#define FUTEX_WAIT_INFINITE (0)
+
+typedef struct futex_mutex_t futex_mutex_t;
+
+struct futex_mutex_t 
+{
+    volatile int value;
+};
+
+typedef struct futex_cond_t futex_cond_t;
+
+struct futex_cond_t 
+{
+    volatile int value;
+};
+
+
+#if __cplusplus
+extern "C" {
+#endif
+
+void futex_mutex_init(futex_mutex_t *m);
+int futex_mutex_lock(futex_mutex_t *m, unsigned msec);
+void futex_mutex_unlock(futex_mutex_t *m);
+int futex_mutex_trylock(futex_mutex_t *m);
+
+void futex_cond_init(futex_cond_t *c);
+int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec);
+void futex_cond_signal(futex_cond_t *c);
+void futex_cond_broadcast(futex_cond_t *c);
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // _FUTEX_SYNCHRO_H
+
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
new file mode 100644
index 0000000..e593fea
--- /dev/null
+++ b/include/ui/Camera.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008 HTC Inc.
+ *
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_H
+#define ANDROID_HARDWARE_CAMERA_H
+
+#include <ui/ICameraClient.h>
+
+namespace android {
+
+/*
+ * A set of bit masks for specifying how the received preview frames are
+ * handled before the previewCallback() call.
+ *
+ * The least significant 3 bits of an "int" value are used for this purpose:
+ *
+ * ..... 0 0 0
+ *       ^ ^ ^
+ *       | | |---------> determine whether the callback is enabled or not
+ *       | |-----------> determine whether the callback is one-shot or not
+ *       |-------------> determine whether the frame is copied out or not
+ *
+ * WARNING:
+ * When a frame is sent directly without copying, it is the frame receiver's
+ * responsiblity to make sure that the frame data won't get corrupted by
+ * subsequent preview frames filled by the camera. This flag is recommended
+ * only when copying out data brings significant performance price and the
+ * handling/processing of the received frame data is always faster than
+ * the preview frame rate so that data corruption won't occur.
+ *
+ * For instance,
+ * 1. 0x00 disables the callback. In this case, copy out and one shot bits
+ *    are ignored.
+ * 2. 0x01 enables a callback without copying out the received frames. A
+ *    typical use case is the Camcorder application to avoid making costly
+ *    frame copies.
+ * 3. 0x05 is enabling a callback with frame copied out repeatedly. A typical
+ *    use case is the Camera application.
+ * 4. 0x07 is enabling a callback with frame copied out only once. A typical use
+ *    case is the Barcode scanner application.
+ */
+#define FRAME_CALLBACK_FLAG_ENABLE_MASK              0x01
+#define FRAME_CALLBACK_FLAG_ONE_SHOT_MASK            0x02
+#define FRAME_CALLBACK_FLAG_COPY_OUT_MASK            0x04
+
+// Typical use cases
+#define FRAME_CALLBACK_FLAG_NOOP                     0x00
+#define FRAME_CALLBACK_FLAG_CAMCORDER                0x01
+#define FRAME_CALLBACK_FLAG_CAMERA                   0x05
+#define FRAME_CALLBACK_FLAG_BARCODE_SCANNER          0x07
+
+class ICameraService;
+class ICamera;
+class Surface;
+class Mutex;
+class String8;
+
+typedef void (*shutter_callback)(void *cookie);
+typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie);
+typedef void (*autofocus_callback)(bool focused, void *cookie);
+typedef void (*error_callback)(status_t err, void *cookie);
+
+class Camera : public BnCameraClient, public IBinder::DeathRecipient
+{
+public:
+            // construct a camera client from an existing remote
+            Camera(const sp<ICamera>& camera);
+
+    static  sp<Camera>  connect();
+                        ~Camera();
+            void        init();
+
+            status_t    reconnect();
+            void        disconnect();
+            status_t    lock();
+            status_t    unlock();
+
+            status_t    getStatus() { return mStatus; }
+
+            // pass the buffered ISurface to the camera service
+            status_t    setPreviewDisplay(const sp<Surface>& surface);
+            status_t    setPreviewDisplay(const sp<ISurface>& surface);
+
+            // start preview mode, must call setPreviewDisplay first
+            status_t    startPreview();
+
+            // stop preview mode
+            void        stopPreview();
+
+            // get preview state
+            bool        previewEnabled();
+
+            // start recording mode, must call setPreviewDisplay first
+            status_t    startRecording();
+
+            // stop recording mode
+            void        stopRecording();
+
+            // get recording state
+            bool        recordingEnabled();
+
+            // release a recording frame
+            void        releaseRecordingFrame(const sp<IMemory>& mem);
+
+            // autoFocus - status returned from callback
+            status_t    autoFocus();
+
+            // take a picture - picture returned from callback
+            status_t    takePicture();
+
+            // set preview/capture parameters - key/value pairs
+            status_t    setParameters(const String8& params);
+
+            // get preview/capture parameters - key/value pairs
+            String8     getParameters() const;
+
+            void        setShutterCallback(shutter_callback cb, void *cookie);
+            void        setRawCallback(frame_callback cb, void *cookie);
+            void        setJpegCallback(frame_callback cb, void *cookie);
+            void        setRecordingCallback(frame_callback cb, void *cookie);
+            void        setPreviewCallback(frame_callback cb, void *cookie, int preview_callback_flag = FRAME_CALLBACK_FLAG_NOOP);
+            void        setErrorCallback(error_callback cb, void *cookie);
+            void        setAutoFocusCallback(autofocus_callback cb, void *cookie);
+
+    // ICameraClient interface
+    virtual void        shutterCallback();
+    virtual void        rawCallback(const sp<IMemory>& picture);
+    virtual void        jpegCallback(const sp<IMemory>& picture);
+    virtual void        previewCallback(const sp<IMemory>& frame);
+    virtual void        errorCallback(status_t error);
+    virtual void        autoFocusCallback(bool focused);
+    virtual void        recordingCallback(const sp<IMemory>& frame);
+
+    sp<ICamera>         remote();
+
+private:
+                        Camera();
+                        virtual void binderDied(const wp<IBinder>& who);
+
+            class DeathNotifier: public IBinder::DeathRecipient
+            {
+            public:
+                DeathNotifier() {
+                }
+
+                virtual void binderDied(const wp<IBinder>& who);
+            };
+
+            static sp<DeathNotifier> mDeathNotifier;
+
+            // helper function to obtain camera service handle
+            static const sp<ICameraService>& getCameraService();
+
+            sp<ICamera>         mCamera;
+            status_t            mStatus;
+
+            shutter_callback    mShutterCallback;
+            void                *mShutterCallbackCookie;
+            frame_callback      mRawCallback;
+            void                *mRawCallbackCookie;
+            frame_callback      mJpegCallback;
+            void                *mJpegCallbackCookie;
+            frame_callback      mPreviewCallback;
+            void                *mPreviewCallbackCookie;
+            frame_callback      mRecordingCallback;
+            void                *mRecordingCallbackCookie;
+            error_callback      mErrorCallback;
+            void                *mErrorCallbackCookie;
+            autofocus_callback  mAutoFocusCallback;
+            void                *mAutoFocusCallbackCookie;
+
+            friend class DeathNotifier;
+
+            static  Mutex               mLock;
+            static  sp<ICameraService>  mCameraService;
+
+};
+
+}; // namespace android
+
+#endif
+
diff --git a/include/ui/CameraHardwareInterface.h b/include/ui/CameraHardwareInterface.h
new file mode 100644
index 0000000..73036f0
--- /dev/null
+++ b/include/ui/CameraHardwareInterface.h
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
+#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
+
+#include <utils/IMemory.h>
+#include <utils/RefBase.h>
+#include <ui/CameraParameters.h>
+#include <ui/Overlay.h>
+
+namespace android {
+
+/** Callback for startPreview() */
+typedef void (*preview_callback)(const sp<IMemory>& mem, void* user);
+
+/** Callback for startRecord() */
+typedef void (*recording_callback)(const sp<IMemory>& mem, void* user);
+
+/** Callback for takePicture() */
+typedef void (*shutter_callback)(void* user);
+
+/** Callback for takePicture() */
+typedef void (*raw_callback)(const sp<IMemory>& mem, void* user);
+
+/** Callback for takePicture() */
+typedef void (*jpeg_callback)(const sp<IMemory>& mem, void* user);
+
+/** Callback for autoFocus() */
+typedef void (*autofocus_callback)(bool focused, void* user);
+
+/**
+ * CameraHardwareInterface.h defines the interface to the
+ * camera hardware abstraction layer, used for setting and getting
+ * parameters, live previewing, and taking pictures.
+ *
+ * It is a referenced counted interface with RefBase as its base class.
+ * CameraService calls openCameraHardware() to retrieve a strong pointer to the
+ * instance of this interface and may be called multiple times. The
+ * following steps describe a typical sequence:
+ *
+ *   -# After CameraService calls openCameraHardware(), getParameters() and
+ *      setParameters() are used to initialize the camera instance.
+ *      CameraService calls getPreviewHeap() to establish access to the
+ *      preview heap so it can be registered with SurfaceFlinger for
+ *      efficient display updating while in preview mode.
+ *   -# startPreview() is called, which is passed a preview_callback()
+ *      function and a user parameter. The camera instance then periodically
+ *      calls preview_callback() each time a new preview frame is available.
+ *      The callback routine has two parameters: the first is a pointer to
+ *      the IMemory containing the frame and the second a user parameter. If
+ *      the preview_callback code needs to use this memory after returning,
+ *      it must copy the data.
+ *
+ * Prior to taking a picture, CameraService calls autofocus() with
+ * autofocus_callback() and a user parameter. When auto focusing has
+ * completed, the camera instance calls autofocus_callback(), which informs
+ * the application whether focusing was successful. The camera instance
+ * only calls autofocus_callback() once and it is up to the application to
+ * call autoFocus() again if refocusing is desired.
+ *
+ * CameraService calls takePicture() to request the camera instance take a
+ * picture. This method has two callbacks: raw_callback() and jpeg_callback().
+ * When the raw image is available, raw_callback() is called with a pointer
+ * to the IMemory containing the raw image. When the jpeg image is available,
+ * jpeg_callback() is called with a pointer to the IMemory containing the
+ * jpeg image. As with preview_callback(), the memory must be copied if it's
+ * needed after returning.
+ */
+class CameraHardwareInterface : public virtual RefBase {
+public:
+    virtual ~CameraHardwareInterface() { }
+
+    /** Return the IMemoryHeap for the preview image heap */
+    virtual sp<IMemoryHeap>         getPreviewHeap() const = 0;
+
+    /** Return the IMemoryHeap for the raw image heap */
+    virtual sp<IMemoryHeap>         getRawHeap() const = 0;
+
+    /**
+     * Start preview mode. When a preview image is available
+     * preview_callback is called with the user parameter. The
+     * call back parameter may be null.
+     */
+    virtual status_t    startPreview(preview_callback cb, void* user) = 0;
+    /**
+     * Only used if overlays are used for camera preview.
+     */
+    virtual bool useOverlay() {return false;}
+    virtual status_t setOverlay(const sp<Overlay> &overlay) {return BAD_VALUE;}
+
+    /**
+     * Stop a previously started preview.
+     */
+    virtual void        stopPreview() = 0;
+
+    /**
+     * Returns true if preview is enabled.
+     */
+    virtual bool        previewEnabled() = 0;
+
+    /**
+     * Start record mode. When a record image is available recording_callback()
+     * is called with the user parameter.  Every record frame must be released
+     * by calling releaseRecordingFrame().
+     */
+    virtual status_t    startRecording(recording_callback cb, void* user) = 0;
+
+    /**
+     * Stop a previously started recording.
+     */
+    virtual void        stopRecording() = 0;
+
+    /**
+     * Returns true if recording is enabled.
+     */
+    virtual bool        recordingEnabled() = 0;
+    
+    /**
+     * Release a record frame previously returned by the recording_callback()
+     * passed to startRecord().
+     */
+    virtual void        releaseRecordingFrame(const sp<IMemory>& mem) = 0;
+
+    /**
+     * Start auto focus, the callback routine is called
+     * once when focusing is complete. autoFocus() will
+     * be called again if another auto focus is needed.
+     */
+    virtual status_t    autoFocus(autofocus_callback,
+                                  void* user) = 0;
+
+    /**
+     * Take a picture. The raw_callback is called when
+     * the uncompressed image is available. The jpeg_callback
+     * is called when the compressed image is available. These
+     * call backs may be null. The user parameter is passed
+     * to each of the call back routines.
+     */
+    virtual status_t    takePicture(shutter_callback,
+                                    raw_callback,
+                                    jpeg_callback,
+                                    void* user) = 0;
+
+    /**
+     * Cancel a picture that was started with takePicture.  You may cancel any
+     * of the shutter, raw, or jpeg callbacks.  Calling this method when no
+     * picture is being taken is a no-op.
+     */
+    virtual status_t    cancelPicture(bool cancel_shutter,
+                                      bool cancel_raw,
+                                      bool cancel_jpeg) = 0;
+
+    /** Set the camera parameters. */
+    virtual status_t    setParameters(const CameraParameters& params) = 0;
+
+    /** Return the camera parameters. */
+    virtual CameraParameters  getParameters() const = 0;
+
+    /**
+     * Release the hardware resources owned by this object.  Note that this is
+     * *not* done in the destructor.
+     */
+    virtual void release() = 0;
+    
+    /**
+     * Dump state of the camera hardware
+     */
+    virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
+};
+
+/** factory function to instantiate a camera hardware object */
+extern "C" sp<CameraHardwareInterface> openCameraHardware();
+
+};  // namespace android
+
+#endif
diff --git a/include/ui/CameraParameters.h b/include/ui/CameraParameters.h
new file mode 100644
index 0000000..9ca1806
--- /dev/null
+++ b/include/ui/CameraParameters.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_PARAMETERS_H
+#define ANDROID_HARDWARE_CAMERA_PARAMETERS_H
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class CameraParameters
+{
+public:
+    CameraParameters();
+    CameraParameters(const String8 &params) { unflatten(params); }
+    ~CameraParameters();
+
+    enum {
+        CAMERA_ORIENTATION_UNKNOWN = 0,
+        CAMERA_ORIENTATION_PORTRAIT = 1,
+        CAMERA_ORIENTATION_LANDSCAPE = 2,
+    };
+
+    String8 flatten() const;
+    void unflatten(const String8 &params);
+
+    void set(const char *key, const char *value);
+    void set(const char *key, int value);
+    const char *get(const char *key) const;
+    int getInt(const char *key) const;
+
+    /* preview-size=176x144 */
+    void setPreviewSize(int width, int height);
+    void getPreviewSize(int *width, int *height) const;
+
+    /* preview-fps=15 */
+    void setPreviewFrameRate(int fps);
+    int getPreviewFrameRate() const;
+
+    /* preview-format=rgb565|yuv422 */
+    void setPreviewFormat(const char *format);
+    const char *getPreviewFormat() const;
+
+    /* picture-size=1024x768 */
+    void setPictureSize(int width, int height);
+    void getPictureSize(int *width, int *height) const;
+
+    /* picture-format=yuv422|jpeg */
+    void setPictureFormat(const char *format);
+    const char *getPictureFormat() const;
+
+    int getOrientation() const;
+    void setOrientation(int orientation);
+
+    void dump() const;
+    status_t dump(int fd, const Vector<String16>& args) const;
+
+private:
+    DefaultKeyedVector<String8,String8>    mMap;
+};
+
+
+}; // namespace android
+
+#endif
diff --git a/include/ui/DisplayInfo.h b/include/ui/DisplayInfo.h
new file mode 100644
index 0000000..c419efe
--- /dev/null
+++ b/include/ui/DisplayInfo.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+
+#ifndef ANDROID_UI_DISPLAY_INFO_H
+#define ANDROID_UI_DISPLAY_INFO_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/PixelFormat.h>
+
+namespace android {
+
+struct DisplayInfo {
+    uint32_t            w;
+    uint32_t            h;
+    PixelFormatInfo     pixelFormatInfo;
+    uint8_t             orientation;
+    uint8_t             reserved[3];
+    float               fps;
+    float               density;
+    float               xdpi;
+    float               ydpi;
+};
+
+}; // namespace android
+
+#endif // ANDROID_COMPOSER_DISPLAY_INFO_H
+
diff --git a/include/ui/EGLDisplaySurface.h b/include/ui/EGLDisplaySurface.h
new file mode 100644
index 0000000..a8b5853
--- /dev/null
+++ b/include/ui/EGLDisplaySurface.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_EGL_DISPLAY_SURFACE_H
+#define ANDROID_EGL_DISPLAY_SURFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Timers.h>
+
+#include <ui/EGLNativeSurface.h>
+
+#include <pixelflinger/pixelflinger.h>
+#include <linux/fb.h>
+
+#include <EGL/egl.h>
+
+struct copybit_device_t;
+struct copybit_image_t;
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Region;
+class Rect;
+
+class EGLDisplaySurface : public EGLNativeSurface<EGLDisplaySurface>
+{
+public:
+    EGLDisplaySurface();
+    ~EGLDisplaySurface();
+    
+    int32_t getPageFlipCount() const;
+    void    copyFrontToBack(const Region& copyback);
+    void    copyFrontToImage(const copybit_image_t& dst);
+    void    copyBackToImage(const copybit_image_t& dst);
+    
+    void        setSwapRectangle(int l, int t, int w, int h);
+
+private:
+    static void         hook_incRef(NativeWindowType window);
+    static void         hook_decRef(NativeWindowType window);
+    static uint32_t     hook_swapBuffers(NativeWindowType window);
+     
+            uint32_t    swapBuffers();
+
+            status_t    mapFrameBuffer();
+
+            enum {
+                PAGE_FLIP = 0x00000001
+            };
+    GGLSurface          mFb[2];
+    int                 mIndex;
+    uint32_t            mFlags;
+    size_t              mSize;
+    fb_var_screeninfo   mInfo;
+    fb_fix_screeninfo   mFinfo;
+    int32_t             mPageFlipCount;
+    nsecs_t             mTime;
+    int32_t             mSwapCount;
+    nsecs_t             mSleep;
+    uint32_t            mFeatureFlags;
+    copybit_device_t*   mBlitEngine;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_EGL_DISPLAY_SURFACE_H
+
diff --git a/include/ui/EGLNativeSurface.h b/include/ui/EGLNativeSurface.h
new file mode 100644
index 0000000..7964e7c
--- /dev/null
+++ b/include/ui/EGLNativeSurface.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_EGL_NATIVE_SURFACE_H
+#define ANDROID_EGL_NATIVE_SURFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/atomic.h>
+#include <utils/RefBase.h>
+
+#include <EGL/eglnatives.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+template <class TYPE>
+class EGLNativeSurface : public egl_native_window_t, public LightRefBase<TYPE>
+{
+public:
+    EGLNativeSurface() { 
+        memset(egl_native_window_t::reserved, 0, 
+                sizeof(egl_native_window_t::reserved));
+        memset(egl_native_window_t::reserved_proc, 0, 
+                sizeof(egl_native_window_t::reserved_proc));
+        memset(egl_native_window_t::oem, 0, 
+                sizeof(egl_native_window_t::oem));
+    }
+protected:
+    EGLNativeSurface& operator = (const EGLNativeSurface& rhs);
+    EGLNativeSurface(const EGLNativeSurface& rhs);
+    inline ~EGLNativeSurface() { };
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_EGL_SURFACE_H
+
diff --git a/include/ui/EGLNativeWindowSurface.h b/include/ui/EGLNativeWindowSurface.h
new file mode 100644
index 0000000..3494234
--- /dev/null
+++ b/include/ui/EGLNativeWindowSurface.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
+#define ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <ui/EGLNativeSurface.h>
+#include <EGL/egl.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Surface;
+
+class EGLNativeWindowSurface : public EGLNativeSurface<EGLNativeWindowSurface>
+{
+public:
+    EGLNativeWindowSurface(const sp<Surface>& surface);
+    ~EGLNativeWindowSurface();
+
+    void        setSwapRectangle(int l, int t, int w, int h);
+
+private:
+    static void         hook_incRef(NativeWindowType window);
+    static void         hook_decRef(NativeWindowType window);
+    static uint32_t     hook_swapBuffers(NativeWindowType window);
+    static void         hook_connect(NativeWindowType window);
+    static void         hook_disconnect(NativeWindowType window);
+
+            uint32_t    swapBuffers();
+            void        connect();
+            void        disconnect();
+            
+            sp<Surface> mSurface;
+            bool        mConnected;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
+
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
new file mode 100644
index 0000000..3848d8c
--- /dev/null
+++ b/include/ui/EventHub.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+#ifndef _RUNTIME_EVENT_HUB_H
+#define _RUNTIME_EVENT_HUB_H
+
+#include <utils/String8.h>
+#include <utils/threads.h>
+#include <utils.h>
+
+#include <linux/input.h>
+
+struct pollfd;
+
+namespace android {
+
+class KeyLayoutMap;
+
+/*
+ * Grand Central Station for events.  With a single call to waitEvent()
+ * you can wait for:
+ *  - input events from the keypad of a real device
+ *  - input events and meta-events (e.g. "quit") from the simulator
+ *  - synthetic events from the runtime (e.g. "URL fetch completed")
+ *  - real or forged "vsync" events
+ *
+ * Do not instantiate this class.  Instead, call startUp().
+ */
+class EventHub : public RefBase
+{
+public:
+    EventHub();
+    
+    status_t errorCheck() const;
+    
+    // bit fields for classes of devices.
+    enum {
+        CLASS_KEYBOARD      = 0x00000001,
+        CLASS_ALPHAKEY      = 0x00000002,
+        CLASS_TOUCHSCREEN   = 0x00000004,
+        CLASS_TRACKBALL     = 0x00000008
+    };
+    uint32_t getDeviceClasses(int32_t deviceId) const;
+    
+    String8 getDeviceName(int32_t deviceId) const;
+    
+    int getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue,
+            int* outMaxValue, int* outFlat, int* outFuzz) const;
+        
+    int getSwitchState(int sw) const;
+    int getSwitchState(int32_t deviceId, int sw) const;
+    
+    int getScancodeState(int key) const;
+    int getScancodeState(int32_t deviceId, int key) const;
+    
+    int getKeycodeState(int key) const;
+    int getKeycodeState(int32_t deviceId, int key) const;
+    
+    // special type codes when devices are added/removed.
+    enum {
+        DEVICE_ADDED = 0x10000000,
+        DEVICE_REMOVED = 0x20000000
+    };
+    
+    // examine key input devices for specific framework keycode support
+    bool hasKeys(size_t numCodes, int32_t* keyCodes, uint8_t* outFlags);
+
+    virtual bool getEvent(int32_t* outDeviceId, int32_t* outType,
+            int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
+            int32_t* outValue, nsecs_t* outWhen);
+    
+protected:
+    virtual ~EventHub();
+    virtual void onFirstRef();
+    
+private:
+    bool openPlatformInput(void);
+    int32_t convertDeviceKey_TI_P2(int code);
+
+    int open_device(const char *device);
+    int close_device(const char *device);
+    int scan_dir(const char *dirname);
+    int read_notify(int nfd);
+
+    status_t mError;
+
+    struct device_t {
+        const int32_t   id;
+        const String8   path;
+        String8         name;
+        uint32_t        classes;
+        uint8_t*        keyBitmask;
+        KeyLayoutMap*   layoutMap;
+        String8         keylayoutFilename;
+        device_t*       next;
+        
+        device_t(int32_t _id, const char* _path);
+        ~device_t();
+    };
+
+    device_t* getDevice(int32_t deviceId) const;
+    
+    // Protect all internal state.
+    mutable Mutex   mLock;
+    
+    bool            mHaveFirstKeyboard;
+    int32_t         mFirstKeyboardId; // the API is that the build in keyboard is id 0, so map it
+    
+    struct device_ent {
+        device_t* device;
+        uint32_t seq;
+    };
+    device_ent      *mDevicesById;
+    int             mNumDevicesById;
+    
+    device_t        *mOpeningDevices;
+    device_t        *mClosingDevices;
+    
+    device_t        **mDevices;
+    struct pollfd   *mFDs;
+    int             mFDCount;
+    
+    // device ids that report particular switches.
+#ifdef EV_SW
+    int32_t         mSwitches[SW_MAX+1];
+#endif
+};
+
+}; // namespace android
+
+#endif // _RUNTIME_EVENT_HUB_H
diff --git a/include/ui/ICamera.h b/include/ui/ICamera.h
new file mode 100644
index 0000000..241fb63
--- /dev/null
+++ b/include/ui/ICamera.h
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_ICAMERA_H
+#define ANDROID_HARDWARE_ICAMERA_H
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+#include <ui/ISurface.h>
+#include <utils/IMemory.h>
+#include <utils/String8.h>
+#include <ui/Camera.h>
+
+namespace android {
+
+class ICameraClient;
+
+class ICamera: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(Camera);
+
+    virtual void            disconnect() = 0;
+
+    // connect new client with existing camera remote
+    virtual status_t        connect(const sp<ICameraClient>& client) = 0;
+
+    // prevent other processes from using this ICamera interface
+    virtual status_t        lock() = 0;
+
+    // allow other processes to use this ICamera interface
+    virtual status_t        unlock() = 0;
+
+    // pass the buffered ISurface to the camera service
+    virtual status_t        setPreviewDisplay(const sp<ISurface>& surface) = 0;
+
+    // set the preview callback flag to affect how the received frames from
+    // preview are handled.
+    virtual void            setPreviewCallbackFlag(int flag) = 0;
+
+    // start preview mode, must call setPreviewDisplay first
+    virtual status_t        startPreview() = 0;
+
+    // stop preview mode
+    virtual void            stopPreview() = 0;
+
+    // get preview state
+    virtual bool            previewEnabled() = 0;
+
+    // start recording mode
+    virtual status_t        startRecording() = 0;
+
+    // stop recording mode
+    virtual void            stopRecording() = 0;    
+
+    // get recording state
+    virtual bool            recordingEnabled() = 0;
+
+    // release a recording frame
+    virtual void            releaseRecordingFrame(const sp<IMemory>& mem) = 0;
+
+    // auto focus
+    virtual status_t        autoFocus() = 0;
+
+    // take a picture
+    virtual status_t        takePicture() = 0;
+
+    // set preview/capture parameters - key/value pairs
+    virtual status_t        setParameters(const String8& params) = 0;
+
+    // get preview/capture parameters - key/value pairs
+    virtual String8         getParameters() const = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCamera: public BnInterface<ICamera>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/ui/ICameraClient.h b/include/ui/ICameraClient.h
new file mode 100644
index 0000000..73b951c
--- /dev/null
+++ b/include/ui/ICameraClient.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_ICAMERA_APP_H
+#define ANDROID_HARDWARE_ICAMERA_APP_H
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+#include <utils/IMemory.h>
+
+namespace android {
+
+class ICameraClient: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(CameraClient);
+
+    virtual void            shutterCallback() = 0;
+    virtual void            rawCallback(const sp<IMemory>& picture) = 0;
+    virtual void            jpegCallback(const sp<IMemory>& picture) = 0;
+    virtual void            previewCallback(const sp<IMemory>& frame) = 0;
+    virtual void            errorCallback(status_t error) = 0;
+    virtual void            autoFocusCallback(bool focused) = 0;
+    virtual void            recordingCallback(const sp<IMemory>& frame) = 0;
+
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCameraClient: public BnInterface<ICameraClient>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/ui/ICameraService.h b/include/ui/ICameraService.h
new file mode 100644
index 0000000..dfd8923
--- /dev/null
+++ b/include/ui/ICameraService.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_ICAMERASERVICE_H
+#define ANDROID_HARDWARE_ICAMERASERVICE_H
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+
+#include <ui/ICameraClient.h>
+#include <ui/ICamera.h>
+
+namespace android {
+
+class ICameraService : public IInterface
+{
+protected:
+    enum {
+        CONNECT = IBinder::FIRST_CALL_TRANSACTION,
+    };
+
+public:
+    DECLARE_META_INTERFACE(CameraService);
+
+    virtual sp<ICamera>     connect(const sp<ICameraClient>& cameraClient) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCameraService: public BnInterface<ICameraService>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/ui/IOverlay.h b/include/ui/IOverlay.h
new file mode 100644
index 0000000..699b1b0
--- /dev/null
+++ b/include/ui/IOverlay.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_IOVERLAY_H
+#define ANDROID_IOVERLAY_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+#include <utils/RefBase.h>
+#include <ui/PixelFormat.h>
+
+namespace android {
+
+class IOverlay : public IInterface
+{
+public: 
+    DECLARE_META_INTERFACE(Overlay);
+
+    virtual void destroy() = 0; // one-way
+};
+
+// ----------------------------------------------------------------------------
+
+class BnOverlay : public BnInterface<IOverlay>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IOVERLAY_H
diff --git a/include/ui/ISurface.h b/include/ui/ISurface.h
new file mode 100644
index 0000000..87b320f
--- /dev/null
+++ b/include/ui/ISurface.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_ISURFACE_H
+#define ANDROID_ISURFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+#include <utils/RefBase.h>
+#include <ui/PixelFormat.h>
+
+#include <hardware/hardware.h>
+
+namespace android {
+
+typedef int32_t    SurfaceID;
+
+class IMemoryHeap;
+class OverlayRef;
+
+class ISurface : public IInterface
+{
+protected:
+    enum {
+        REGISTER_BUFFERS = IBinder::FIRST_CALL_TRANSACTION,
+        UNREGISTER_BUFFERS,
+        POST_BUFFER, // one-way transaction
+        CREATE_OVERLAY,
+    };
+
+public: 
+    DECLARE_META_INTERFACE(Surface);
+
+    
+    class BufferHeap {
+    public:
+        enum {
+            /* rotate source image 90 degrees */
+            ROT_90    = HAL_TRANSFORM_ROT_90,
+        };
+        BufferHeap();
+        
+        BufferHeap(uint32_t w, uint32_t h,
+                int32_t hor_stride, int32_t ver_stride, 
+                PixelFormat format, const sp<IMemoryHeap>& heap);
+        
+        BufferHeap(uint32_t w, uint32_t h,
+                int32_t hor_stride, int32_t ver_stride, 
+                PixelFormat format, uint32_t transform, uint32_t flags,
+                const sp<IMemoryHeap>& heap);
+        
+        ~BufferHeap(); 
+        
+        uint32_t w;
+        uint32_t h;
+        int32_t hor_stride;
+        int32_t ver_stride;
+        PixelFormat format;
+        uint32_t transform;
+        uint32_t flags;
+        sp<IMemoryHeap> heap;
+    };
+    
+    virtual status_t registerBuffers(const BufferHeap& buffers) = 0;
+
+    virtual void postBuffer(ssize_t offset) = 0; // one-way
+
+    virtual void unregisterBuffers() = 0;
+    
+    virtual sp<OverlayRef> createOverlay(
+            uint32_t w, uint32_t h, int32_t format) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSurface : public BnInterface<ISurface>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ISURFACE_H
diff --git a/include/ui/ISurfaceComposer.h b/include/ui/ISurfaceComposer.h
new file mode 100644
index 0000000..f9eeb30
--- /dev/null
+++ b/include/ui/ISurfaceComposer.h
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_ISURFACE_COMPOSER_H
+#define ANDROID_ISURFACE_COMPOSER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/ISurfaceFlingerClient.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class DisplayInfo;
+class IGPUCallback;
+
+class ISurfaceComposer : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(SurfaceComposer);
+
+    enum { // (keep in sync with Surface.java)
+        eHidden             = 0x00000004,
+        eGPU                = 0x00000008,
+        eHardware           = 0x00000010,
+        eDestroyBackbuffer  = 0x00000020,
+        eSecure             = 0x00000080,
+        eNonPremultiplied   = 0x00000100,
+        ePushBuffers        = 0x00000200,
+
+        eFXSurfaceNormal    = 0x00000000,
+        eFXSurfaceBlur      = 0x00010000,
+        eFXSurfaceDim       = 0x00020000,
+        eFXSurfaceMask      = 0x000F0000,
+    };
+
+    enum {
+        ePositionChanged            = 0x00000001,
+        eLayerChanged               = 0x00000002,
+        eSizeChanged                = 0x00000004,
+        eAlphaChanged               = 0x00000008,
+        eMatrixChanged              = 0x00000010,
+        eTransparentRegionChanged   = 0x00000020,
+        eVisibilityChanged          = 0x00000040,
+        eFreezeTintChanged          = 0x00000080,
+        eDestroyed                  = 0x00000100
+    };
+
+    enum {
+        eLayerHidden        = 0x01,
+        eLayerFrozen        = 0x02,
+        eLayerDither        = 0x04,
+        eLayerFilter        = 0x08,
+        eLayerBlurFreeze    = 0x10
+    };
+
+    enum {
+        eOrientationDefault     = 0,
+        eOrientation90          = 1,
+        eOrientation180         = 2,
+        eOrientation270         = 3,
+        eOrientationSwapMask    = 0x01
+    };
+
+    /* create connection with surface flinger, requires
+     * ACCESS_SURFACE_FLINGER permission
+     */
+
+    virtual sp<ISurfaceFlingerClient> createConnection() = 0;
+
+    /* retrieve the control block */
+    virtual sp<IMemory> getCblk() const = 0;
+
+    /* open/close transactions. recquires ACCESS_SURFACE_FLINGER permission */
+    virtual void openGlobalTransaction() = 0;
+    virtual void closeGlobalTransaction() = 0;
+
+    /* [un]freeze display. recquires ACCESS_SURFACE_FLINGER permission */
+    virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags) = 0;
+    virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags) = 0;
+
+    /* Set display orientation. recquires ACCESS_SURFACE_FLINGER permission */
+    virtual int setOrientation(DisplayID dpy, int orientation) = 0;
+
+    /* signal that we're done booting.
+     * recquires ACCESS_SURFACE_FLINGER permission
+     */
+    virtual void bootFinished() = 0;
+
+    /* get access to the GPU. Access is relinquished when releasing regs */
+    struct gpu_info_t {
+        struct gpu_region_t {
+            sp<IMemory> region;
+            size_t reserved;
+        };
+        sp<IMemory>             regs;
+        size_t                  count;
+        gpu_region_t            regions[2];
+    };
+    virtual status_t requestGPU(
+            const sp<IGPUCallback>& callback,
+            gpu_info_t* gpu) = 0;
+
+    /* take the gpu back from any apps using it. They'll get a
+     * EGL_CONTEXT_LOST error */
+    virtual status_t revokeGPU() = 0;
+
+    /* Signal surfaceflinger that there might be some work to do
+     * This is an ASYNCHRONOUS call.
+     */
+    virtual void signal() const = 0;
+};
+
+class IGPUCallback : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(GPUCallback);
+    virtual void gpuLost() = 0; //one-way
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSurfaceComposer : public BnInterface<ISurfaceComposer>
+{
+public:
+    enum {
+        // Note: BOOT_FINISHED must remain this value, it is called from
+        // Java by ActivityManagerService.
+        BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
+        CREATE_CONNECTION,
+        GET_CBLK,
+        OPEN_GLOBAL_TRANSACTION,
+        CLOSE_GLOBAL_TRANSACTION,
+        SET_ORIENTATION,
+        FREEZE_DISPLAY,
+        UNFREEZE_DISPLAY,
+        REQUEST_GPU,
+        REVOKE_GPU,
+        SIGNAL
+    };
+
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+class BnGPUCallback : public BnInterface<IGPUCallback>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ISURFACE_COMPOSER_H
diff --git a/include/ui/ISurfaceFlingerClient.h b/include/ui/ISurfaceFlingerClient.h
new file mode 100644
index 0000000..5b9361d
--- /dev/null
+++ b/include/ui/ISurfaceFlingerClient.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_ISURFACE_FLINGER_CLIENT_H
+#define ANDROID_ISURFACE_FLINGER_CLIENT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+#include <utils/RefBase.h>
+
+#include <ui/ISurface.h>
+
+#include <ui/PixelFormat.h>
+  
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class Rect;
+class Point;
+class IMemory;
+class ISurface;
+
+typedef int32_t    ClientID;
+typedef int32_t    DisplayID;
+
+// ----------------------------------------------------------------------------
+
+class layer_state_t;
+
+class ISurfaceFlingerClient : public IInterface
+{
+public: 
+    DECLARE_META_INTERFACE(SurfaceFlingerClient);
+
+    struct surface_data_t {
+        int32_t             token;
+        int32_t             identity;
+        sp<IMemoryHeap>     heap[2];
+        status_t readFromParcel(const Parcel& parcel);
+        status_t writeToParcel(Parcel* parcel) const;
+    };
+    
+    virtual void getControlBlocks(sp<IMemory>* ctl) const = 0;
+
+    virtual sp<ISurface> createSurface( surface_data_t* data,
+                                        int pid, 
+                                        DisplayID display,
+                                        uint32_t w,
+                                        uint32_t h,
+                                        PixelFormat format,
+                                        uint32_t flags) = 0;
+                                    
+    virtual status_t    destroySurface(SurfaceID sid) = 0;
+
+    virtual status_t    setState(int32_t count, const layer_state_t* states) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSurfaceFlingerClient : public BnInterface<ISurfaceFlingerClient>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ISURFACE_FLINGER_CLIENT_H
diff --git a/include/ui/KeyCharacterMap.h b/include/ui/KeyCharacterMap.h
new file mode 100644
index 0000000..bad2cf8
--- /dev/null
+++ b/include/ui/KeyCharacterMap.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef _UI_KEY_CHARACTER_MAP_H
+#define _UI_KEY_CHARACTER_MAP_H
+
+#include <stdint.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+class KeyCharacterMap
+{
+public:
+    ~KeyCharacterMap();
+
+    // see the javadoc for android.text.method.KeyCharacterMap for what
+    // these do
+    unsigned short get(int keycode, int meta);
+    unsigned short getNumber(int keycode);
+    unsigned short getMatch(int keycode, const unsigned short* chars,
+                            int charsize, uint32_t modifiers);
+    unsigned short getDisplayLabel(int keycode);
+    bool getKeyData(int keycode, unsigned short *displayLabel,
+                    unsigned short *number, unsigned short* results);
+    inline unsigned int getKeyboardType() { return m_type; }
+    bool getEvents(uint16_t* chars, size_t len,
+                   Vector<int32_t>* keys, Vector<uint32_t>* modifiers);
+
+    static KeyCharacterMap* load(int id);
+
+    enum {
+        NUMERIC = 1,
+        Q14 = 2,
+        QWERTY = 3 // or AZERTY or whatever
+    };
+
+#define META_MASK 3
+
+private:
+    struct Key
+    {
+        int32_t keycode;
+        uint16_t display_label;
+        uint16_t number;
+        uint16_t data[META_MASK + 1];
+    };
+
+    KeyCharacterMap();
+    static KeyCharacterMap* try_file(const char* filename);
+    Key* find_key(int keycode);
+    bool find_char(uint16_t c, uint32_t* key, uint32_t* mods);
+
+    unsigned int m_type;
+    unsigned int m_keyCount;
+    Key* m_keys;
+};
+
+#endif // _UI_KEY_CHARACTER_MAP_H
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
new file mode 100644
index 0000000..efa6d2b
--- /dev/null
+++ b/include/ui/KeycodeLabels.h
@@ -0,0 +1,236 @@
+/*
+ * 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.
+ */
+
+#ifndef _UI_KEYCODE_LABELS_H
+#define _UI_KEYCODE_LABELS_H
+
+struct KeycodeLabel {
+    const char *literal;
+    int value;
+};
+
+static const KeycodeLabel KEYCODES[] = {
+    { "SOFT_LEFT", 1 },
+    { "SOFT_RIGHT", 2 },
+    { "HOME", 3 },
+    { "BACK", 4 },
+    { "CALL", 5 },
+    { "ENDCALL", 6 },
+    { "0", 7 },
+    { "1", 8 },
+    { "2", 9 },
+    { "3", 10 },
+    { "4", 11 },
+    { "5", 12 },
+    { "6", 13 },
+    { "7", 14 },
+    { "8", 15 },
+    { "9", 16 },
+    { "STAR", 17 },
+    { "POUND", 18 },
+    { "DPAD_UP", 19 },
+    { "DPAD_DOWN", 20 },
+    { "DPAD_LEFT", 21 },
+    { "DPAD_RIGHT", 22 },
+    { "DPAD_CENTER", 23 },
+    { "VOLUME_UP", 24 },
+    { "VOLUME_DOWN", 25 },
+    { "POWER", 26 },
+    { "CAMERA", 27 },
+    { "CLEAR", 28 },
+    { "A", 29 },
+    { "B", 30 },
+    { "C", 31 },
+    { "D", 32 },
+    { "E", 33 },
+    { "F", 34 },
+    { "G", 35 },
+    { "H", 36 },
+    { "I", 37 },
+    { "J", 38 },
+    { "K", 39 },
+    { "L", 40 },
+    { "M", 41 },
+    { "N", 42 },
+    { "O", 43 },
+    { "P", 44 },
+    { "Q", 45 },
+    { "R", 46 },
+    { "S", 47 },
+    { "T", 48 },
+    { "U", 49 },
+    { "V", 50 },
+    { "W", 51 },
+    { "X", 52 },
+    { "Y", 53 },
+    { "Z", 54 },
+    { "COMMA", 55 },
+    { "PERIOD", 56 },
+    { "ALT_LEFT", 57 },
+    { "ALT_RIGHT", 58 },
+    { "SHIFT_LEFT", 59 },
+    { "SHIFT_RIGHT", 60 },
+    { "TAB", 61 },
+    { "SPACE", 62 },
+    { "SYM", 63 },
+    { "EXPLORER", 64 },
+    { "ENVELOPE", 65 },
+    { "ENTER", 66 },
+    { "DEL", 67 },
+    { "GRAVE", 68 },
+    { "MINUS", 69 },
+    { "EQUALS", 70 },
+    { "LEFT_BRACKET", 71 },
+    { "RIGHT_BRACKET", 72 },
+    { "BACKSLASH", 73 },
+    { "SEMICOLON", 74 },
+    { "APOSTROPHE", 75 },
+    { "SLASH", 76 },
+    { "AT", 77 },
+    { "NUM", 78 },
+    { "HEADSETHOOK", 79 },
+    { "FOCUS", 80 },
+    { "PLUS", 81 },
+    { "MENU", 82 },
+    { "NOTIFICATION", 83 },
+    { "SEARCH", 84 },
+    { "PLAYPAUSE", 85 },
+    { "STOP", 86 },
+    { "NEXTSONG", 87 },
+    { "PREVIOUSSONG", 88 },
+    { "REWIND", 89 },
+    { "FORWARD", 90 },
+    { "MUTE", 91 },
+
+    // NOTE: If you add a new keycode here you must also add it to:
+    //   (enum KeyCode, in this file)
+    //   frameworks/base/core/java/android/view/KeyEvent.java
+    //   tools/puppet_master/PuppetMaster.nav_keys.py
+    //   frameworks/base/core/res/res/values/attrs.xml
+
+    { NULL, 0 }
+};
+
+// These constants need to match the above mappings.
+typedef enum KeyCode {
+    kKeyCodeUnknown = 0,
+
+    kKeyCodeSoftLeft = 1,
+    kKeyCodeSoftRight = 2,
+    kKeyCodeHome = 3,
+    kKeyCodeBack = 4,
+    kKeyCodeCall = 5,
+    kKeyCodeEndCall = 6,
+    kKeyCode0 = 7,
+    kKeyCode1 = 8,
+    kKeyCode2 = 9,
+    kKeyCode3 = 10,
+    kKeyCode4 = 11,
+    kKeyCode5 = 12,
+    kKeyCode6 = 13,
+    kKeyCode7 = 14,
+    kKeyCode8 = 15,
+    kKeyCode9 = 16,
+    kKeyCodeStar = 17,
+    kKeyCodePound = 18,
+    kKeyCodeDpadUp = 19,
+    kKeyCodeDpadDown = 20,
+    kKeyCodeDpadLeft = 21,
+    kKeyCodeDpadRight = 22,
+    kKeyCodeDpadCenter = 23,
+    kKeyCodeVolumeUp = 24,
+    kKeyCodeVolumeDown = 25,
+    kKeyCodePower = 26,
+    kKeyCodeCamera = 27,
+    kKeyCodeClear = 28,
+    kKeyCodeA = 29,
+    kKeyCodeB = 30,
+    kKeyCodeC = 31,
+    kKeyCodeD = 32,
+    kKeyCodeE = 33,
+    kKeyCodeF = 34,
+    kKeyCodeG = 35,
+    kKeyCodeH = 36,
+    kKeyCodeI = 37,
+    kKeyCodeJ = 38,
+    kKeyCodeK = 39,
+    kKeyCodeL = 40,
+    kKeyCodeM = 41,
+    kKeyCodeN = 42,
+    kKeyCodeO = 43,
+    kKeyCodeP = 44,
+    kKeyCodeQ = 45,
+    kKeyCodeR = 46,
+    kKeyCodeS = 47,
+    kKeyCodeT = 48,
+    kKeyCodeU = 49,
+    kKeyCodeV = 50,
+    kKeyCodeW = 51,
+    kKeyCodeX = 52,
+    kKeyCodeY = 53,
+    kKeyCodeZ = 54,
+    kKeyCodeComma = 55,
+    kKeyCodePeriod = 56,
+    kKeyCodeAltLeft = 57,
+    kKeyCodeAltRight = 58,
+    kKeyCodeShiftLeft = 59,
+    kKeyCodeShiftRight = 60,
+    kKeyCodeTab = 61,
+    kKeyCodeSpace = 62,
+    kKeyCodeSym = 63,
+    kKeyCodeExplorer = 64,
+    kKeyCodeEnvelope = 65,
+    kKeyCodeNewline = 66,
+    kKeyCodeDel = 67,
+    kKeyCodeGrave = 68,
+    kKeyCodeMinus = 69,
+    kKeyCodeEquals = 70,
+    kKeyCodeLeftBracket = 71,
+    kKeyCodeRightBracket = 72,
+    kKeyCodeBackslash = 73,
+    kKeyCodeSemicolon = 74,
+    kKeyCodeApostrophe = 75,
+    kKeyCodeSlash = 76,
+    kKeyCodeAt = 77,
+    kKeyCodeNum = 78,
+    kKeyCodeHeadSetHook = 79,
+    kKeyCodeFocus = 80,
+    kKeyCodePlus = 81,
+    kKeyCodeMenu = 82,
+    kKeyCodeNotification = 83,
+    kKeyCodeSearch = 84,
+    kKeyCodePlayPause = 85,
+    kKeyCodeStop = 86,
+    kKeyCodeNextSong = 87,
+    kKeyCodePreviousSong = 88,
+    kKeyCodeRewind = 89,
+    kKeyCodeForward = 90,
+    kKeyCodeMute = 91
+} KeyCode;
+
+static const KeycodeLabel FLAGS[] = {
+    { "WAKE", 0x00000001 },
+    { "WAKE_DROPPED", 0x00000002 },
+    { "SHIFT", 0x00000004 },
+    { "CAPS_LOCK", 0x00000008 },
+    { "ALT", 0x00000010 },
+    { "ALT_GR", 0x00000020 },
+    { "MENU", 0x00000040 },
+    { "LAUNCHER", 0x00000080 },
+    { NULL, 0 }
+};
+
+#endif // _UI_KEYCODE_LABELS_H
diff --git a/include/ui/Overlay.h b/include/ui/Overlay.h
new file mode 100644
index 0000000..66514b4
--- /dev/null
+++ b/include/ui/Overlay.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_OVERLAY_H
+#define ANDROID_OVERLAY_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/IOverlay.h>
+
+#include <hardware/overlay.h>
+
+namespace android {
+
+class IMemory;
+class IMemoryHeap;
+
+// ----------------------------------------------------------------------------
+
+class OverlayRef : public LightRefBase<OverlayRef>
+{
+public:
+    OverlayRef(overlay_handle_t, const sp<IOverlay>&,
+            uint32_t w, uint32_t h, int32_t f, uint32_t ws, uint32_t hs);
+
+    static sp<OverlayRef> readFromParcel(const Parcel& data);
+    static status_t writeToParcel(Parcel* reply, const sp<OverlayRef>& o);    
+
+private:
+    friend class LightRefBase<OverlayRef>;
+    friend class Overlay;
+
+    OverlayRef();
+    virtual ~OverlayRef();
+
+    overlay_handle_t mOverlayHandle;
+    sp<IOverlay> mOverlayChannel;
+    uint32_t mWidth;
+    uint32_t mHeight;
+    int32_t  mFormat;
+    int32_t  mWidthStride;
+    int32_t  mHeightStride;
+    bool mOwnHandle;
+};
+
+// ----------------------------------------------------------------------------
+
+class Overlay : public virtual RefBase
+{
+public:
+    Overlay(const sp<OverlayRef>& overlayRef);
+
+    /* destroys this overlay */
+    void destroy();
+    
+    /* get the HAL handle for this overlay */
+    overlay_handle_t getHandleRef() const;
+
+    /* blocks until an overlay buffer is available and return that buffer. */
+    status_t dequeueBuffer(overlay_buffer_t* buffer);
+
+    /* release the overlay buffer and post it */
+    status_t queueBuffer(overlay_buffer_t buffer);
+
+    /* returns the address of a given buffer if supported, NULL otherwise. */
+    void* getBufferAddress(overlay_buffer_t buffer);
+
+    /* get physical informations about the overlay */
+    uint32_t getWidth() const;
+    uint32_t getHeight() const;
+    int32_t getFormat() const;
+    int32_t getWidthStride() const;
+    int32_t getHeightStride() const;
+    int32_t getBufferCount() const;
+    status_t getStatus() const;
+    
+private:
+    virtual ~Overlay();
+
+    sp<OverlayRef> mOverlayRef;
+    overlay_data_device_t *mOverlayData;
+    status_t mStatus;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_OVERLAY_H
diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
new file mode 100644
index 0000000..14af823
--- /dev/null
+++ b/include/ui/PixelFormat.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+
+// Pixel formats used across the system.
+// These formats might not all be supported by all renderers, for instance
+// skia or SurfaceFlinger are not required to support all of these formats
+// (either as source or destination)
+
+// XXX: we should consolidate these formats and skia's
+
+#ifndef UI_PIXELFORMAT_H
+#define UI_PIXELFORMAT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <pixelflinger/format.h>
+
+namespace android {
+
+enum {
+    //
+    // these constants need to match those
+    // in graphics/PixelFormat.java & pixelflinger/format.h
+    //
+    PIXEL_FORMAT_UNKNOWN    =   0,
+    PIXEL_FORMAT_NONE       =   0,
+
+    // logical pixel formats used by the SurfaceFlinger -----------------------
+    PIXEL_FORMAT_CUSTOM         = -4,
+        // Custom pixel-format described by a PixelFormatInfo structure
+
+    PIXEL_FORMAT_TRANSLUCENT    = -3,
+        // System chooses a format that supports translucency (many alpha bits)
+
+    PIXEL_FORMAT_TRANSPARENT    = -2,
+        // System chooses a format that supports transparency
+        // (at least 1 alpha bit)
+
+    PIXEL_FORMAT_OPAQUE         = -1,
+        // System chooses an opaque format (no alpha bits required)
+    
+    // real pixel formats supported for rendering -----------------------------
+
+    PIXEL_FORMAT_RGBA_8888   = GGL_PIXEL_FORMAT_RGBA_8888,  // 4x8-bit RGBA
+    PIXEL_FORMAT_RGBX_8888   = GGL_PIXEL_FORMAT_RGBX_8888,  // 4x8-bit RGB0
+    PIXEL_FORMAT_RGB_888     = GGL_PIXEL_FORMAT_RGB_888,    // 3x8-bit RGB
+    PIXEL_FORMAT_RGB_565     = GGL_PIXEL_FORMAT_RGB_565,    // 16-bit RGB
+    PIXEL_FORMAT_BGRA_8888   = GGL_PIXEL_FORMAT_BGRA_8888,  // 4x8-bit BGRA
+    PIXEL_FORMAT_RGBA_5551   = GGL_PIXEL_FORMAT_RGBA_5551,  // 16-bit ARGB
+    PIXEL_FORMAT_RGBA_4444   = GGL_PIXEL_FORMAT_RGBA_4444,  // 16-bit ARGB
+    PIXEL_FORMAT_A_8         = GGL_PIXEL_FORMAT_A_8,        // 8-bit A
+    PIXEL_FORMAT_L_8         = GGL_PIXEL_FORMAT_L_8,        // 8-bit L (R=G=B=L)
+    PIXEL_FORMAT_LA_88       = GGL_PIXEL_FORMAT_LA_88,      // 16-bit LA
+    PIXEL_FORMAT_RGB_332     = GGL_PIXEL_FORMAT_RGB_332,    // 8-bit RGB
+
+    PIXEL_FORMAT_YCbCr_422_SP= GGL_PIXEL_FORMAT_YCbCr_422_SP,
+    PIXEL_FORMAT_YCbCr_420_SP= GGL_PIXEL_FORMAT_YCbCr_420_SP,
+    PIXEL_FORMAT_YCbCr_422_P = GGL_PIXEL_FORMAT_YCbCr_422_P,
+    PIXEL_FORMAT_YCbCr_420_P = GGL_PIXEL_FORMAT_YCbCr_420_P,
+    PIXEL_FORMAT_YCbCr_422_I = GGL_PIXEL_FORMAT_YCbCr_422_I,
+    PIXEL_FORMAT_YCbCr_420_I = GGL_PIXEL_FORMAT_YCbCr_420_I,
+
+    // New formats can be added if they're also defined in
+    // pixelflinger/format.h
+};
+
+typedef int32_t PixelFormat;
+
+struct PixelFormatInfo
+{
+    enum { // components
+        ALPHA               = 1,
+        RGB                 = 2,
+        RGBA                = 3,
+        LUMINANCE           = 4,
+        LUMINANCE_ALPHA     = 5,
+        Y_CB_CR_SP          = 6,
+        Y_CB_CR_P           = 7,
+        Y_CB_CR_I           = 8,
+    };
+
+    inline PixelFormatInfo() : version(sizeof(PixelFormatInfo)) { }
+    size_t getScanlineSize(unsigned int width) const;
+    size_t      version;
+    PixelFormat format;
+    size_t      bytesPerPixel;
+    size_t      bitsPerPixel;
+    uint8_t     h_alpha;
+    uint8_t     l_alpha;
+    uint8_t     h_red;
+    uint8_t     l_red;
+    uint8_t     h_green;
+    uint8_t     l_green;
+    uint8_t     h_blue;
+    uint8_t     l_blue;
+    uint8_t     components;
+    uint8_t     reserved0[3];
+    uint32_t    reserved1;
+};
+
+// Consider caching the results of these functions are they're not
+// guaranteed to be fast.
+ssize_t     bytesPerPixel(PixelFormat format);
+ssize_t     bitsPerPixel(PixelFormat format);
+status_t    getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info);
+
+}; // namespace android
+
+#endif // UI_PIXELFORMAT_H
diff --git a/include/ui/Point.h b/include/ui/Point.h
new file mode 100644
index 0000000..dbbad1e
--- /dev/null
+++ b/include/ui/Point.h
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_UI_POINT
+#define ANDROID_UI_POINT
+
+#include <utils/TypeHelpers.h>
+
+namespace android {
+
+class Point
+{
+public:
+    int x;
+    int y;
+
+    // we don't provide copy-ctor and operator= on purpose
+    // because we want the compiler generated versions
+
+    // Default constructor doesn't initialize the Point
+    inline Point()
+    {
+    }
+
+    inline Point(int _x, int _y) : x(_x), y(_y)
+    {
+    }
+
+    inline bool operator == (const Point& rhs) const {
+        return (x == rhs.x) && (y == rhs.y);
+    }
+    inline bool operator != (const Point& rhs) const {
+        return !operator == (rhs);
+    }
+
+    inline bool isOrigin() const {
+        return !(x|y);
+    }
+
+    // operator < defines an order which allows to use points in sorted
+    // vectors.
+    bool operator < (const Point& rhs) const {
+        return y<rhs.y || (y==rhs.y && x<rhs.x);
+    }
+
+    inline Point& operator - () {
+        x=-x;
+        y=-y;
+        return *this;
+    }
+    
+    inline Point& operator += (const Point& rhs) {
+        x += rhs.x;
+        y += rhs.y;
+        return *this;
+    }
+    inline Point& operator -= (const Point& rhs) {
+        x -= rhs.x;
+        y -= rhs.y;
+        return *this;
+    }
+    
+    Point operator + (const Point& rhs) const {
+        return Point(x+rhs.x, y+rhs.y);
+    }
+    Point operator - (const Point& rhs) const {
+        return Point(x-rhs.x, y-rhs.y);
+    }    
+};
+
+ANDROID_BASIC_TYPES_TRAITS(Point)
+
+}; // namespace android
+
+#endif // ANDROID_UI_POINT
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
new file mode 100644
index 0000000..d232847
--- /dev/null
+++ b/include/ui/Rect.h
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_UI_RECT
+#define ANDROID_UI_RECT
+
+#include <utils/TypeHelpers.h>
+#include <ui/Point.h>
+
+namespace android {
+
+class Rect
+{
+public:
+    int left;
+    int top;
+    int right;
+    int bottom;
+
+    // we don't provide copy-ctor and operator= on purpose
+    // because we want the compiler generated versions
+
+    inline Rect()
+    {
+    }
+
+    inline Rect(int w, int h)
+        : left(0), top(0), right(w), bottom(h)
+    {
+    }
+
+    inline Rect(int l, int t, int r, int b)
+        : left(l), top(t), right(r), bottom(b)
+    {
+    }
+
+    inline Rect(const Point& lt, const Point& rb) 
+        : left(lt.x), top(lt.y), right(rb.x), bottom(rb.y)
+    {
+    }
+
+    void makeInvalid();
+    
+    // a valid rectangle has a non negative width and height
+    inline bool isValid() const {
+        return (width()>=0) && (height()>=0);
+    }
+
+    // an empty rect has a zero width or height, or is invalid
+    inline bool isEmpty() const {
+        return (width()<=0) || (height()<=0);
+    }
+
+    inline void set(const Rect& rhs) {
+        operator = (rhs);
+    }
+
+    // rectangle's width
+    inline int width() const {
+        return right-left;
+    }
+    
+    // rectangle's height
+    inline int height() const {
+        return bottom-top;
+    }
+
+    // returns left-top Point non-const reference, can be assigned
+    inline Point& leftTop() {
+        return reinterpret_cast<Point&>(left);
+    }
+    // returns right bottom non-const reference, can be assigned
+    inline Point& rightBottom() {
+        return reinterpret_cast<Point&>(right);
+    }
+    
+    // the following 4 functions return the 4 corners of the rect as Point
+    inline const Point& leftTop() const {
+        return reinterpret_cast<const Point&>(left);
+    }
+    inline const Point& rightBottom() const {
+        return reinterpret_cast<const Point&>(right);
+    }
+    Point rightTop() const {
+        return Point(right, top);
+    }
+    Point leftBottom() const {
+        return Point(left, bottom);
+    }
+
+    // comparisons
+    inline bool operator == (const Rect& rhs) const {
+        return (left == rhs.left) && (top == rhs.top) &&
+               (right == rhs.right) && (bottom == rhs.bottom);
+    }
+
+    inline bool operator != (const Rect& rhs) const {
+        return !operator == (rhs);
+    }
+
+    // operator < defines an order which allows to use rectangles in sorted
+    // vectors.
+    bool operator < (const Rect& rhs) const;
+
+    Rect& offsetToOrigin() {
+        right -= left;
+        bottom -= top;
+        left = top = 0;
+        return *this;
+    }
+    Rect& offsetTo(const Point& p) {
+        return offsetTo(p.x, p.y);
+    }
+    Rect& offsetBy(const Point& dp) {
+        return offsetBy(dp.x, dp.y);
+    }
+    Rect& operator += (const Point& rhs) {
+        return offsetBy(rhs.x, rhs.y);
+    }
+    Rect& operator -= (const Point& rhs) {
+        return offsetBy(-rhs.x, -rhs.y);
+    }
+    Rect operator + (const Point& rhs) const;
+    Rect operator - (const Point& rhs) const;
+
+    void translate(int dx, int dy) { // legacy, don't use.
+        offsetBy(dx, dy);
+    }
+ 
+    Rect&   offsetTo(int x, int y);
+    Rect&   offsetBy(int x, int y);
+    bool    intersect(const Rect& with, Rect* result) const;
+};
+
+ANDROID_BASIC_TYPES_TRAITS(Rect)
+
+}; // namespace android
+
+#endif // ANDROID_UI_RECT
diff --git a/include/ui/Region.h b/include/ui/Region.h
new file mode 100644
index 0000000..7689673
--- /dev/null
+++ b/include/ui/Region.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_UI_REGION_H
+#define ANDROID_UI_REGION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Vector.h>
+#include <utils/Parcel.h>
+
+#include <ui/Rect.h>
+
+#include <hardware/copybit.h>
+
+#include <core/SkRegion.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class String8;
+
+// ---------------------------------------------------------------------------
+class Region
+{
+public:
+                        Region();
+                        Region(const Region& rhs);
+    explicit            Region(const SkRegion& rhs);
+    explicit            Region(const Rect& rhs);
+    explicit            Region(const Parcel& parcel);
+    explicit            Region(const void* buffer);
+                        ~Region();
+                        
+        Region& operator = (const Region& rhs);
+
+    inline  bool        isEmpty() const     { return mRegion.isEmpty(); }
+    inline  bool        isRect() const      { return mRegion.isRect(); }
+
+            Rect        bounds() const;
+
+            const SkRegion& toSkRegion() const;
+
+            void        clear();
+            void        set(const Rect& r);
+        
+            Region&     orSelf(const Rect& rhs);
+            Region&     andSelf(const Rect& rhs);
+
+            // boolean operators, applied on this
+            Region&     orSelf(const Region& rhs);
+            Region&     andSelf(const Region& rhs);
+            Region&     subtractSelf(const Region& rhs);
+
+            // these translate rhs first
+            Region&     translateSelf(int dx, int dy);
+            Region&     orSelf(const Region& rhs, int dx, int dy);
+            Region&     andSelf(const Region& rhs, int dx, int dy);
+            Region&     subtractSelf(const Region& rhs, int dx, int dy);
+
+            // boolean operators
+            Region      merge(const Region& rhs) const;
+            Region      intersect(const Region& rhs) const;
+            Region      subtract(const Region& rhs) const;
+
+            // these translate rhs first
+            Region      translate(int dx, int dy) const;
+            Region      merge(const Region& rhs, int dx, int dy) const;
+            Region      intersect(const Region& rhs, int dx, int dy) const;
+            Region      subtract(const Region& rhs, int dx, int dy) const;
+
+    // convenience operators overloads
+    inline  Region      operator | (const Region& rhs) const;
+    inline  Region      operator & (const Region& rhs) const;
+    inline  Region      operator - (const Region& rhs) const;
+    inline  Region      operator + (const Point& pt) const;
+
+    inline  Region&     operator |= (const Region& rhs);
+    inline  Region&     operator &= (const Region& rhs);
+    inline  Region&     operator -= (const Region& rhs);
+    inline  Region&     operator += (const Point& pt);
+
+    class iterator {
+        SkRegion::Iterator  mIt;
+    public:
+        iterator(const Region& r);
+        inline operator bool () const { return !done(); }
+        int iterate(Rect* rect);
+    private:
+        inline bool done() const {
+            return const_cast<SkRegion::Iterator&>(mIt).done();
+        }
+    };
+
+            size_t      rects(Vector<Rect>& rectList) const;
+
+            // flatten/unflatten a region to/from a Parcel
+            status_t    write(Parcel& parcel) const;
+            status_t    read(const Parcel& parcel);
+
+            // flatten/unflatten a region to/from a raw buffer
+            ssize_t     write(void* buffer, size_t size) const;
+    static  ssize_t     writeEmpty(void* buffer, size_t size);
+
+            ssize_t     read(const void* buffer);
+    static  bool        isEmpty(void* buffer);
+
+    void        dump(String8& out, const char* what, uint32_t flags=0) const;
+    void        dump(const char* what, uint32_t flags=0) const;
+
+private:
+    SkRegion    mRegion;
+};
+
+
+Region Region::operator | (const Region& rhs) const {
+    return merge(rhs);
+}
+Region Region::operator & (const Region& rhs) const {
+    return intersect(rhs);
+}
+Region Region::operator - (const Region& rhs) const {
+    return subtract(rhs);
+}
+Region Region::operator + (const Point& pt) const {
+    return translate(pt.x, pt.y);
+}
+
+
+Region& Region::operator |= (const Region& rhs) {
+    return orSelf(rhs);
+}
+Region& Region::operator &= (const Region& rhs) {
+    return andSelf(rhs);
+}
+Region& Region::operator -= (const Region& rhs) {
+    return subtractSelf(rhs);
+}
+Region& Region::operator += (const Point& pt) {
+    return translateSelf(pt.x, pt.y);
+}
+
+// ---------------------------------------------------------------------------
+
+struct region_iterator : public copybit_region_t {
+    region_iterator(const Region& region) : i(region) {
+        this->next = iterate;
+    }
+private:
+    static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
+        return static_cast<const region_iterator*>(self)
+        ->i.iterate(reinterpret_cast<Rect*>(rect));
+    }
+    mutable Region::iterator i;
+};
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_UI_REGION_H
+
diff --git a/include/ui/Surface.h b/include/ui/Surface.h
new file mode 100644
index 0000000..33953a9
--- /dev/null
+++ b/include/ui/Surface.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_UI_SURFACE_H
+#define ANDROID_UI_SURFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+#include <ui/ISurface.h>
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+#include <ui/ISurfaceFlingerClient.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Rect;
+class SurfaceComposerClient;
+
+class Surface : public RefBase
+{
+
+public:
+    struct SurfaceInfo {
+        uint32_t    w;
+        uint32_t    h;
+        uint32_t    bpr;
+        PixelFormat format;
+        void*       bits;
+        void*       base;
+        uint32_t    reserved[2];
+    };
+
+    bool        isValid() const { return this && mToken>=0 && mClient!=0; }
+    SurfaceID   ID() const      { return mToken; }
+
+    status_t    lock(SurfaceInfo* info, bool blocking = true);
+    status_t    lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
+    status_t    unlockAndPost();
+    status_t    unlock();
+
+    void*       heapBase(int i) const;
+    uint32_t    getFlags() const { return mFlags; }
+
+    // setSwapRectangle() is mainly used by EGL
+    void        setSwapRectangle(const Rect& r);
+    const Rect& swapRectangle() const;
+    status_t    nextBuffer(SurfaceInfo* info);
+
+    sp<Surface>         dup() const;
+    static sp<Surface>  readFromParcel(Parcel* parcel);
+    static status_t     writeToParcel(const sp<Surface>& surface, Parcel* parcel);
+    static bool         isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs);
+
+    status_t    setLayer(int32_t layer);
+    status_t    setPosition(int32_t x, int32_t y);
+    status_t    setSize(uint32_t w, uint32_t h);
+    status_t    hide();
+    status_t    show(int32_t layer = -1);
+    status_t    freeze();
+    status_t    unfreeze();
+    status_t    setFlags(uint32_t flags, uint32_t mask);
+    status_t    setTransparentRegionHint(const Region& transparent);
+    status_t    setAlpha(float alpha=1.0f);
+    status_t    setMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
+    status_t    setFreezeTint(uint32_t tint);
+
+    uint32_t    getIdentity() const { return mIdentity; }
+private:
+    friend class SurfaceComposerClient;
+
+    // camera and camcorder need access to the ISurface binder interface for preview
+    friend class Camera;
+    friend class MediaRecorder;
+    // mediaplayer needs access to ISurface for display
+    friend class MediaPlayer;
+    friend class Test;
+    const sp<ISurface>& getISurface() const { return mSurface; }
+
+    // can't be copied
+    Surface& operator = (Surface& rhs);
+    Surface(const Surface& rhs);
+
+    Surface(const sp<SurfaceComposerClient>& client,
+            const sp<ISurface>& surface,
+            const ISurfaceFlingerClient::surface_data_t& data,
+            uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
+            bool owner = true);
+
+    Surface(Surface const* rhs);
+
+    ~Surface();
+
+    Region dirtyRegion() const;
+    void setDirtyRegion(const Region& region) const;
+
+    // this locks protects calls to lockSurface() / unlockSurface()
+    // and is called by SurfaceComposerClient.
+    Mutex& getLock() const { return mSurfaceLock; }
+
+    sp<SurfaceComposerClient>   mClient;
+    sp<ISurface>                mSurface;
+    sp<IMemoryHeap>             mHeap[2];
+    SurfaceID                   mToken;
+    uint32_t                    mIdentity;
+    PixelFormat                 mFormat;
+    uint32_t                    mFlags;
+    const bool                  mOwner;
+    mutable void*               mSurfaceHeapBase[2];
+    mutable Region              mDirtyRegion;
+    mutable Rect                mSwapRectangle;
+    mutable uint8_t             mBackbufferIndex;
+    mutable Mutex               mSurfaceLock;
+};
+
+}; // namespace android
+
+#endif // ANDROID_UI_SURFACE_H
+
diff --git a/include/ui/SurfaceComposerClient.h b/include/ui/SurfaceComposerClient.h
new file mode 100644
index 0000000..5d9222d
--- /dev/null
+++ b/include/ui/SurfaceComposerClient.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_SURFACE_COMPOSER_CLIENT_H
+#define ANDROID_SURFACE_COMPOSER_CLIENT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/ISurfaceComposer.h>
+#include <ui/Region.h>
+#include <ui/Surface.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Region;
+class SurfaceFlingerSynchro;
+struct per_client_cblk_t;
+struct layer_cblk_t;
+
+class SurfaceComposerClient : virtual public RefBase
+{
+public:    
+                SurfaceComposerClient();
+    virtual     ~SurfaceComposerClient();
+
+    // Always make sure we could initialize
+    status_t    initCheck() const;
+
+    // Return the connection of this client
+    sp<IBinder> connection() const;
+    
+    // Retrieve a client for an existing connection.
+    static sp<SurfaceComposerClient>
+                clientForConnection(const sp<IBinder>& conn);
+
+    // Forcibly remove connection before all references have gone away.
+    void        dispose();
+
+    // ------------------------------------------------------------------------
+    // surface creation / destruction
+
+    //! Create a surface
+    sp<Surface>   createSurface(
+            int pid,            //!< pid of the process the surfacec is for
+            DisplayID display,  //!< Display to create this surface on
+            uint32_t w,         //!< width in pixel
+            uint32_t h,         //!< height in pixel
+            PixelFormat format, //!< pixel-format desired
+            uint32_t flags = 0  //!< usage flags
+    );
+
+    // ------------------------------------------------------------------------
+    // Composer parameters
+    // All composer parameters must be changed within a transaction
+    // several surfaces can be updated in one transaction, all changes are
+    // committed at once when the transaction is closed.
+    // CloseTransaction() usually requires an IPC with the server.
+    
+    //! Open a composer transaction
+    status_t    openTransaction();
+
+    //! commit the transaction
+    status_t    closeTransaction();
+
+    //! Open a composer transaction on all active SurfaceComposerClients.
+    static void openGlobalTransaction();
+        
+    //! Close a composer transaction on all active SurfaceComposerClients.
+    static void closeGlobalTransaction();
+    
+    //! Freeze the specified display but not transactions.
+    static status_t freezeDisplay(DisplayID dpy, uint32_t flags = 0);
+        
+    //! Resume updates on the specified display.
+    static status_t unfreezeDisplay(DisplayID dpy, uint32_t flags = 0);
+
+    //! Set the orientation of the given display
+    static int setOrientation(DisplayID dpy, int orientation);
+
+    // Query the number of displays
+    static ssize_t getNumberOfDisplays();
+
+    // Get information about a display
+    static status_t getDisplayInfo(DisplayID dpy, DisplayInfo* info);
+    static ssize_t getDisplayWidth(DisplayID dpy);
+    static ssize_t getDisplayHeight(DisplayID dpy);
+    static ssize_t getDisplayOrientation(DisplayID dpy);
+
+
+private:
+    friend class Surface;
+    
+    SurfaceComposerClient(const sp<ISurfaceComposer>& sm, 
+            const sp<IBinder>& conn);
+
+    status_t    hide(Surface* surface);
+    status_t    show(Surface* surface, int32_t layer = -1);
+    status_t    freeze(Surface* surface);
+    status_t    unfreeze(Surface* surface);
+    status_t    setFlags(Surface* surface, uint32_t flags, uint32_t mask);
+    status_t    setTransparentRegionHint(Surface* surface, const Region& transparent);
+    status_t    setLayer(Surface* surface, int32_t layer);
+    status_t    setAlpha(Surface* surface, float alpha=1.0f);
+    status_t    setFreezeTint(Surface* surface, uint32_t tint);
+    status_t    setMatrix(Surface* surface, float dsdx, float dtdx, float dsdy, float dtdy);
+    status_t    setPosition(Surface* surface, int32_t x, int32_t y);
+    status_t    setSize(Surface* surface, uint32_t w, uint32_t h);
+    
+    //! Unlock the surface, and specify the dirty region if any
+    status_t    unlockAndPostSurface(Surface* surface);
+    status_t    unlockSurface(Surface* surface);
+
+    status_t    lockSurface(Surface* surface,
+                            Surface::SurfaceInfo* info,
+                            Region* dirty,
+                            bool blocking = true);
+
+    status_t    nextBuffer(Surface* surface,
+                            Surface::SurfaceInfo* info);
+
+    status_t    destroySurface(SurfaceID sid);
+
+    void        _init(const sp<ISurfaceComposer>& sm,
+                    const sp<ISurfaceFlingerClient>& conn);
+    void        _signal_server();
+    static void _send_dirty_region(layer_cblk_t* lcblk, const Region& dirty);
+
+    inline layer_state_t*   _get_state_l(const sp<Surface>& surface);
+    layer_state_t*          _lockLayerState(const sp<Surface>& surface);
+    inline void             _unlockLayerState();
+
+    status_t validateSurface(
+            per_client_cblk_t const* cblk, Surface const * surface);
+
+    void pinHeap(const sp<IMemoryHeap>& heap);
+
+    mutable     Mutex                               mLock;
+                layer_state_t*                      mPrebuiltLayerState;
+                SortedVector<layer_state_t>         mStates;
+                int32_t                             mTransactionOpen;
+
+                // these don't need to be protected because they never change
+                // after assignment
+                status_t                    mStatus;
+                per_client_cblk_t*          mControl;
+                sp<IMemory>                 mControlMemory;
+                sp<ISurfaceFlingerClient>   mClient;
+                sp<IMemoryHeap>             mSurfaceHeap;
+                uint8_t*                    mSurfaceHeapBase;
+                void*                       mGL;
+                SurfaceFlingerSynchro*      mSignalServer;
+};
+
+}; // namespace android
+
+#endif // ANDROID_SURFACE_COMPOSER_CLIENT_H
+
diff --git a/include/utils.h b/include/utils.h
new file mode 100644
index 0000000..30648b1
--- /dev/null
+++ b/include/utils.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Handy utility functions and portability code.  This file includes all
+// of the generally-useful headers in the "utils" directory.
+//
+#ifndef _LIBS_UTILS_H
+#define _LIBS_UTILS_H
+
+#include <utils/ported.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <utils/List.h>
+#include <utils/string_array.h>
+#include <utils/misc.h>
+#include <utils/Errors.h>
+
+#endif // _LIBS_UTILS_H
diff --git a/include/utils/AndroidUnicode.h b/include/utils/AndroidUnicode.h
new file mode 100644
index 0000000..563fcd0
--- /dev/null
+++ b/include/utils/AndroidUnicode.h
@@ -0,0 +1,255 @@
+/*
+ * 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.
+ */
+
+//
+
+#ifndef ANDROID_UNICODE_H
+#define ANDROID_UNICODE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#define REPLACEMENT_CHAR (0xFFFD)
+
+// this part of code is copied from umachine.h under ICU
+/**
+ * Define UChar32 as a type for single Unicode code points.
+ * UChar32 is a signed 32-bit integer (same as int32_t).
+ *
+ * The Unicode code point range is 0..0x10ffff.
+ * All other values (negative or >=0x110000) are illegal as Unicode code points.
+ * They may be used as sentinel values to indicate "done", "error"
+ * or similar non-code point conditions.
+ *
+ * @stable ICU 2.4
+ */
+typedef int32_t UChar32;
+
+namespace android {
+
+    class Encoding;
+    /**
+     * \class Unicode
+     *
+     * Helper class for getting properties of Unicode characters. Characters
+     * can have one of the types listed in CharType and each character can have the
+     * directionality of Direction.
+     */
+    class Unicode
+    {
+    public:
+        /**
+         * Directions specified in the Unicode standard. These directions map directly
+         * to java.lang.Character.
+         */
+        enum Direction {
+            DIRECTIONALITY_UNDEFINED = -1,
+            DIRECTIONALITY_LEFT_TO_RIGHT,
+            DIRECTIONALITY_RIGHT_TO_LEFT,
+            DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC,
+            DIRECTIONALITY_EUROPEAN_NUMBER,
+            DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR,
+            DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR,
+            DIRECTIONALITY_ARABIC_NUMBER,
+            DIRECTIONALITY_COMMON_NUMBER_SEPARATOR,
+            DIRECTIONALITY_NONSPACING_MARK,
+            DIRECTIONALITY_BOUNDARY_NEUTRAL,
+            DIRECTIONALITY_PARAGRAPH_SEPARATOR,
+            DIRECTIONALITY_SEGMENT_SEPARATOR,
+            DIRECTIONALITY_WHITESPACE,
+            DIRECTIONALITY_OTHER_NEUTRALS,
+            DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING,
+            DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE,
+            DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING,
+            DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE,
+            DIRECTIONALITY_POP_DIRECTIONAL_FORMAT
+        };
+
+        /**
+         * Character types as specified in the Unicode standard. These map directly to
+         * java.lang.Character.
+         */
+        enum CharType {
+            CHARTYPE_UNASSIGNED = 0,
+            CHARTYPE_UPPERCASE_LETTER,
+            CHARTYPE_LOWERCASE_LETTER,
+            CHARTYPE_TITLECASE_LETTER,
+            CHARTYPE_MODIFIER_LETTER,
+            CHARTYPE_OTHER_LETTER,
+            CHARTYPE_NON_SPACING_MARK,
+            CHARTYPE_ENCLOSING_MARK,
+            CHARTYPE_COMBINING_SPACING_MARK,
+            CHARTYPE_DECIMAL_DIGIT_NUMBER,
+            CHARTYPE_LETTER_NUMBER,
+            CHARTYPE_OTHER_NUMBER,
+            CHARTYPE_SPACE_SEPARATOR,
+            CHARTYPE_LINE_SEPARATOR,
+            CHARTYPE_PARAGRAPH_SEPARATOR,
+            CHARTYPE_CONTROL,
+            CHARTYPE_FORMAT,
+            CHARTYPE_MISSING_VALUE_FOR_JAVA,    /* This is the mysterious missing 17 value from the java constants */
+            CHARTYPE_PRIVATE_USE,
+            CHARTYPE_SURROGATE,
+            CHARTYPE_DASH_PUNCTUATION,
+            CHARTYPE_START_PUNCTUATION,
+            CHARTYPE_END_PUNCTUATION,
+            CHARTYPE_CONNECTOR_PUNCTUATION,
+            CHARTYPE_OTHER_PUNCTUATION,
+            CHARTYPE_MATH_SYMBOL,
+            CHARTYPE_CURRENCY_SYMBOL,
+            CHARTYPE_MODIFIER_SYMBOL,
+            CHARTYPE_OTHER_SYMBOL,
+            CHARTYPE_INITIAL_QUOTE_PUNCTUATION,
+            CHARTYPE_FINAL_QUOTE_PUNCTUATION
+        };
+
+        /**
+         * Decomposition types as described by the unicode standard. These values map to
+         * the same values in uchar.h in ICU.
+         */
+        enum DecompositionType {
+            DECOMPOSITION_NONE = 0,
+            DECOMPOSITION_CANONICAL,
+            DECOMPOSITION_COMPAT,
+            DECOMPOSITION_CIRCLE,
+            DECOMPOSITION_FINAL,
+            DECOMPOSITION_FONT,
+            DECOMPOSITION_FRACTION,
+            DECOMPOSITION_INITIAL,
+            DECOMPOSITION_ISOLATED,
+            DECOMPOSITION_MEDIAL,
+            DECOMPOSITION_NARROW,
+            DECOMPOSITION_NOBREAK,
+            DECOMPOSITION_SMALL,
+            DECOMPOSITION_SQUARE,
+            DECOMPOSITION_SUB,
+            DECOMPOSITION_SUPER,
+            DECOMPOSITION_VERTICAL,
+            DECOMPOSITION_WIDE
+        };
+
+        /**
+         * Returns the packed data for java calls
+         * @param c The unicode character.
+         * @return The packed data for the character.
+         *
+         * Copied from java.lang.Character implementation:
+         * 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+         * F E D C B A 9 8 7 6 5 4 3 2 1 0 F E D C B A 9 8 7 6 5 4 3 2 1 0
+         * 
+         *                              31 types                 ---------
+         *                   18 directionalities       ---------
+         *                   2 mirroreds             -
+         *                               -----------      56  toupper diffs
+         *                   -----------                  48  tolower diffs
+         *               ---                              4 totitlecase diffs
+         * -------------                                 84 numeric values
+         *     ---------                                 24 mirror char diffs
+         */
+        static uint32_t getPackedData(UChar32 c);
+        
+        /**
+         * Get the Character type.
+         * @param c The unicode character.
+         * @return The character's type or CHARTYPE_UNASSIGNED if the character is invalid
+         *         or has an unassigned class.
+         */
+        static CharType getType(UChar32 c);    
+
+        /**
+         * Get the Character's decomposition type.
+         * @param c The unicode character.
+         * @return The character's decomposition type or DECOMPOSITION_NONE is there 
+         *         is no decomposition.
+         */
+        static DecompositionType getDecompositionType(UChar32 c);
+        
+        /**
+         * Returns the digit value of a character or -1 if the character
+         * is not within the specified radix.
+         *
+         * The digit value is computed for integer characters and letters
+         * within the given radix. This function does not handle Roman Numerals,
+         * fractions, or any other characters that may represent numbers.
+         * 
+         * @param c The unicode character
+         * @param radix The intended radix.
+         * @return The digit value or -1 if there is no digit value or if the value is outside the radix.
+         */
+        static int getDigitValue(UChar32 c, int radix = 10);
+
+        /**
+         * Return the numeric value of a character
+         *
+         * @param c The unicode character.
+         * @return The numeric value of the character. -1 if the character has no numeric value, 
+         *         -2 if the character has a numeric value that is not representable by an integer.
+         */
+        static int getNumericValue(UChar32 c);
+
+        /**
+         * Convert the character to lowercase
+         * @param c The unicode character.
+         * @return The lowercase character equivalent of c. If c does not have a lowercase equivalent,
+         *         the original character is returned.
+         */
+        static UChar32 toLower(UChar32 c);
+            
+        /**
+         * Convert the character to uppercase
+         * @param c The unicode character.
+         * @return The uppercase character equivalent of c. If c does not have an uppercase equivalent,
+         *         the original character is returned.
+         */
+        static UChar32 toUpper(UChar32 c);
+    
+        /**
+         * Get the directionality of the character.
+         * @param c The unicode character.
+         * @return The direction of the character or DIRECTIONALITY_UNDEFINED.
+         */
+        static Direction getDirectionality(UChar32 c);
+            
+        /**
+         * Check if the character is a mirrored character. This means that the character
+         * has an equivalent character that is the mirror image of itself.
+         * @param c The unicode character.
+         * @return True iff c has a mirror equivalent.
+         */
+        static bool isMirrored(UChar32 c);
+         
+        /**
+         * Return the mirror of the given character.
+         * @param c The unicode character.
+         * @return The mirror equivalent of c. If c does not have a mirror equivalent,
+         *         the original character is returned.
+         * @see isMirrored
+         */
+        static UChar32 toMirror(UChar32 c);
+        
+        /**
+         * Convert the character to title case.
+         * @param c The unicode character.
+         * @return The titlecase equivalent of c. If c does not have a titlecase equivalent,
+         *         the original character is returned.
+         */
+        static UChar32 toTitle(UChar32 c);
+
+   };
+
+}
+
+#endif
diff --git a/include/utils/Asset.h b/include/utils/Asset.h
new file mode 100644
index 0000000..453a204
--- /dev/null
+++ b/include/utils/Asset.h
@@ -0,0 +1,315 @@
+/*
+ * 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.
+ */
+
+//
+// Class providing access to a read-only asset.  Asset objects are NOT
+// thread-safe, and should not be shared across threads.
+//
+#ifndef __LIBS_ASSET_H
+#define __LIBS_ASSET_H
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "FileMap.h"
+#include "String8.h"
+#include "Errors.h"
+
+namespace android {
+
+/*
+ * Instances of this class provide read-only operations on a byte stream.
+ *
+ * Access may be optimized for streaming, random, or whole buffer modes.  All
+ * operations are supported regardless of how the file was opened, but some
+ * things will be less efficient.  [pass that in??]
+ *
+ * "Asset" is the base class for all types of assets.  The classes below
+ * provide most of the implementation.  The AssetManager uses one of the
+ * static "create" functions defined here to create a new instance.
+ */
+class Asset {
+public:
+    virtual ~Asset(void);
+
+    static int32_t getGlobalCount();
+    
+    /* used when opening an asset */
+    typedef enum AccessMode {
+        ACCESS_UNKNOWN = 0,
+
+        /* read chunks, and seek forward and backward */
+        ACCESS_RANDOM,
+
+        /* read sequentially, with an occasional forward seek */
+        ACCESS_STREAMING,
+
+        /* caller plans to ask for a read-only buffer with all data */
+        ACCESS_BUFFER,
+    } AccessMode;
+
+    enum {
+        /* data larger than this does not get uncompressed into a buffer */
+#ifdef HAVE_ANDROID_OS
+        UNCOMPRESS_DATA_MAX = 1 * 1024 * 1024
+#else
+        UNCOMPRESS_DATA_MAX = 2 * 1024 * 1024
+#endif
+    };
+
+    /*
+     * Read data from the current offset.  Returns the actual number of
+     * bytes read, 0 on EOF, or -1 on error.
+     */
+    virtual ssize_t read(void* buf, size_t count) = 0;
+
+    /*
+     * Seek to the specified offset.  "whence" uses the same values as
+     * lseek/fseek.  Returns the new position on success, or (off_t) -1
+     * on failure.
+     */
+    virtual off_t seek(off_t offset, int whence) = 0;
+
+    /*
+     * Close the asset, freeing all associated resources.
+     */
+    virtual void close(void) = 0;
+
+    /*
+     * Get a pointer to a buffer with the entire contents of the file.
+     */
+    virtual const void* getBuffer(bool wordAligned) = 0;
+
+    /*
+     * Get the total amount of data that can be read.
+     */
+    virtual off_t getLength(void) const = 0;
+
+    /*
+     * Get the total amount of data that can be read from the current position.
+     */
+    virtual off_t getRemainingLength(void) const = 0;
+
+    /*
+     * Open a new file descriptor that can be used to read this asset.
+     * Returns -1 if you can not use the file descriptor (for example if the
+     * asset is compressed).
+     */
+    virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const = 0;
+    
+    /*
+     * Get a string identifying the asset's source.  This might be a full
+     * path, it might be a colon-separated list of identifiers.
+     *
+     * This is NOT intended to be used for anything except debug output.
+     * DO NOT try to parse this or use it to open a file.
+     */
+    const char* getAssetSource(void) const { return mAssetSource.string(); }
+
+protected:
+    Asset(void);        // constructor; only invoked indirectly
+
+    /* handle common seek() housekeeping */
+    off_t handleSeek(off_t offset, int whence, off_t curPosn, off_t maxPosn);
+
+    /* set the asset source string */
+    void setAssetSource(const String8& path) { mAssetSource = path; }
+
+    AccessMode getAccessMode(void) const { return mAccessMode; }
+
+private:
+    /* these operations are not implemented */
+    Asset(const Asset& src);
+    Asset& operator=(const Asset& src);
+
+    /* AssetManager needs access to our "create" functions */
+    friend class AssetManager;
+
+    /*
+     * Create the asset from a named file on disk.
+     */
+    static Asset* createFromFile(const char* fileName, AccessMode mode);
+
+    /*
+     * Create the asset from a named, compressed file on disk (e.g. ".gz").
+     */
+    static Asset* createFromCompressedFile(const char* fileName,
+        AccessMode mode);
+
+#if 0
+    /*
+     * Create the asset from a segment of an open file.  This will fail
+     * if "offset" and "length" don't fit within the bounds of the file.
+     *
+     * The asset takes ownership of the file descriptor.
+     */
+    static Asset* createFromFileSegment(int fd, off_t offset, size_t length,
+        AccessMode mode);
+
+    /*
+     * Create from compressed data.  "fd" should be seeked to the start of
+     * the compressed data.  This could be inside a gzip file or part of a
+     * Zip archive.
+     *
+     * The asset takes ownership of the file descriptor.
+     *
+     * This may not verify the validity of the compressed data until first
+     * use.
+     */
+    static Asset* createFromCompressedData(int fd, off_t offset,
+        int compressionMethod, size_t compressedLength,
+        size_t uncompressedLength, AccessMode mode);
+#endif
+
+    /*
+     * Create the asset from a memory-mapped file segment.
+     *
+     * The asset takes ownership of the FileMap.
+     */
+    static Asset* createFromUncompressedMap(FileMap* dataMap, AccessMode mode);
+
+    /*
+     * Create the asset from a memory-mapped file segment with compressed
+     * data.  "method" is a Zip archive compression method constant.
+     *
+     * The asset takes ownership of the FileMap.
+     */
+    static Asset* createFromCompressedMap(FileMap* dataMap, int method,
+        size_t uncompressedLen, AccessMode mode);
+
+
+    /*
+     * Create from a reference-counted chunk of shared memory.
+     */
+    // TODO
+
+    AccessMode  mAccessMode;        // how the asset was opened
+    String8    mAssetSource;       // debug string
+};
+
+
+/*
+ * ===========================================================================
+ *
+ * Innards follow.  Do not use these classes directly.
+ */
+
+/*
+ * An asset based on an uncompressed file on disk.  It may encompass the
+ * entire file or just a piece of it.  Access is through fread/fseek.
+ */
+class _FileAsset : public Asset {
+public:
+    _FileAsset(void);
+    virtual ~_FileAsset(void);
+
+    /*
+     * Use a piece of an already-open file.
+     *
+     * On success, the object takes ownership of "fd".
+     */
+    status_t openChunk(const char* fileName, int fd, off_t offset, size_t length);
+
+    /*
+     * Use a memory-mapped region.
+     *
+     * On success, the object takes ownership of "dataMap".
+     */
+    status_t openChunk(FileMap* dataMap);
+
+    /*
+     * Standard Asset interfaces.
+     */
+    virtual ssize_t read(void* buf, size_t count);
+    virtual off_t seek(off_t offset, int whence);
+    virtual void close(void);
+    virtual const void* getBuffer(bool wordAligned);
+    virtual off_t getLength(void) const { return mLength; }
+    virtual off_t getRemainingLength(void) const { return mLength-mOffset; }
+    virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const;
+
+private:
+    off_t       mStart;         // absolute file offset of start of chunk
+    off_t       mLength;        // length of the chunk
+    off_t       mOffset;        // current local offset, 0 == mStart
+    FILE*       mFp;            // for read/seek
+    char*       mFileName;      // for opening
+
+    /*
+     * To support getBuffer() we either need to read the entire thing into
+     * a buffer or memory-map it.  For small files it's probably best to
+     * just read them in.
+     */
+    enum { kReadVsMapThreshold = 4096 };
+
+    FileMap*    mMap;           // for memory map
+    unsigned char* mBuf;        // for read
+    
+    const void* ensureAlignment(FileMap* map);
+};
+
+
+/*
+ * An asset based on compressed data in a file.
+ */
+class _CompressedAsset : public Asset {
+public:
+    _CompressedAsset(void);
+    virtual ~_CompressedAsset(void);
+
+    /*
+     * Use a piece of an already-open file.
+     *
+     * On success, the object takes ownership of "fd".
+     */
+    status_t openChunk(int fd, off_t offset, int compressionMethod,
+        size_t uncompressedLen, size_t compressedLen);
+
+    /*
+     * Use a memory-mapped region.
+     *
+     * On success, the object takes ownership of "fd".
+     */
+    status_t openChunk(FileMap* dataMap, int compressionMethod,
+        size_t uncompressedLen);
+
+    /*
+     * Standard Asset interfaces.
+     */
+    virtual ssize_t read(void* buf, size_t count);
+    virtual off_t seek(off_t offset, int whence);
+    virtual void close(void);
+    virtual const void* getBuffer(bool wordAligned);
+    virtual off_t getLength(void) const { return mUncompressedLen; }
+    virtual off_t getRemainingLength(void) const { return mUncompressedLen-mOffset; }
+    virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const { return -1; }
+
+private:
+    off_t       mStart;         // offset to start of compressed data
+    off_t       mCompressedLen; // length of the compressed data
+    off_t       mUncompressedLen; // length of the uncompressed data
+    off_t       mOffset;        // current offset, 0 == start of uncomp data
+
+    FileMap*    mMap;           // for memory-mapped input
+    int         mFd;            // for file input
+
+    unsigned char*  mBuf;       // for getBuffer()
+};
+
+// need: shared mmap version?
+
+}; // namespace android
+
+#endif // __LIBS_ASSET_H
diff --git a/include/utils/AssetDir.h b/include/utils/AssetDir.h
new file mode 100644
index 0000000..abf8a35
--- /dev/null
+++ b/include/utils/AssetDir.h
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+//
+// Access a chunk of the asset hierarchy as if it were a single directory.
+//
+#ifndef __LIBS_ASSETDIR_H
+#define __LIBS_ASSETDIR_H
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <utils/misc.h>
+#include <sys/types.h>
+
+namespace android {
+
+/*
+ * This provides vector-style access to a directory.  We do this rather
+ * than modeling opendir/readdir access because it's simpler and the
+ * nature of the operation requires us to have all data on hand anyway.
+ *
+ * The list of files will be sorted in ascending order by ASCII value.
+ *
+ * The contents are populated by our friend, the AssetManager.
+ */
+class AssetDir {
+public:
+    AssetDir(void)
+        : mFileInfo(NULL)
+        {}
+    virtual ~AssetDir(void) {
+        delete mFileInfo;
+    }
+
+    /*
+     * Vector-style access.
+     */
+    size_t getFileCount(void) { return mFileInfo->size(); }
+    const String8& getFileName(int idx) {
+        return mFileInfo->itemAt(idx).getFileName();
+    }
+    const String8& getSourceName(int idx) {
+        return mFileInfo->itemAt(idx).getSourceName();
+    }
+
+    /*
+     * Get the type of a file (usually regular or directory).
+     */
+    FileType getFileType(int idx) {
+        return mFileInfo->itemAt(idx).getFileType();
+    }
+
+private:
+    /* these operations are not implemented */
+    AssetDir(const AssetDir& src);
+    const AssetDir& operator=(const AssetDir& src);
+
+    friend class AssetManager;
+
+    /*
+     * This holds information about files in the asset hierarchy.
+     */
+    class FileInfo {
+    public:
+        FileInfo(void) {}
+        FileInfo(const String8& path)      // useful for e.g. svect.indexOf
+            : mFileName(path), mFileType(kFileTypeUnknown)
+            {}
+        ~FileInfo(void) {}
+        FileInfo(const FileInfo& src) {
+            copyMembers(src);
+        }
+        const FileInfo& operator= (const FileInfo& src) {
+            if (this != &src)
+                copyMembers(src);
+            return *this;
+        }
+
+        void copyMembers(const FileInfo& src) {
+            mFileName = src.mFileName;
+            mFileType = src.mFileType;
+            mSourceName = src.mSourceName;
+        }
+
+        /* need this for SortedVector; must compare only on file name */
+        bool operator< (const FileInfo& rhs) const {
+            return mFileName < rhs.mFileName;
+        }
+
+        /* used by AssetManager */
+        bool operator== (const FileInfo& rhs) const {
+            return mFileName == rhs.mFileName;
+        }
+
+        void set(const String8& path, FileType type) {
+            mFileName = path;
+            mFileType = type;
+        }
+
+        const String8& getFileName(void) const { return mFileName; }
+        void setFileName(const String8& path) { mFileName = path; }
+
+        FileType getFileType(void) const { return mFileType; }
+        void setFileType(FileType type) { mFileType = type; }
+
+        const String8& getSourceName(void) const { return mSourceName; }
+        void setSourceName(const String8& path) { mSourceName = path; }
+
+        /*
+         * Handy utility for finding an entry in a sorted vector of FileInfo.
+         * Returns the index of the matching entry, or -1 if none found.
+         */
+        static int findEntry(const SortedVector<FileInfo>* pVector,
+            const String8& fileName);
+
+    private:
+        String8    mFileName;      // filename only
+        FileType    mFileType;      // regular, directory, etc
+
+        String8    mSourceName;    // currently debug-only
+    };
+
+    /* AssetManager uses this to initialize us */
+    void setFileList(SortedVector<FileInfo>* list) { mFileInfo = list; }
+
+    SortedVector<FileInfo>* mFileInfo;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ASSETDIR_H
diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h
new file mode 100644
index 0000000..e94c0e8
--- /dev/null
+++ b/include/utils/AssetManager.h
@@ -0,0 +1,323 @@
+/*
+ * 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.
+ */
+
+//
+// Asset management class.  AssetManager objects are thread-safe.
+//
+#ifndef __LIBS_ASSETMANAGER_H
+#define __LIBS_ASSETMANAGER_H
+
+#include <utils/Asset.h>
+#include <utils/AssetDir.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+#include <utils/ZipFileRO.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class Asset;        // fwd decl for things that include Asset.h first
+class ResTable;
+struct ResTable_config;
+
+/*
+ * Every application that uses assets needs one instance of this.  A
+ * single instance may be shared across multiple threads, and a single
+ * thread may have more than one instance (the latter is discouraged).
+ *
+ * The purpose of the AssetManager is to create Asset objects.  To do
+ * this efficiently it may cache information about the locations of
+ * files it has seen.  This can be controlled with the "cacheMode"
+ * argument.
+ *
+ * The asset hierarchy may be examined like a filesystem, using
+ * AssetDir objects to peruse a single directory.
+ */
+class AssetManager {
+public:
+    typedef enum CacheMode {
+        CACHE_UNKNOWN = 0,
+        CACHE_OFF,          // don't try to cache file locations
+        CACHE_DEFER,        // construct cache as pieces are needed
+        //CACHE_SCAN,         // scan full(!) asset hierarchy at init() time
+    } CacheMode;
+
+    AssetManager(CacheMode cacheMode = CACHE_OFF);
+    virtual ~AssetManager(void);
+
+    static int32_t getGlobalCount();
+    
+    /*                                                                       
+     * Add a new source for assets.  This can be called multiple times to
+     * look in multiple places for assets.  It can be either a directory (for
+     * finding assets as raw files on the disk) or a ZIP file.  This newly
+     * added asset path will be examined first when searching for assets,
+     * before any that were previously added.
+     *
+     * Returns "true" on success, "false" on failure.  If 'cookie' is non-NULL,
+     * then on success, *cookie is set to the value corresponding to the
+     * newly-added asset source.
+     */
+    bool addAssetPath(const String8& path, void** cookie);
+
+    /*                                                                       
+     * Convenience for adding the standard system assets.  Uses the
+     * ANDROID_ROOT environment variable to find them.
+     */
+    bool addDefaultAssets();
+
+    /*                                                                       
+     * Iterate over the asset paths in this manager.  (Previously
+     * added via addAssetPath() and addDefaultAssets().)  On first call,
+     * 'cookie' must be NULL, resulting in the first cookie being returned.
+     * Each next cookie will be returned there-after, until NULL indicating
+     * the end has been reached.
+     */
+    void* nextAssetPath(void* cookie) const;
+
+    /*                                                                       
+     * Return an asset path in the manager.  'which' must be between 0 and
+     * countAssetPaths().
+     */
+    String8 getAssetPath(void* cookie) const;
+
+    /*
+     * Set the current locale and vendor.  The locale can change during
+     * the lifetime of an AssetManager if the user updates the device's
+     * language setting.  The vendor is less likely to change.
+     *
+     * Pass in NULL to indicate no preference.
+     */
+    void setLocale(const char* locale);
+    void setVendor(const char* vendor);
+
+    /*
+     * Choose screen orientation for resources values returned.
+     */
+    void setConfiguration(const ResTable_config& config, const char* locale = NULL);
+
+    typedef Asset::AccessMode AccessMode;       // typing shortcut
+
+    /*
+     * Open an asset.
+     *
+     * This will search through locale-specific and vendor-specific
+     * directories and packages to find the file.
+     *
+     * The object returned does not depend on the AssetManager.  It should
+     * be freed by calling Asset::close().
+     */
+    Asset* open(const char* fileName, AccessMode mode);
+
+    /*
+     * Open a non-asset file as an asset.
+     *
+     * This is for opening files that are included in an asset package
+     * but aren't assets.  These sit outside the usual "locale/vendor"
+     * path hierarchy, and will not be seen by "AssetDir" or included
+     * in our filename cache.
+     */
+    Asset* openNonAsset(const char* fileName, AccessMode mode);
+
+    /*
+     * Explicit non-asset file.  The file explicitly named by the cookie (the
+     * resource set to look in) and fileName will be opened and returned.
+     */
+    Asset* openNonAsset(void* cookie, const char* fileName, AccessMode mode);
+
+    /*
+     * Open a directory within the asset hierarchy.
+     *
+     * The contents of the directory are an amalgam of vendor-specific,
+     * locale-specific, and generic assets stored loosely or in asset
+     * packages.  Depending on the cache setting and previous accesses,
+     * this call may incur significant disk overhead.
+     *
+     * To open the top-level directory, pass in "".
+     */
+    AssetDir* openDir(const char* dirName);
+
+    /*
+     * Get the type of a file in the asset hierarchy.  They will either
+     * be "regular" or "directory".  [Currently only works for "regular".]
+     *
+     * Can also be used as a quick test for existence of a file.
+     */
+    FileType getFileType(const char* fileName);
+
+    /*                                                                       
+     * Return the complete resource table to find things in the package.
+     */
+    const ResTable& getResources(bool required = true) const;
+
+    /*
+     * Discard cached filename information.  This only needs to be called
+     * if somebody has updated the set of "loose" files, and we want to
+     * discard our cached notion of what's where.
+     */
+    void purge(void) { purgeFileNameCacheLocked(); }
+
+    /*
+     * Return true if the files this AssetManager references are all
+     * up-to-date (have not been changed since it was created).  If false
+     * is returned, you will need to create a new AssetManager to get
+     * the current data.
+     */
+    bool isUpToDate();
+    
+    /**
+     * Get the known locales for this asset manager object.
+     */
+    void getLocales(Vector<String8>* locales) const;
+
+private:
+    struct asset_path
+    {
+        String8 path;
+        FileType type;
+    };
+
+    Asset* openInPathLocked(const char* fileName, AccessMode mode,
+        const asset_path& path);
+    Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
+        const asset_path& path);
+    Asset* openInLocaleVendorLocked(const char* fileName, AccessMode mode,
+        const asset_path& path, const char* locale, const char* vendor);
+    String8 createPathNameLocked(const asset_path& path, const char* locale,
+        const char* vendor);
+    String8 createPathNameLocked(const asset_path& path, const char* rootDir);
+    String8 createZipSourceNameLocked(const String8& zipFileName,
+        const String8& dirName, const String8& fileName);
+
+    ZipFileRO* getZipFileLocked(const asset_path& path);
+    Asset* openAssetFromFileLocked(const String8& fileName, AccessMode mode);
+    Asset* openAssetFromZipLocked(const ZipFileRO* pZipFile,
+        const ZipEntryRO entry, AccessMode mode, const String8& entryName);
+
+    bool scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+        const asset_path& path, const char* rootDir, const char* dirName);
+    SortedVector<AssetDir::FileInfo>* scanDirLocked(const String8& path);
+    bool scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+        const asset_path& path, const char* rootDir, const char* dirName);
+    void mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+        const SortedVector<AssetDir::FileInfo>* pContents);
+
+    void loadFileNameCacheLocked(void);
+    void fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+        const char* dirName);
+    bool fncScanAndMergeDirLocked(
+        SortedVector<AssetDir::FileInfo>* pMergedInfo,
+        const asset_path& path, const char* locale, const char* vendor,
+        const char* dirName);
+    void purgeFileNameCacheLocked(void);
+
+    const ResTable* getResTable(bool required = true) const;
+    void setLocaleLocked(const char* locale);
+    void updateResourceParamsLocked() const;
+
+    class SharedZip : public RefBase {
+    public:
+        static sp<SharedZip> get(const String8& path);
+
+        ZipFileRO* getZip();
+
+        Asset* getResourceTableAsset();
+        Asset* setResourceTableAsset(Asset* asset);
+
+        bool isUpToDate();
+        
+    protected:
+        ~SharedZip();
+
+    private:
+        SharedZip(const String8& path, time_t modWhen);
+        SharedZip(); // <-- not implemented
+
+        String8 mPath;
+        ZipFileRO* mZipFile;
+        time_t mModWhen;
+
+        Asset* mResourceTableAsset;
+
+        static Mutex gLock;
+        static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
+    };
+
+    /*
+     * Manage a set of Zip files.  For each file we need a pointer to the
+     * ZipFile and a time_t with the file's modification date.
+     *
+     * We currently only have two zip files (current app, "common" app).
+     * (This was originally written for 8, based on app/locale/vendor.)
+     */
+    class ZipSet {
+    public:
+        ZipSet(void);
+        ~ZipSet(void);
+
+        /*
+         * Return a ZipFileRO structure for a ZipFileRO with the specified
+         * parameters.
+         */
+        ZipFileRO* getZip(const String8& path);
+
+        Asset* getZipResourceTable(const String8& path);
+        Asset* setZipResourceTable(const String8& path, Asset* asset);
+
+        // generate path, e.g. "common/en-US-noogle.zip"
+        static String8 getPathName(const char* path);
+
+        bool isUpToDate();
+        
+    private:
+        void closeZip(int idx);
+
+        int getIndex(const String8& zip) const;
+        mutable Vector<String8> mZipPath;
+        mutable Vector<sp<SharedZip> > mZipFile;
+    };
+
+    // Protect all internal state.
+    mutable Mutex   mLock;
+
+    ZipSet          mZipSet;
+
+    Vector<asset_path> mAssetPaths;
+    char*           mLocale;
+    char*           mVendor;
+
+    mutable ResTable* mResources;
+    ResTable_config* mConfig;
+
+    /*
+     * Cached data for "loose" files.  This lets us avoid poking at the
+     * filesystem when searching for loose assets.  Each entry is the
+     * "extended partial" path, e.g. "default/default/foo/bar.txt".  The
+     * full set of files is present, including ".EXCLUDE" entries.
+     *
+     * We do not cache directory names.  We don't retain the ".gz",
+     * because to our clients "foo" and "foo.gz" both look like "foo".
+     */
+    CacheMode       mCacheMode;         // is the cache enabled?
+    bool            mCacheValid;        // clear when locale or vendor changes
+    SortedVector<AssetDir::FileInfo> mCache;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ASSETMANAGER_H
diff --git a/include/utils/Atomic.h b/include/utils/Atomic.h
new file mode 100644
index 0000000..7eb476c
--- /dev/null
+++ b/include/utils/Atomic.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_UTILS_ATOMIC_H
+#define ANDROID_UTILS_ATOMIC_H
+
+#include <cutils/atomic.h>
+
+#endif // ANDROID_UTILS_ATOMIC_H
diff --git a/include/utils/Binder.h b/include/utils/Binder.h
new file mode 100644
index 0000000..b5b8d98
--- /dev/null
+++ b/include/utils/Binder.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BINDER_H
+#define ANDROID_BINDER_H
+
+#include <utils/IBinder.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BBinder : public IBinder
+{
+public:
+                        BBinder();
+
+    virtual String16    getInterfaceDescriptor() const;
+    virtual bool        isBinderAlive() const;
+    virtual status_t    pingBinder();
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+    virtual status_t    transact(   uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+
+    virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient,
+                                    void* cookie = NULL,
+                                    uint32_t flags = 0);
+
+    virtual status_t    unlinkToDeath(  const wp<DeathRecipient>& recipient,
+                                        void* cookie = NULL,
+                                        uint32_t flags = 0,
+                                        wp<DeathRecipient>* outRecipient = NULL);
+
+    virtual void        attachObject(   const void* objectID,
+                                        void* object,
+                                        void* cleanupCookie,
+                                        object_cleanup_func func);
+    virtual void*       findObject(const void* objectID) const;
+    virtual void        detachObject(const void* objectID);
+
+    virtual BBinder*    localBinder();
+
+protected:
+    virtual             ~BBinder();
+
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+
+private:
+                        BBinder(const BBinder& o);
+            BBinder&    operator=(const BBinder& o);
+
+    class Extras;
+
+            Extras*     mExtras;
+            void*       mReserved0;
+};
+
+// ---------------------------------------------------------------------------
+
+class BpRefBase : public virtual RefBase
+{
+protected:
+                            BpRefBase(const sp<IBinder>& o);
+    virtual                 ~BpRefBase();
+    virtual void            onFirstRef();
+    virtual void            onLastStrongRef(const void* id);
+    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
+
+    inline  IBinder*        remote()                { return mRemote; }
+    inline  IBinder*        remote() const          { return mRemote; }
+
+private:
+                            BpRefBase(const BpRefBase& o);
+    BpRefBase&              operator=(const BpRefBase& o);
+
+    IBinder* const          mRemote;
+    RefBase::weakref_type*  mRefs;
+    volatile int32_t        mState;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_BINDER_H
diff --git a/include/utils/BpBinder.h b/include/utils/BpBinder.h
new file mode 100644
index 0000000..7b96e29
--- /dev/null
+++ b/include/utils/BpBinder.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_BPBINDER_H
+#define ANDROID_BPBINDER_H
+
+#include <utils/IBinder.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BpBinder : public IBinder
+{
+public:
+                        BpBinder(int32_t handle);
+
+    inline  int32_t     handle() const { return mHandle; }
+
+    virtual String16    getInterfaceDescriptor() const;
+    virtual bool        isBinderAlive() const;
+    virtual status_t    pingBinder();
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+    virtual status_t    transact(   uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+
+    virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient,
+                                    void* cookie = NULL,
+                                    uint32_t flags = 0);
+    virtual status_t    unlinkToDeath(  const wp<DeathRecipient>& recipient,
+                                        void* cookie = NULL,
+                                        uint32_t flags = 0,
+                                        wp<DeathRecipient>* outRecipient = NULL);
+
+    virtual void        attachObject(   const void* objectID,
+                                        void* object,
+                                        void* cleanupCookie,
+                                        object_cleanup_func func);
+    virtual void*       findObject(const void* objectID) const;
+    virtual void        detachObject(const void* objectID);
+
+    virtual BpBinder*   remoteBinder();
+
+            status_t    setConstantData(const void* data, size_t size);
+            void        sendObituary();
+
+    class ObjectManager
+    {
+    public:
+                    ObjectManager();
+                    ~ObjectManager();
+
+        void        attach( const void* objectID,
+                            void* object,
+                            void* cleanupCookie,
+                            IBinder::object_cleanup_func func);
+        void*       find(const void* objectID) const;
+        void        detach(const void* objectID);
+
+        void        kill();
+
+    private:
+                    ObjectManager(const ObjectManager&);
+        ObjectManager& operator=(const ObjectManager&);
+
+        struct entry_t
+        {
+            void* object;
+            void* cleanupCookie;
+            IBinder::object_cleanup_func func;
+        };
+
+        KeyedVector<const void*, entry_t> mObjects;
+    };
+
+protected:
+    virtual             ~BpBinder();
+    virtual void        onFirstRef();
+    virtual void        onLastStrongRef(const void* id);
+    virtual bool        onIncStrongAttempted(uint32_t flags, const void* id);
+
+private:
+    const   int32_t             mHandle;
+
+    struct Obituary {
+        wp<DeathRecipient> recipient;
+        void* cookie;
+        uint32_t flags;
+    };
+
+            void                reportOneDeath(const Obituary& obit);
+
+    mutable Mutex               mLock;
+            volatile int32_t    mAlive;
+            volatile int32_t    mObitsSent;
+            Vector<Obituary>*   mObituaries;
+            ObjectManager       mObjects;
+            Parcel*             mConstantData;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_BPBINDER_H
diff --git a/include/utils/Buffer.h b/include/utils/Buffer.h
new file mode 100644
index 0000000..8e22b0f
--- /dev/null
+++ b/include/utils/Buffer.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#ifndef __UTILS_BUFFER_H__
+#define __UTILS_BUFFER_H__ 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace android {
+
+class Buffer
+{
+private:
+    char *buf;
+    int bufsiz;
+    int used;
+    void ensureCapacity(int len);
+
+    void
+    makeRoomFor(int len)
+    {
+        if (len + used >= bufsiz) {
+            bufsiz = (len + used) * 3/2 + 2;
+            char *blah = new char[bufsiz];
+
+            memcpy(blah, buf, used);
+            delete[] buf;
+            buf = blah;
+        }
+    }
+    
+public:
+    Buffer()
+    {
+        bufsiz = 16;
+        buf = new char[bufsiz];
+        clear();
+    }
+
+    ~Buffer()
+    {
+       delete[] buf;
+    }
+
+    void
+    clear()
+    {
+        buf[0] = '\0';
+        used = 0;
+    }
+
+    int
+    length()
+    {
+        return used;
+    }
+
+    void
+    append(const char c)
+    {
+        makeRoomFor(1);
+        buf[used] = c;
+        used++;
+        buf[used] = '\0';
+    }
+
+    void
+    append(const char *s, int len)
+    {
+        makeRoomFor(len);
+
+        memcpy(buf + used, s, len);
+        used += len;
+        buf[used] = '\0';
+    }
+
+    void
+    append(const char *s)
+    {
+        append(s, strlen(s));
+    }
+
+    char *
+    getBytes()
+    {
+        return buf;
+    }
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/utils/BufferedTextOutput.h b/include/utils/BufferedTextOutput.h
new file mode 100644
index 0000000..69c6240
--- /dev/null
+++ b/include/utils/BufferedTextOutput.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BUFFEREDTEXTOUTPUT_H
+#define ANDROID_BUFFEREDTEXTOUTPUT_H
+
+#include <utils/TextOutput.h>
+#include <utils/threads.h>
+#include <cutils/uio.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BufferedTextOutput : public TextOutput
+{
+public:
+    //** Flags for constructor */
+    enum {
+        MULTITHREADED = 0x0001
+    };
+    
+                        BufferedTextOutput(uint32_t flags = 0);
+    virtual             ~BufferedTextOutput();
+    
+    virtual status_t    print(const char* txt, size_t len);
+    virtual void        moveIndent(int delta);
+    
+    virtual void        pushBundle();
+    virtual void        popBundle();
+    
+protected:
+    virtual status_t    writeLines(const struct iovec& vec, size_t N) = 0;
+
+private:
+    struct BufferState;
+    struct ThreadState;
+    
+    static  ThreadState*getThreadState();
+    static  void        threadDestructor(void *st);
+    
+            BufferState*getBuffer() const;
+            
+    uint32_t            mFlags;
+    const int32_t       mSeq;
+    const int32_t       mIndex;
+    
+    Mutex               mLock;
+    BufferState*        mGlobalState;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_BUFFEREDTEXTOUTPUT_H
diff --git a/include/utils/ByteOrder.h b/include/utils/ByteOrder.h
new file mode 100644
index 0000000..4c06067
--- /dev/null
+++ b/include/utils/ByteOrder.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+//
+
+#ifndef _LIBS_UTILS_BYTE_ORDER_H
+#define _LIBS_UTILS_BYTE_ORDER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#ifdef HAVE_WINSOCK
+#include <winsock2.h>
+#else
+#include <netinet/in.h>
+#endif
+
+/*
+ * These macros are like the hton/ntoh byte swapping macros,
+ * except they allow you to swap to and from the "device" byte
+ * order.  The device byte order is the endianness of the target
+ * device -- for the ARM CPUs we use today, this is little endian.
+ *
+ * Note that the byte swapping functions have not been optimized
+ * much; performance is currently not an issue for them since the
+ * intent is to allow us to avoid byte swapping on the device.
+ */
+
+#define DEVICE_BYTE_ORDER LITTLE_ENDIAN
+
+#if BYTE_ORDER == DEVICE_BYTE_ORDER
+
+#define	dtohl(x)	(x)
+#define	dtohs(x)	(x)
+#define	htodl(x)	(x)
+#define	htods(x)	(x)
+
+#else
+
+static inline uint32_t android_swap_long(uint32_t v)
+{
+    return (v<<24) | ((v<<8)&0x00FF0000) | ((v>>8)&0x0000FF00) | (v>>24);
+}
+
+static inline uint16_t android_swap_short(uint16_t v)
+{
+    return (v<<8) | (v>>8);
+}
+
+#define	dtohl(x)	(android_swap_long(x))
+#define	dtohs(x)	(android_swap_short(x))
+#define	htodl(x)	(android_swap_long(x))
+#define	htods(x)	(android_swap_short(x))
+
+#endif
+
+#endif // _LIBS_UTILS_BYTE_ORDER_H
diff --git a/include/utils/CallStack.h b/include/utils/CallStack.h
new file mode 100644
index 0000000..c2c8ce5
--- /dev/null
+++ b/include/utils/CallStack.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_CALLSTACK_H
+#define ANDROID_CALLSTACK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/String8.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class CallStack
+{
+public:
+    enum {
+        MAX_DEPTH = 31
+    };
+
+    CallStack();
+    CallStack(const CallStack& rhs);
+    ~CallStack();
+
+    CallStack& operator = (const CallStack& rhs);
+    
+    bool operator == (const CallStack& rhs) const;
+    bool operator != (const CallStack& rhs) const;
+    bool operator < (const CallStack& rhs) const;
+    bool operator >= (const CallStack& rhs) const;
+    bool operator > (const CallStack& rhs) const;
+    bool operator <= (const CallStack& rhs) const;
+    
+    const void* operator [] (int index) const;
+    
+    void clear();
+
+    void update(int32_t ignoreDepth=0, int32_t maxDepth=MAX_DEPTH);
+
+    // Dump a stack trace to the log
+    void dump(const char* prefix = 0) const;
+
+    // Return a string (possibly very long) containing the complete stack trace
+    String8 toString(const char* prefix = 0) const;
+    
+    size_t size() const { return mCount; }
+
+private:
+    // Internal helper function
+    String8 toStringSingleLevel(const char* prefix, int32_t level) const;
+
+    size_t      mCount;
+    const void* mStack[MAX_DEPTH];
+};
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_CALLSTACK_H
diff --git a/include/utils/Debug.h b/include/utils/Debug.h
new file mode 100644
index 0000000..a662b9c
--- /dev/null
+++ b/include/utils/Debug.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Debugging tools.  These should be able to be stripped
+// in release builds.
+//
+#ifndef ANDROID_DEBUG_H
+#define ANDROID_DEBUG_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+
+template<bool> struct CompileTimeAssert;
+template<> struct CompileTimeAssert<true> {};
+
+const char* stringForIndent(int32_t indentLevel);
+
+typedef void (*debugPrintFunc)(void* cookie, const char* txt);
+
+void printTypeCode(uint32_t typeCode,
+    debugPrintFunc func = 0, void* cookie = 0);
+void printHexData(int32_t indent, const void *buf, size_t length,
+    size_t bytesPerLine=16, int32_t singleLineBytesCutoff=16,
+    size_t alignment=0, bool cArrayStyle=false,
+    debugPrintFunc func = 0, void* cookie = 0);
+
+}; // namespace android
+
+#endif // ANDROID_DEBUG_H
diff --git a/include/utils/Endian.h b/include/utils/Endian.h
new file mode 100644
index 0000000..19f2504
--- /dev/null
+++ b/include/utils/Endian.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Android endian-ness defines.
+//
+#ifndef _LIBS_UTILS_ENDIAN_H
+#define _LIBS_UTILS_ENDIAN_H
+
+#if defined(HAVE_ENDIAN_H)
+
+#include <endian.h>
+
+#else /*not HAVE_ENDIAN_H*/
+
+#define __BIG_ENDIAN 0x1000
+#define __LITTLE_ENDIAN 0x0001
+
+#if defined(HAVE_LITTLE_ENDIAN)
+# define __BYTE_ORDER __LITTLE_ENDIAN
+#else
+# define __BYTE_ORDER __BIG_ENDIAN
+#endif
+
+#endif /*not HAVE_ENDIAN_H*/
+
+#endif /*_LIBS_UTILS_ENDIAN_H*/
diff --git a/include/utils/Errors.h b/include/utils/Errors.h
new file mode 100644
index 0000000..1bf9e6f
--- /dev/null
+++ b/include/utils/Errors.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_ERRORS_H
+#define ANDROID_ERRORS_H
+
+#include <sys/types.h>
+#include <errno.h>
+
+namespace android {
+
+// use this type to return error codes
+#ifdef HAVE_MS_C_RUNTIME
+typedef int         status_t;
+#else
+typedef int32_t     status_t;
+#endif
+
+/* the MS C runtime lacks a few error codes */
+
+/*
+ * Error codes. 
+ * All error codes are negative values.
+ */
+
+// Win32 #defines NO_ERROR as well.  It has the same value, so there's no
+// real conflict, though it's a bit awkward.
+#ifdef _WIN32
+# undef NO_ERROR
+#endif
+ 
+enum {
+    OK                = 0,    // Everything's swell.
+    NO_ERROR          = 0,    // No errors.
+    
+    UNKNOWN_ERROR       = 0x80000000,
+
+    NO_MEMORY           = -ENOMEM,
+    INVALID_OPERATION   = -ENOSYS,
+    BAD_VALUE           = -EINVAL,
+    BAD_TYPE            = 0x80000001,
+    NAME_NOT_FOUND      = -ENOENT,
+    PERMISSION_DENIED   = -EPERM,
+    NO_INIT             = -ENODEV,
+    ALREADY_EXISTS      = -EEXIST,
+    DEAD_OBJECT         = -EPIPE,
+    FAILED_TRANSACTION  = 0x80000002,
+    JPARKS_BROKE_IT     = -EPIPE,
+#if !defined(HAVE_MS_C_RUNTIME)
+    BAD_INDEX           = -EOVERFLOW,
+    NOT_ENOUGH_DATA     = -ENODATA,
+    WOULD_BLOCK         = -EWOULDBLOCK, 
+    TIMED_OUT           = -ETIME,
+    UNKNOWN_TRANSACTION = -EBADMSG,
+#else    
+    BAD_INDEX           = -E2BIG,
+    NOT_ENOUGH_DATA     = 0x80000003,
+    WOULD_BLOCK         = 0x80000004,
+    TIMED_OUT           = 0x80000005,
+    UNKNOWN_TRANSACTION = 0x80000006,
+#endif    
+};
+
+// Restore define; enumeration is in "android" namespace, so the value defined
+// there won't work for Win32 code in a different namespace.
+#ifdef _WIN32
+# define NO_ERROR 0L
+#endif
+
+}; // namespace android
+    
+// ---------------------------------------------------------------------------
+    
+#endif // ANDROID_ERRORS_H
diff --git a/include/utils/FileMap.h b/include/utils/FileMap.h
new file mode 100644
index 0000000..8dfd3be
--- /dev/null
+++ b/include/utils/FileMap.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+//
+// Encapsulate a shared file mapping.
+//
+#ifndef __LIBS_FILE_MAP_H
+#define __LIBS_FILE_MAP_H
+
+#include <sys/types.h>
+
+#ifdef HAVE_WIN32_FILEMAP
+#include <windows.h>
+#endif
+
+namespace android {
+
+/*
+ * This represents a memory-mapped file.  It might be the entire file or
+ * only part of it.  This requires a little bookkeeping because the mapping
+ * needs to be aligned on page boundaries, and in some cases we'd like to
+ * have multiple references to the mapped area without creating additional
+ * maps.
+ *
+ * This always uses MAP_SHARED.
+ *
+ * TODO: we should be able to create a new FileMap that is a subset of
+ * an existing FileMap and shares the underlying mapped pages.  Requires
+ * completing the refcounting stuff and possibly introducing the notion
+ * of a FileMap hierarchy.
+ */
+class FileMap {
+public:
+    FileMap(void);
+
+    /*
+     * Create a new mapping on an open file.
+     *
+     * Closing the file descriptor does not unmap the pages, so we don't
+     * claim ownership of the fd.
+     *
+     * Returns "false" on failure.
+     */
+    bool create(const char* origFileName, int fd,
+                off_t offset, size_t length, bool readOnly);
+
+    /*
+     * Return the name of the file this map came from, if known.
+     */
+    const char* getFileName(void) const { return mFileName; }
+    
+    /*
+     * Get a pointer to the piece of the file we requested.
+     */
+    void* getDataPtr(void) const { return mDataPtr; }
+
+    /*
+     * Get the length we requested.
+     */
+    size_t getDataLength(void) const { return mDataLength; }
+
+    /*
+     * Get the data offset used to create this map.
+     */
+    off_t getDataOffset(void) const { return mDataOffset; }
+
+    /*
+     * Get a "copy" of the object.
+     */
+    FileMap* acquire(void) { mRefCount++; return this; }
+
+    /*
+     * Call this when mapping is no longer needed.
+     */
+    void release(void) {
+        if (--mRefCount <= 0)
+            delete this;
+    }
+
+    /*
+     * This maps directly to madvise() values, but allows us to avoid
+     * including <sys/mman.h> everywhere.
+     */
+    enum MapAdvice {
+        NORMAL, RANDOM, SEQUENTIAL, WILLNEED, DONTNEED
+    };
+
+    /*
+     * Apply an madvise() call to the entire file.
+     *
+     * Returns 0 on success, -1 on failure.
+     */
+    int advise(MapAdvice advice);
+
+protected:
+    // don't delete objects; call release()
+    ~FileMap(void);
+
+private:
+    // these are not implemented
+    FileMap(const FileMap& src);
+    const FileMap& operator=(const FileMap& src);
+
+    int         mRefCount;      // reference count
+    char*       mFileName;      // original file name, if known
+    void*       mBasePtr;       // base of mmap area; page aligned
+    size_t      mBaseLength;    // length, measured from "mBasePtr"
+    off_t       mDataOffset;    // offset used when map was created
+    void*       mDataPtr;       // start of requested data, offset from base
+    size_t      mDataLength;    // length, measured from "mDataPtr"
+#ifdef HAVE_WIN32_FILEMAP
+    HANDLE      mFileHandle;    // Win32 file handle
+    HANDLE      mFileMapping;   // Win32 file mapping handle
+#endif
+
+    static long mPageSize;
+};
+
+}; // namespace android
+
+#endif // __LIBS_FILE_MAP_H
diff --git a/include/utils/IBinder.h b/include/utils/IBinder.h
new file mode 100644
index 0000000..7370330
--- /dev/null
+++ b/include/utils/IBinder.h
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_IBINDER_H
+#define ANDROID_IBINDER_H
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+
+#define B_PACK_CHARS(c1, c2, c3, c4) \
+    ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BBinder;
+class BpBinder;
+class IInterface;
+class Parcel;
+
+/**
+ * Base class and low-level protocol for a remotable object.
+ * You can derive from this class to create an object for which other
+ * processes can hold references to it.  Communication between processes
+ * (method calls, property get and set) is down through a low-level
+ * protocol implemented on top of the transact() API.
+ */
+class IBinder : public virtual RefBase
+{
+public:
+    enum {
+        FIRST_CALL_TRANSACTION  = 0x00000001,
+        LAST_CALL_TRANSACTION   = 0x00ffffff,
+
+        PING_TRANSACTION        = B_PACK_CHARS('_','P','N','G'),
+        DUMP_TRANSACTION        = B_PACK_CHARS('_','D','M','P'),
+        INTERFACE_TRANSACTION   = B_PACK_CHARS('_', 'N', 'T', 'F'),
+
+        // Corresponds to tfOneWay -- an asynchronous call.
+        FLAG_ONEWAY             = 0x00000001
+    };
+
+    inline                  IBinder() { }
+
+    /**
+     * Check if this IBinder implements the interface named by
+     * @a descriptor.  If it does, the base pointer to it is returned,
+     * which you can safely static_cast<> to the concrete C++ interface.
+     */
+    virtual sp<IInterface>  queryLocalInterface(const String16& descriptor);
+
+    /**
+     * Return the canonical name of the interface provided by this IBinder
+     * object.
+     */
+    virtual String16        getInterfaceDescriptor() const = 0;
+
+    virtual bool            isBinderAlive() const = 0;
+    virtual status_t        pingBinder() = 0;
+    virtual status_t        dump(int fd, const Vector<String16>& args) = 0;
+
+    virtual status_t        transact(   uint32_t code,
+                                        const Parcel& data,
+                                        Parcel* reply,
+                                        uint32_t flags = 0) = 0;
+
+    /**
+     * This method allows you to add data that is transported through
+     * IPC along with your IBinder pointer.  When implementing a Binder
+     * object, override it to write your desired data in to @a outData.
+     * You can then call getConstantData() on your IBinder to retrieve
+     * that data, from any process.  You MUST return the number of bytes
+     * written in to the parcel (including padding).
+     */
+    class DeathRecipient : public virtual RefBase
+    {
+    public:
+        virtual void binderDied(const wp<IBinder>& who) = 0;
+    };
+
+    /**
+     * Register the @a recipient for a notification if this binder
+     * goes away.  If this binder object unexpectedly goes away
+     * (typically because its hosting process has been killed),
+     * then DeathRecipient::binderDied() will be called with a referene
+     * to this.
+     *
+     * The @a cookie is optional -- if non-NULL, it should be a
+     * memory address that you own (that is, you know it is unique).
+     *
+     * @note You will only receive death notifications for remote binders,
+     * as local binders by definition can't die without you dying as well.
+     * Trying to use this function on a local binder will result in an
+     * INVALID_OPERATION code being returned and nothing happening.
+     *
+     * @note This link always holds a weak reference to its recipient.
+     *
+     * @note You will only receive a weak reference to the dead
+     * binder.  You should not try to promote this to a strong reference.
+     * (Nor should you need to, as there is nothing useful you can
+     * directly do with it now that it has passed on.)
+     */
+    virtual status_t        linkToDeath(const sp<DeathRecipient>& recipient,
+                                        void* cookie = NULL,
+                                        uint32_t flags = 0) = 0;
+
+    /**
+     * Remove a previously registered death notification.
+     * The @a recipient will no longer be called if this object
+     * dies.  The @a cookie is optional.  If non-NULL, you can
+     * supply a NULL @a recipient, and the recipient previously
+     * added with that cookie will be unlinked.
+     */
+    virtual status_t        unlinkToDeath(  const wp<DeathRecipient>& recipient,
+                                            void* cookie = NULL,
+                                            uint32_t flags = 0,
+                                            wp<DeathRecipient>* outRecipient = NULL) = 0;
+
+    virtual bool            checkSubclass(const void* subclassID) const;
+
+    typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
+
+    virtual void            attachObject(   const void* objectID,
+                                            void* object,
+                                            void* cleanupCookie,
+                                            object_cleanup_func func) = 0;
+    virtual void*           findObject(const void* objectID) const = 0;
+    virtual void            detachObject(const void* objectID) = 0;
+
+    virtual BBinder*        localBinder();
+    virtual BpBinder*       remoteBinder();
+
+protected:
+    inline virtual          ~IBinder() { }
+
+private:
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_IBINDER_H
diff --git a/include/utils/IInterface.h b/include/utils/IInterface.h
new file mode 100644
index 0000000..959722a
--- /dev/null
+++ b/include/utils/IInterface.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+#ifndef ANDROID_IINTERFACE_H
+#define ANDROID_IINTERFACE_H
+
+#include <utils/Binder.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IInterface : public virtual RefBase
+{
+public:
+            sp<IBinder>         asBinder();
+            sp<const IBinder>   asBinder() const;
+
+protected:
+    virtual IBinder*            onAsBinder() = 0;
+};
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
+{
+    return INTERFACE::asInterface(obj);
+}
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+class BnInterface : public INTERFACE, public BBinder
+{
+public:
+    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
+    virtual String16            getInterfaceDescriptor() const;
+
+protected:
+    virtual IBinder*            onAsBinder();
+};
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+class BpInterface : public INTERFACE, public BpRefBase
+{
+public:
+                                BpInterface(const sp<IBinder>& remote);
+
+protected:
+    virtual IBinder*            onAsBinder();
+};
+
+// ----------------------------------------------------------------------
+
+#define DECLARE_META_INTERFACE(INTERFACE)                               \
+    static const String16 descriptor;                                   \
+    static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj);        \
+    virtual String16 getInterfaceDescriptor() const;                    \
+
+#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
+    const String16 I##INTERFACE::descriptor(NAME);                      \
+    String16 I##INTERFACE::getInterfaceDescriptor() const {             \
+        return I##INTERFACE::descriptor;                                \
+    }                                                                   \
+    sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj)  \
+    {                                                                   \
+        sp<I##INTERFACE> intr;                                          \
+        if (obj != NULL) {                                              \
+            intr = static_cast<I##INTERFACE*>(                          \
+                obj->queryLocalInterface(                               \
+                        I##INTERFACE::descriptor).get());               \
+            if (intr == NULL) {                                         \
+                intr = new Bp##INTERFACE(obj);                          \
+            }                                                           \
+        }                                                               \
+        return intr;                                                    \
+    }                                                                   \
+
+// ----------------------------------------------------------------------
+// No user-servicable parts after this...
+
+template<typename INTERFACE>
+inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
+        const String16& _descriptor)
+{
+    if (_descriptor == INTERFACE::descriptor) return this;
+    return NULL;
+}
+
+template<typename INTERFACE>
+inline String16 BnInterface<INTERFACE>::getInterfaceDescriptor() const
+{
+    return INTERFACE::getInterfaceDescriptor();
+}
+
+template<typename INTERFACE>
+IBinder* BnInterface<INTERFACE>::onAsBinder()
+{
+    return this;
+}
+
+template<typename INTERFACE>
+inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
+    : BpRefBase(remote)
+{
+}
+
+template<typename INTERFACE>
+inline IBinder* BpInterface<INTERFACE>::onAsBinder()
+{
+    return remote();
+}
+    
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IINTERFACE_H
diff --git a/include/utils/IMemory.h b/include/utils/IMemory.h
new file mode 100644
index 0000000..35a3fd7
--- /dev/null
+++ b/include/utils/IMemory.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_IMEMORY_H
+#define ANDROID_IMEMORY_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IMemoryHeap : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MemoryHeap);
+
+    // flags returned by getFlags()
+    enum {
+        READ_ONLY   = 0x00000001,
+        MAP_ONCE    = 0x00000002
+    };
+
+    virtual int         getHeapID() const = 0;
+    virtual void*       getBase() const = 0;
+    virtual size_t      getSize() const = 0;
+    virtual uint32_t    getFlags() const = 0;
+
+    // these are there just for backward source compatibility
+    int32_t heapID() const { return getHeapID(); }
+    void*   base() const  { return getBase(); }
+    size_t  virtualSize() const { return getSize(); }
+};
+
+class BnMemoryHeap : public BnInterface<IMemoryHeap>
+{
+public:
+    virtual status_t onTransact( 
+            uint32_t code,
+            const Parcel& data,
+            Parcel* reply,
+            uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+class IMemory : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(Memory);
+
+    virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
+
+    // helpers
+    void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
+    void* pointer() const;
+    size_t size() const;
+    ssize_t offset() const;
+};
+
+class BnMemory : public BnInterface<IMemory>
+{
+public:
+    virtual status_t onTransact(
+            uint32_t code,
+            const Parcel& data,
+            Parcel* reply,
+            uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IMEMORY_H
diff --git a/include/utils/IPCThreadState.h b/include/utils/IPCThreadState.h
new file mode 100644
index 0000000..0490fd3
--- /dev/null
+++ b/include/utils/IPCThreadState.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_IPC_THREAD_STATE_H
+#define ANDROID_IPC_THREAD_STATE_H
+
+#include <utils/Errors.h>
+#include <utils/Parcel.h>
+#include <utils/ProcessState.h>
+#include <utils/Vector.h>
+
+#ifdef HAVE_WIN32_PROC
+typedef  int  uid_t;
+#endif
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class IPCThreadState
+{
+public:
+    static  IPCThreadState*     self();
+    
+            sp<ProcessState>    process();
+            
+            status_t            clearLastError();
+
+            int                 getCallingPid();
+            int                 getCallingUid();
+            
+            int64_t             clearCallingIdentity();
+            void                restoreCallingIdentity(int64_t token);
+            
+            void                flushCommands();
+
+            void                joinThreadPool(bool isMain = true);
+            
+            // Stop the local process.
+            void                stopProcess(bool immediate = true);
+            
+            status_t            transact(int32_t handle,
+                                         uint32_t code, const Parcel& data,
+                                         Parcel* reply, uint32_t flags);
+
+            void                incStrongHandle(int32_t handle);
+            void                decStrongHandle(int32_t handle);
+            void                incWeakHandle(int32_t handle);
+            void                decWeakHandle(int32_t handle);
+            status_t            attemptIncStrongHandle(int32_t handle);
+    static  void                expungeHandle(int32_t handle, IBinder* binder);
+            status_t            requestDeathNotification(   int32_t handle,
+                                                            BpBinder* proxy); 
+            status_t            clearDeathNotification( int32_t handle,
+                                                        BpBinder* proxy); 
+
+    static  void                shutdown();
+    
+private:
+                                IPCThreadState();
+                                ~IPCThreadState();
+
+            status_t            sendReply(const Parcel& reply, uint32_t flags);
+            status_t            waitForResponse(Parcel *reply,
+                                                status_t *acquireResult=NULL);
+            status_t            talkWithDriver(bool doReceive=true);
+            status_t            writeTransactionData(int32_t cmd,
+                                                     uint32_t binderFlags,
+                                                     int32_t handle,
+                                                     uint32_t code,
+                                                     const Parcel& data,
+                                                     status_t* statusBuffer);
+            status_t            executeCommand(int32_t command);
+            
+            void                clearCaller();
+            
+    static  void                threadDestructor(void *st);
+    static  void                freeBuffer(Parcel* parcel,
+                                           const uint8_t* data, size_t dataSize,
+                                           const size_t* objects, size_t objectsSize,
+                                           void* cookie);
+    
+    const   sp<ProcessState>    mProcess;
+            Vector<BBinder*>    mPendingStrongDerefs;
+            Vector<RefBase::weakref_type*> mPendingWeakDerefs;
+                                
+            Parcel              mIn;
+            Parcel              mOut;
+            status_t            mLastError;
+            pid_t               mCallingPid;
+            uid_t               mCallingUid;
+};
+    
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_IPC_THREAD_STATE_H
diff --git a/include/utils/IPermissionController.h b/include/utils/IPermissionController.h
new file mode 100644
index 0000000..cb1dd34
--- /dev/null
+++ b/include/utils/IPermissionController.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+#ifndef ANDROID_IPERMISSION_CONTROLLER_H
+#define ANDROID_IPERMISSION_CONTROLLER_H
+
+#include <utils/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IPermissionController : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(PermissionController);
+
+    virtual bool                checkPermission(const String16& permission,
+                                                int32_t pid, int32_t uid) = 0;
+    
+    enum {
+        CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+    };
+};
+
+// ----------------------------------------------------------------------
+
+class BnPermissionController : public BnInterface<IPermissionController>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IPERMISSION_CONTROLLER_H
+
diff --git a/include/utils/IServiceManager.h b/include/utils/IServiceManager.h
new file mode 100644
index 0000000..e3d99fe
--- /dev/null
+++ b/include/utils/IServiceManager.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+#ifndef ANDROID_ISERVICE_MANAGER_H
+#define ANDROID_ISERVICE_MANAGER_H
+
+#include <utils/IInterface.h>
+#include <utils/IPermissionController.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IServiceManager : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(ServiceManager);
+
+    /**
+     * Retrieve an existing service, blocking for a few seconds
+     * if it doesn't yet exist.
+     */
+    virtual sp<IBinder>         getService( const String16& name) const = 0;
+
+    /**
+     * Retrieve an existing service, non-blocking.
+     */
+    virtual sp<IBinder>         checkService( const String16& name) const = 0;
+
+    /**
+     * Register a service.
+     */
+    virtual status_t            addService( const String16& name,
+                                            const sp<IBinder>& service) = 0;
+
+    /**
+     * Return list of all existing services.
+     */
+    virtual Vector<String16>    listServices() = 0;
+
+    enum {
+        GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        CHECK_SERVICE_TRANSACTION,
+        ADD_SERVICE_TRANSACTION,
+        LIST_SERVICES_TRANSACTION,
+    };
+};
+
+sp<IServiceManager> defaultServiceManager();
+
+template<typename INTERFACE>
+status_t getService(const String16& name, sp<INTERFACE>* outService)
+{
+    const sp<IServiceManager> sm = defaultServiceManager();
+    if (sm != NULL) {
+        *outService = interface_cast<INTERFACE>(sm->getService(name));
+        if ((*outService) != NULL) return NO_ERROR;
+    }
+    return NAME_NOT_FOUND;
+}
+
+bool checkCallingPermission(const String16& permission);
+bool checkCallingPermission(const String16& permission,
+                            int32_t* outPid, int32_t* outUid);
+
+// ----------------------------------------------------------------------
+
+class BnServiceManager : public BnInterface<IServiceManager>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ISERVICE_MANAGER_H
+
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
new file mode 100644
index 0000000..f4513ee
--- /dev/null
+++ b/include/utils/KeyedVector.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_KEYED_VECTOR_H
+#define ANDROID_KEYED_VECTOR_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/SortedVector.h>
+#include <utils/TypeHelpers.h>
+#include <utils/Errors.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+template <typename KEY, typename VALUE>
+class KeyedVector
+{
+public:
+    typedef KEY    key_type;
+    typedef VALUE  value_type;
+
+    inline                  KeyedVector();
+
+    /*
+     * empty the vector
+     */
+
+    inline  void            clear()                     { mVector.clear(); }
+
+    /*! 
+     * vector stats
+     */
+
+    //! returns number of items in the vector
+    inline  size_t          size() const                { return mVector.size(); }
+    //! returns wether or not the vector is empty
+    inline  bool            isEmpty() const             { return mVector.isEmpty(); }
+    //! returns how many items can be stored without reallocating the backing store
+    inline  size_t          capacity() const            { return mVector.capacity(); }
+    //! setst the capacity. capacity can never be reduced less than size()
+    inline ssize_t          setCapacity(size_t size)    { return mVector.setCapacity(size); }
+    
+    /*! 
+     * accessors
+     */
+            const VALUE&    valueFor(const KEY& key) const;
+            const VALUE&    valueAt(size_t index) const;
+            const KEY&      keyAt(size_t index) const;
+            ssize_t         indexOfKey(const KEY& key) const;
+
+    /*!
+     * modifing the array
+     */
+
+            VALUE&          editValueFor(const KEY& key);
+            VALUE&          editValueAt(size_t index);
+
+            /*! 
+             * add/insert/replace items
+             */
+             
+            ssize_t         add(const KEY& key, const VALUE& item);
+            ssize_t         replaceValueFor(const KEY& key, const VALUE& item);
+            ssize_t         replaceValueAt(size_t index, const VALUE& item);
+
+    /*!
+     * remove items
+     */
+
+            ssize_t         removeItem(const KEY& key);
+            ssize_t         removeItemsAt(size_t index, size_t count = 1);
+            
+private:
+            SortedVector< key_value_pair_t<KEY, VALUE> >    mVector;
+};
+
+// ---------------------------------------------------------------------------
+
+/**
+ * Variation of KeyedVector that holds a default value to return when
+ * valueFor() is called with a key that doesn't exist.
+ */
+template <typename KEY, typename VALUE>
+class DefaultKeyedVector : public KeyedVector<KEY, VALUE>
+{
+public:
+    inline                  DefaultKeyedVector(const VALUE& defValue = VALUE());
+            const VALUE&    valueFor(const KEY& key) const;
+
+private:
+            VALUE                                           mDefault;
+};
+
+// ---------------------------------------------------------------------------
+
+template<typename KEY, typename VALUE> inline
+KeyedVector<KEY,VALUE>::KeyedVector()
+{
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::indexOfKey(const KEY& key) const {
+    return mVector.indexOf( key_value_pair_t<KEY,VALUE>(key) );
+}
+
+template<typename KEY, typename VALUE> inline
+const VALUE& KeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
+    ssize_t i = indexOfKey(key);
+    assert(i>=0);
+    return mVector.itemAt(i).value;
+}
+
+template<typename KEY, typename VALUE> inline
+const VALUE& KeyedVector<KEY,VALUE>::valueAt(size_t index) const {
+    return mVector.itemAt(index).value;
+}
+
+template<typename KEY, typename VALUE> inline
+const KEY& KeyedVector<KEY,VALUE>::keyAt(size_t index) const {
+    return mVector.itemAt(index).key;
+}
+
+template<typename KEY, typename VALUE> inline
+VALUE& KeyedVector<KEY,VALUE>::editValueFor(const KEY& key) {
+    ssize_t i = indexOfKey(key);
+    assert(i>=0);
+    return mVector.editItemAt(i).value;
+}
+
+template<typename KEY, typename VALUE> inline
+VALUE& KeyedVector<KEY,VALUE>::editValueAt(size_t index) {
+    return mVector.editItemAt(index).value;
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::add(const KEY& key, const VALUE& value) {
+    return mVector.add( key_value_pair_t<KEY,VALUE>(key, value) );
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::replaceValueFor(const KEY& key, const VALUE& value) {
+    key_value_pair_t<KEY,VALUE> pair(key, value);
+    mVector.remove(pair);
+    return mVector.add(pair);
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::replaceValueAt(size_t index, const VALUE& item) {
+    if (index<size()) {
+        mVector.editValueAt(index).value = item;
+        return index;
+    }
+    return BAD_INDEX;
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::removeItem(const KEY& key) {
+    return mVector.remove(key_value_pair_t<KEY,VALUE>(key));
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY, VALUE>::removeItemsAt(size_t index, size_t count) {
+    return mVector.removeItemsAt(index, count);
+}
+
+// ---------------------------------------------------------------------------
+
+template<typename KEY, typename VALUE> inline
+DefaultKeyedVector<KEY,VALUE>::DefaultKeyedVector(const VALUE& defValue)
+    : mDefault(defValue)
+{
+}
+
+template<typename KEY, typename VALUE> inline
+const VALUE& DefaultKeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
+    ssize_t i = indexOfKey(key);
+    return i >= 0 ? KeyedVector<KEY,VALUE>::valueAt(i) : mDefault;
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_KEYED_VECTOR_H
diff --git a/include/utils/List.h b/include/utils/List.h
new file mode 100644
index 0000000..1a6be9a
--- /dev/null
+++ b/include/utils/List.h
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Templated list class.  Normally we'd use STL, but we don't have that.
+// This class mimics STL's interfaces.
+//
+// Objects are copied into the list with the '=' operator or with copy-
+// construction, so if the compiler's auto-generated versions won't work for
+// you, define your own.
+//
+// The only class you want to use from here is "List".  Do not use classes
+// starting with "_" directly.
+//
+#ifndef _LIBS_UTILS_LIST_H
+#define _LIBS_UTILS_LIST_H
+
+namespace android {
+
+/*
+ * One element in the list.
+ */
+template<class T> class _ListNode {
+public:
+    typedef _ListNode<T> _Node;
+
+    _ListNode(const T& val) : mVal(val) {}
+    ~_ListNode(void) {}
+
+    T& getRef(void) { return mVal; }
+    void setVal(const T& val) { mVal = val; }
+
+    _Node* getPrev(void) const { return mpPrev; }
+    void setPrev(_Node* ptr) { mpPrev = ptr; }
+    _Node* getNext(void) const { return mpNext; }
+    void setNext(_Node* ptr) { mpNext = ptr; }
+
+private:
+    T           mVal;
+    _Node*      mpPrev;
+    _Node*      mpNext;
+};
+
+/*
+ * Iterator for walking through the list.
+ */
+template<class T, class Tref> class _ListIterator {
+public:
+    typedef _ListIterator<T,Tref> _Iter;
+    typedef _ListNode<T> _Node;
+
+    _ListIterator(void) {}
+    _ListIterator(_Node* ptr) : mpNode(ptr) {}
+    ~_ListIterator(void) {}
+
+    /*
+     * Dereference operator.  Used to get at the juicy insides.
+     */
+    Tref operator*() const { return mpNode->getRef(); }
+
+    /*
+     * Iterator comparison.
+     */
+    bool operator==(const _Iter& right) const { return mpNode == right.mpNode; }
+    bool operator!=(const _Iter& right) const { return mpNode != right.mpNode; }
+
+    /*
+     * Incr/decr, used to move through the list.
+     */
+    _Iter& operator++(void) {        // pre-increment
+        mpNode = mpNode->getNext();
+        return *this;
+    }
+    _Iter operator++(int) {          // post-increment
+        _Iter tmp = *this;
+        ++*this;
+        return tmp;
+    }
+    _Iter& operator--(void) {        // pre-increment
+        mpNode = mpNode->getPrev();
+        return *this;
+    }
+    _Iter operator--(int) {          // post-increment
+        _Iter tmp = *this;
+        --*this;
+        return tmp;
+    }
+
+    _Node* getNode(void) const { return mpNode; }
+
+private:
+    _Node*      mpNode;
+};
+
+
+/*
+ * Doubly-linked list.  Instantiate with "List<MyClass> myList".
+ *
+ * Objects added to the list are copied using the assignment operator,
+ * so this must be defined.
+ */
+template<class T> class List {
+public:
+    typedef _ListNode<T> _Node;
+
+    List(void) {
+        prep();
+    }
+    List(const List<T>& src) {      // copy-constructor
+        prep();
+        insert(begin(), src.begin(), src.end());
+    }
+    virtual ~List(void) {
+        clear();
+        delete[] (unsigned char*) mpMiddle;
+    }
+
+    typedef _ListIterator<T,T&> iterator;
+    typedef _ListIterator<T, const T&> const_iterator;
+
+    List<T>& operator=(const List<T>& right);
+
+    /* returns true if the list is empty */
+    bool empty(void) const { return mpMiddle->getNext() == mpMiddle; }
+
+    /* return #of elements in list */
+    unsigned int size(void) const {
+        return distance(begin(), end());
+    }
+
+    /*
+     * Return the first element or one past the last element.  The
+     * _ListNode* we're returning is converted to an "iterator" by a
+     * constructor in _ListIterator.
+     */
+    iterator begin()                { return mpMiddle->getNext(); }
+    const_iterator begin() const    { return mpMiddle->getNext(); }
+    iterator end()                  { return mpMiddle; }
+    const_iterator end() const      { return mpMiddle; }
+
+    /* add the object to the head or tail of the list */
+    void push_front(const T& val) { insert(begin(), val); }
+    void push_back(const T& val) { insert(end(), val); }
+
+    /* insert before the current node; returns iterator at new node */
+    iterator insert(iterator posn, const T& val) {
+        _Node* newNode = new _Node(val);        // alloc & copy-construct
+        newNode->setNext(posn.getNode());
+        newNode->setPrev(posn.getNode()->getPrev());
+        posn.getNode()->getPrev()->setNext(newNode);
+        posn.getNode()->setPrev(newNode);
+        return newNode;
+    }
+
+    /* insert a range of elements before the current node */
+    void insert(iterator posn, const_iterator first, const_iterator last) {
+        for ( ; first != last; ++first)
+            insert(posn, *first);
+    }
+
+    /* remove one entry; returns iterator at next node */
+    iterator erase(iterator posn) {
+        _Node* pNext = posn.getNode()->getNext();
+        _Node* pPrev = posn.getNode()->getPrev();
+        pPrev->setNext(pNext);
+        pNext->setPrev(pPrev);
+        delete posn.getNode();
+        return pNext;
+    }
+
+    /* remove a range of elements */
+    iterator erase(iterator first, iterator last) {
+        while (first != last)
+            erase(first++);     // don't erase than incr later!
+        return last;
+    }
+
+    /* remove all contents of the list */
+    void clear(void) {
+        _Node* pCurrent = mpMiddle->getNext();
+        _Node* pNext;
+
+        while (pCurrent != mpMiddle) {
+            pNext = pCurrent->getNext();
+            delete pCurrent;
+            pCurrent = pNext;
+        }
+        mpMiddle->setPrev(mpMiddle);
+        mpMiddle->setNext(mpMiddle);
+    }
+
+    /*
+     * Measure the distance between two iterators.  On exist, "first"
+     * will be equal to "last".  The iterators must refer to the same
+     * list.
+     *
+     * (This is actually a generic iterator function.  It should be part
+     * of some other class, possibly an iterator base class.  It needs to
+     * know the difference between a list, which has to march through,
+     * and a vector, which can just do pointer math.)
+     */
+    unsigned int distance(iterator first, iterator last) {
+        unsigned int count = 0;
+        while (first != last) {
+            ++first;
+            ++count;
+        }
+        return count;
+    }
+    unsigned int distance(const_iterator first, const_iterator last) const {
+        unsigned int count = 0;
+        while (first != last) {
+            ++first;
+            ++count;
+        }
+        return count;
+    }
+
+private:
+    /*
+     * I want a _ListNode but don't need it to hold valid data.  More
+     * to the point, I don't want T's constructor to fire, since it
+     * might have side-effects or require arguments.  So, we do this
+     * slightly uncouth storage alloc.
+     */
+    void prep(void) {
+        mpMiddle = (_Node*) new unsigned char[sizeof(_Node)];
+        mpMiddle->setPrev(mpMiddle);
+        mpMiddle->setNext(mpMiddle);
+    }
+
+    /*
+     * This node plays the role of "pointer to head" and "pointer to tail".
+     * It sits in the middle of a circular list of nodes.  The iterator
+     * runs around the circle until it encounters this one.
+     */
+    _Node*      mpMiddle;
+};
+
+/*
+ * Assignment operator.
+ *
+ * The simplest way to do this would be to clear out the target list and
+ * fill it with the source.  However, we can speed things along by
+ * re-using existing elements.
+ */
+template<class T>
+List<T>& List<T>::operator=(const List<T>& right)
+{
+    if (this == &right)
+        return *this;       // self-assignment
+    iterator firstDst = begin();
+    iterator lastDst = end();
+    const_iterator firstSrc = right.begin();
+    const_iterator lastSrc = right.end();
+    while (firstSrc != lastSrc && firstDst != lastDst)
+        *firstDst++ = *firstSrc++;
+    if (firstSrc == lastSrc)        // ran out of elements in source?
+        erase(firstDst, lastDst);   // yes, erase any extras
+    else
+        insert(lastDst, firstSrc, lastSrc);     // copy remaining over
+    return *this;
+}
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_LIST_H
diff --git a/include/utils/Log.h b/include/utils/Log.h
new file mode 100644
index 0000000..3c6cc8b
--- /dev/null
+++ b/include/utils/Log.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// C/C++ logging functions.  See the logging documentation for API details.
+//
+// We'd like these to be available from C code (in case we import some from
+// somewhere), so this has a C interface.
+//
+// The output will be correct when the log file is shared between multiple
+// threads and/or multiple processes so long as the operating system
+// supports O_APPEND.  These calls have mutex-protected data structures
+// and so are NOT reentrant.  Do not use LOG in a signal handler.
+//
+#ifndef _LIBS_UTILS_LOG_H
+#define _LIBS_UTILS_LOG_H
+
+#include <cutils/log.h>
+
+#endif // _LIBS_UTILS_LOG_H
diff --git a/include/utils/LogSocket.h b/include/utils/LogSocket.h
new file mode 100644
index 0000000..01fbfb5
--- /dev/null
+++ b/include/utils/LogSocket.h
@@ -0,0 +1,20 @@
+/* utils/LogSocket.h
+** 
+** Copyright 2008, The Android Open Source Project
+**
+** This file is dual licensed.  It may be redistributed and/or modified
+** under the terms of the Apache 2.0 License OR version 2 of the GNU
+** General Public License.
+*/
+
+#ifndef _UTILS_LOGSOCKET_H
+#define _UTILS_LOGSOCKET_H
+
+#define SOCKET_CLOSE_LOCAL 0
+
+void add_send_stats(int fd, int send);
+void add_recv_stats(int fd, int recv);
+void log_socket_close(int fd, short reason);
+void log_socket_connect(int fd, unsigned int ip, unsigned short port);
+
+#endif /* _UTILS_LOGSOCKET_H */
diff --git a/include/utils/MemoryBase.h b/include/utils/MemoryBase.h
new file mode 100644
index 0000000..eb5a9d2
--- /dev/null
+++ b/include/utils/MemoryBase.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEMORY_BASE_H
+#define ANDROID_MEMORY_BASE_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <utils/IMemory.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MemoryBase : public BnMemory 
+{
+public:
+    MemoryBase(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
+    virtual ~MemoryBase();
+    virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+
+protected:
+    size_t getSize() const { return mSize; }
+    ssize_t getOffset() const { return mOffset; }
+    const sp<IMemoryHeap>& getHeap() const { return mHeap; }
+
+private:
+    size_t          mSize;
+    ssize_t         mOffset;
+    sp<IMemoryHeap> mHeap;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_BASE_H
diff --git a/include/utils/MemoryDealer.h b/include/utils/MemoryDealer.h
new file mode 100644
index 0000000..454b627
--- /dev/null
+++ b/include/utils/MemoryDealer.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_MEMORY_DEALER_H
+#define ANDROID_MEMORY_DEALER_H
+
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/IMemory.h>
+#include <utils/threads.h>
+#include <utils/MemoryHeapBase.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+class String8;
+
+/*
+ * interface for implementing a "heap". A heap basically provides
+ * the IMemoryHeap interface for cross-process sharing and the
+ * ability to map/unmap pages within the heap.
+ */
+class HeapInterface : public virtual BnMemoryHeap
+{
+public:
+    // all values must be page-aligned
+    virtual sp<IMemory> mapMemory(size_t offset, size_t size) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * interface for implementing an allocator. An allocator provides
+ * methods for allocating and freeing memory blocks and dumping
+ * its state.
+ */
+class AllocatorInterface : public RefBase
+{
+public:
+    enum {
+        PAGE_ALIGNED = 0x00000001
+    };
+
+    virtual size_t      allocate(size_t size, uint32_t flags = 0) = 0;
+    virtual status_t    deallocate(size_t offset) = 0;
+    virtual size_t      size() const = 0;
+    virtual void        dump(const char* what, uint32_t flags = 0) const = 0;
+    virtual void        dump(String8& res,
+            const char* what, uint32_t flags = 0) const = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * concrete implementation of HeapInterface on top of mmap() 
+ */
+class SharedHeap : public HeapInterface, public MemoryHeapBase
+{
+public:
+                        SharedHeap(size_t size, uint32_t flags = 0, char const * name = NULL);
+    virtual             ~SharedHeap();
+    virtual sp<IMemory> mapMemory(size_t offset, size_t size);
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * A simple templatized doubly linked-list implementation
+ */
+
+template <typename NODE>
+class LinkedList
+{
+    NODE*  mFirst;
+    NODE*  mLast;
+
+public:
+                LinkedList() : mFirst(0), mLast(0) { }
+    bool        isEmpty() const { return mFirst == 0; }
+    NODE const* head() const { return mFirst; }
+    NODE*       head() { return mFirst; }
+    NODE const* tail() const { return mLast; }
+    NODE*       tail() { return mLast; }
+
+    void insertAfter(NODE* node, NODE* newNode) {
+        newNode->prev = node;
+        newNode->next = node->next;
+        if (node->next == 0) mLast = newNode;
+        else                 node->next->prev = newNode;
+        node->next = newNode;
+    }
+
+    void insertBefore(NODE* node, NODE* newNode) {
+         newNode->prev = node->prev;
+         newNode->next = node;
+         if (node->prev == 0)   mFirst = newNode;
+         else                   node->prev->next = newNode;
+         node->prev = newNode;
+    }
+
+    void insertHead(NODE* newNode) {
+        if (mFirst == 0) {
+            mFirst = mLast = newNode;
+            newNode->prev = newNode->next = 0;
+        } else {
+            insertBefore(mFirst, newNode);
+        }
+    }
+    
+    void insertTail(NODE* newNode) {
+        if (mLast == 0) insertBeginning(newNode);
+        else            insertAfter(mLast, newNode);
+    }
+
+    NODE* remove(NODE* node) {
+        if (node->prev == 0)    mFirst = node->next;
+        else                    node->prev->next = node->next;
+        if (node->next == 0)    mLast = node->prev;
+        else                    node->next->prev = node->prev;
+        return node;
+    }
+};
+
+
+/*
+ * concrete implementation of AllocatorInterface using a simple
+ * best-fit allocation scheme
+ */
+class SimpleBestFitAllocator : public AllocatorInterface
+{
+public:
+
+                        SimpleBestFitAllocator(size_t size);
+    virtual             ~SimpleBestFitAllocator();
+
+    virtual size_t      allocate(size_t size, uint32_t flags = 0);
+    virtual status_t    deallocate(size_t offset);
+    virtual size_t      size() const;
+    virtual void        dump(const char* what, uint32_t flags = 0) const;
+    virtual void        dump(String8& res,
+            const char* what, uint32_t flags = 0) const;
+
+private:
+
+    struct chunk_t {
+        chunk_t(size_t start, size_t size) 
+            : start(start), size(size), free(1), prev(0), next(0) {
+        }
+        size_t              start;
+        size_t              size : 28;
+        int                 free : 4;
+        mutable chunk_t*    prev;
+        mutable chunk_t*    next;
+    };
+
+    ssize_t  alloc(size_t size, uint32_t flags);
+    chunk_t* dealloc(size_t start);
+    void     dump_l(const char* what, uint32_t flags = 0) const;
+    void     dump_l(String8& res, const char* what, uint32_t flags = 0) const;
+
+    static const int    kMemoryAlign;
+    mutable Mutex       mLock;
+    LinkedList<chunk_t> mList;
+    size_t              mHeapSize;
+};
+
+// ----------------------------------------------------------------------------
+
+class MemoryDealer : public RefBase
+{
+public:
+
+    enum {
+        READ_ONLY = MemoryHeapBase::READ_ONLY,
+        PAGE_ALIGNED = AllocatorInterface::PAGE_ALIGNED
+    };
+
+    // creates a memory dealer with the SharedHeap and SimpleBestFitAllocator
+    MemoryDealer(size_t size, uint32_t flags = 0, const char* name = 0);
+
+    // provide a custom heap but use the SimpleBestFitAllocator
+    MemoryDealer(const sp<HeapInterface>& heap);
+
+    // provide both custom heap and allocotar
+    MemoryDealer(
+            const sp<HeapInterface>& heap,
+            const sp<AllocatorInterface>& allocator);
+
+    virtual ~MemoryDealer();
+
+    virtual sp<IMemory> allocate(size_t size, uint32_t flags = 0);
+    virtual void        deallocate(size_t offset);
+    virtual void        dump(const char* what, uint32_t flags = 0) const;
+
+
+    sp<IMemoryHeap> getMemoryHeap() const { return heap(); }
+    sp<AllocatorInterface> getAllocator() const { return allocator(); }
+
+private:    
+    const sp<HeapInterface>&        heap() const;
+    const sp<AllocatorInterface>&   allocator() const;
+
+    class Allocation : public BnMemory {
+    public:
+        Allocation(const sp<MemoryDealer>& dealer,
+                ssize_t offset, size_t size, const sp<IMemory>& memory);
+        virtual ~Allocation();
+        virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+    private:
+        sp<MemoryDealer>        mDealer;
+        ssize_t                 mOffset;
+        size_t                  mSize;
+        sp<IMemory>             mMemory;
+    };
+
+    sp<HeapInterface>           mHeap;
+    sp<AllocatorInterface>      mAllocator;
+};
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_DEALER_H
diff --git a/include/utils/MemoryHeapBase.h b/include/utils/MemoryHeapBase.h
new file mode 100644
index 0000000..574acf4
--- /dev/null
+++ b/include/utils/MemoryHeapBase.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEMORY_HEAP_BASE_H
+#define ANDROID_MEMORY_HEAP_BASE_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <utils/IMemory.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MemoryHeapBase : public virtual BnMemoryHeap 
+{
+public:
+    enum {
+        READ_ONLY = IMemoryHeap::READ_ONLY,
+        MAP_ONCE = IMemoryHeap::MAP_ONCE,
+        // memory won't be mapped locally, but will be mapped in the remote
+        // process.
+        DONT_MAP_LOCALLY = 0x00000100
+    };
+
+    /* 
+     * maps the memory referenced by fd. but DOESN'T take ownership
+     * of the filedescriptor (it makes a copy with dup()
+     */
+    MemoryHeapBase(int fd, size_t size, uint32_t flags = 0);
+    
+    /*
+     * maps memory from the given device
+     */
+    MemoryHeapBase(const char* device, size_t size = 0, uint32_t flags = 0);
+
+    /*
+     * maps memory from ashmem, with the given name for debugging
+     */
+    MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = NULL);
+
+    virtual ~MemoryHeapBase();
+
+    /* implement IMemoryHeap interface */
+    virtual int         getHeapID() const;
+    virtual void*       getBase() const;
+    virtual size_t      getSize() const;
+    virtual uint32_t    getFlags() const;
+
+    const char*         getDevice() const;
+    
+    /* this closes this heap -- use carefully */
+    void dispose();
+
+    /* this is only needed as a workaround, use only if you know
+     * what you are doing */
+    status_t setDevice(const char* device) {
+        if (mDevice == 0)
+            mDevice = device;
+        return mDevice ? NO_ERROR : ALREADY_EXISTS;
+    }
+    
+protected:
+            MemoryHeapBase();
+    // init() takes ownership of fd
+    status_t init(int fd, void *base, int size,
+            int flags = 0, const char* device = NULL);    
+
+private:
+    status_t mapfd(int fd, size_t size);
+
+    int         mFD;
+    size_t      mSize;
+    void*       mBase;
+    uint32_t    mFlags;
+    const char* mDevice;
+    bool        mNeedUnmap;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_HEAP_BASE_H
diff --git a/include/utils/MemoryHeapPmem.h b/include/utils/MemoryHeapPmem.h
new file mode 100644
index 0000000..60335ad
--- /dev/null
+++ b/include/utils/MemoryHeapPmem.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEMORY_HEAP_PMEM_H
+#define ANDROID_MEMORY_HEAP_PMEM_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <utils/MemoryDealer.h>
+#include <utils/MemoryHeapBase.h>
+#include <utils/IMemory.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+
+class MemoryHeapBase;
+
+// ---------------------------------------------------------------------------
+
+class MemoryHeapPmem : public HeapInterface, public MemoryHeapBase
+{
+public:
+    class MemoryPmem : public BnMemory {
+    public:
+        MemoryPmem(const sp<MemoryHeapPmem>& heap);
+        ~MemoryPmem();
+    protected:
+        const sp<MemoryHeapPmem>&  getHeap() const { return mClientHeap; }
+    private:
+        friend class MemoryHeapPmem;
+        virtual void revoke() = 0;
+        sp<MemoryHeapPmem>  mClientHeap;
+    };
+    
+    MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
+                uint32_t flags = IMemoryHeap::MAP_ONCE);
+    ~MemoryHeapPmem();
+
+    /* HeapInterface additions */
+    virtual sp<IMemory> mapMemory(size_t offset, size_t size);
+
+    /* make the whole heap visible (you know who you are) */
+    virtual status_t slap();
+    
+    /* hide (revoke) the whole heap (the client will see the garbage page) */
+    virtual status_t unslap();
+    
+    /* revoke all allocations made by this heap */
+    virtual void revoke();
+
+private:
+    /* use this to create your own IMemory for mapMemory */
+    virtual sp<MemoryPmem> createMemory(size_t offset, size_t size);
+    void remove(const wp<MemoryPmem>& memory);
+
+private:
+    sp<MemoryHeapBase>              mParentHeap;
+    mutable Mutex                   mLock;
+    SortedVector< wp<MemoryPmem> >  mAllocations;
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_HEAP_PMEM_H
diff --git a/include/utils/Parcel.h b/include/utils/Parcel.h
new file mode 100644
index 0000000..9087c44
--- /dev/null
+++ b/include/utils/Parcel.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_PARCEL_H
+#define ANDROID_PARCEL_H
+
+#include <cutils/native_handle.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class IBinder;
+class ProcessState;
+class String8;
+class TextOutput;
+
+struct flat_binder_object;  // defined in support_p/binder_module.h
+
+class Parcel
+{
+public:
+                        Parcel();
+                        ~Parcel();
+    
+    const uint8_t*      data() const;
+    size_t              dataSize() const;
+    size_t              dataAvail() const;
+    size_t              dataPosition() const;
+    size_t              dataCapacity() const;
+    
+    status_t            setDataSize(size_t size);
+    void                setDataPosition(size_t pos) const;
+    status_t            setDataCapacity(size_t size);
+    
+    status_t            setData(const uint8_t* buffer, size_t len);
+
+    status_t            appendFrom(Parcel *parcel, size_t start, size_t len);
+
+    bool                hasFileDescriptors() const;
+
+    status_t            writeInterfaceToken(const String16& interface);
+    bool                enforceInterface(const String16& interface) const;
+            
+    void                freeData();
+
+    const size_t*       objects() const;
+    size_t              objectsCount() const;
+    
+    status_t            errorCheck() const;
+    void                setError(status_t err);
+    
+    status_t            write(const void* data, size_t len);
+    void*               writeInplace(size_t len);
+    status_t            writeUnpadded(const void* data, size_t len);
+    status_t            writeInt32(int32_t val);
+    status_t            writeInt64(int64_t val);
+    status_t            writeFloat(float val);
+    status_t            writeDouble(double val);
+    status_t            writeCString(const char* str);
+    status_t            writeString8(const String8& str);
+    status_t            writeString16(const String16& str);
+    status_t            writeString16(const char16_t* str, size_t len);
+    status_t            writeStrongBinder(const sp<IBinder>& val);
+    status_t            writeWeakBinder(const wp<IBinder>& val);
+
+    // doesn't take ownership of the native_handle
+    status_t            writeNativeHandle(const native_handle& handle);
+    
+    // Place a file descriptor into the parcel.  The given fd must remain
+    // valid for the lifetime of the parcel.
+    status_t            writeFileDescriptor(int fd);
+    
+    // Place a file descriptor into the parcel.  A dup of the fd is made, which
+    // will be closed once the parcel is destroyed.
+    status_t            writeDupFileDescriptor(int fd);
+    
+    status_t            writeObject(const flat_binder_object& val, bool nullMetaData);
+
+    void                remove(size_t start, size_t amt);
+    
+    status_t            read(void* outData, size_t len) const;
+    const void*         readInplace(size_t len) const;
+    int32_t             readInt32() const;
+    status_t            readInt32(int32_t *pArg) const;
+    int64_t             readInt64() const;
+    status_t            readInt64(int64_t *pArg) const;
+    float               readFloat() const;
+    status_t            readFloat(float *pArg) const;
+    double              readDouble() const;
+    status_t            readDouble(double *pArg) const;
+
+    const char*         readCString() const;
+    String8             readString8() const;
+    String16            readString16() const;
+    const char16_t*     readString16Inplace(size_t* outLen) const;
+    sp<IBinder>         readStrongBinder() const;
+    wp<IBinder>         readWeakBinder() const;
+
+    
+    // if alloc is NULL, native_handle is allocated with malloc(), otherwise
+    // alloc is used. If the function fails, the effects of alloc() must be
+    // reverted by the caller.
+    native_handle*     readNativeHandle(
+            native_handle* (*alloc)(void* cookie, int numFds, int ints),
+            void* cookie) const;
+
+    
+    // Retrieve a file descriptor from the parcel.  This returns the raw fd
+    // in the parcel, which you do not own -- use dup() to get your own copy.
+    int                 readFileDescriptor() const;
+    
+    const flat_binder_object* readObject(bool nullMetaData) const;
+
+    // Explicitly close all file descriptors in the parcel.
+    void                closeFileDescriptors();
+    
+    typedef void        (*release_func)(Parcel* parcel,
+                                        const uint8_t* data, size_t dataSize,
+                                        const size_t* objects, size_t objectsSize,
+                                        void* cookie);
+                        
+    const uint8_t*      ipcData() const;
+    size_t              ipcDataSize() const;
+    const size_t*       ipcObjects() const;
+    size_t              ipcObjectsCount() const;
+    void                ipcSetDataReference(const uint8_t* data, size_t dataSize,
+                                            const size_t* objects, size_t objectsCount,
+                                            release_func relFunc, void* relCookie);
+    
+    void                print(TextOutput& to, uint32_t flags = 0) const;
+    
+private:
+                        Parcel(const Parcel& o);
+    Parcel&             operator=(const Parcel& o);
+    
+    status_t            finishWrite(size_t len);
+    void                releaseObjects();
+    void                acquireObjects();
+    status_t            growData(size_t len);
+    status_t            restartWrite(size_t desired);
+    status_t            continueWrite(size_t desired);
+    void                freeDataNoInit();
+    void                initState();
+    void                scanForFds() const;
+                        
+    status_t            mError;
+    uint8_t*            mData;
+    size_t              mDataSize;
+    size_t              mDataCapacity;
+    mutable size_t      mDataPos;
+    size_t*             mObjects;
+    size_t              mObjectsSize;
+    size_t              mObjectsCapacity;
+    mutable size_t      mNextObjectHint;
+
+    mutable bool        mFdsKnown;
+    mutable bool        mHasFds;
+    
+    release_func        mOwner;
+    void*               mOwnerCookie;
+};
+
+// ---------------------------------------------------------------------------
+
+inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
+{
+    parcel.print(to);
+    return to;
+}
+
+// ---------------------------------------------------------------------------
+
+// Generic acquire and release of objects.
+void acquire_object(const sp<ProcessState>& proc,
+                    const flat_binder_object& obj, const void* who);
+void release_object(const sp<ProcessState>& proc,
+                    const flat_binder_object& obj, const void* who);
+
+void flatten_binder(const sp<ProcessState>& proc,
+                    const sp<IBinder>& binder, flat_binder_object* out);
+void flatten_binder(const sp<ProcessState>& proc,
+                    const wp<IBinder>& binder, flat_binder_object* out);
+status_t unflatten_binder(const sp<ProcessState>& proc,
+                          const flat_binder_object& flat, sp<IBinder>* out);
+status_t unflatten_binder(const sp<ProcessState>& proc,
+                          const flat_binder_object& flat, wp<IBinder>* out);
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_PARCEL_H
diff --git a/include/utils/Pipe.h b/include/utils/Pipe.h
new file mode 100644
index 0000000..6404168
--- /dev/null
+++ b/include/utils/Pipe.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// FIFO I/O.
+//
+#ifndef _LIBS_UTILS_PIPE_H
+#define _LIBS_UTILS_PIPE_H
+
+#ifdef HAVE_ANDROID_OS
+#error DO NOT USE THIS FILE IN THE DEVICE BUILD
+#endif
+
+namespace android {
+
+/*
+ * Simple anonymous unidirectional pipe.
+ *
+ * The primary goal is to create an implementation with minimal overhead
+ * under Linux.  Making Windows, Mac OS X, and Linux all work the same way
+ * is a secondary goal.  Part of this goal is to have something that can
+ * be fed to a select() call, so that the application can sleep in the
+ * kernel until something interesting happens.
+ */
+class Pipe {
+public:
+    Pipe(void);
+    virtual ~Pipe(void);
+
+    /* Create the pipe */
+    bool create(void);
+
+    /* Create a read-only pipe, using the supplied handle as read handle */
+    bool createReader(unsigned long handle);
+    /* Create a write-only pipe, using the supplied handle as write handle */
+    bool createWriter(unsigned long handle);
+
+    /* Is this object ready to go? */
+    bool isCreated(void);
+
+    /*
+     * Read "count" bytes from the pipe.  Returns the amount of data read,
+     * or 0 if no data available and we're non-blocking.
+     * Returns -1 on error.
+     */
+    int read(void* buf, int count);
+
+    /*
+     * Write "count" bytes into the pipe.  Returns number of bytes written,
+     * or 0 if there's no room for more data and we're non-blocking.
+     * Returns -1 on error.
+     */
+    int write(const void* buf, int count);
+
+    /* Returns "true" if data is available to read */
+    bool readReady(void);
+
+    /* Enable or disable non-blocking I/O for reads */
+    bool setReadNonBlocking(bool val);
+    /* Enable or disable non-blocking I/O for writes.  Only works on Linux. */
+    bool setWriteNonBlocking(bool val);
+
+    /*
+     * Get the handle.  Only useful in some platform-specific situations.
+     */
+    unsigned long getReadHandle(void);
+    unsigned long getWriteHandle(void);
+
+    /*
+     * Modify inheritance, i.e. whether or not a child process will get
+     * copies of the descriptors.  Systems with fork+exec allow us to close
+     * the descriptors before launching the child process, but Win32
+     * doesn't allow it.
+     */
+    bool disallowReadInherit(void);
+    bool disallowWriteInherit(void);
+
+    /*
+     * Close one side or the other.  Useful in the parent after launching
+     * a child process.
+     */
+    bool closeRead(void);
+    bool closeWrite(void);
+
+private:
+    bool    mReadNonBlocking;
+    bool    mWriteNonBlocking;
+
+    unsigned long mReadHandle;
+    unsigned long mWriteHandle;
+};
+
+}; // android
+
+#endif // _LIBS_UTILS_PIPE_H
diff --git a/include/utils/ProcessState.h b/include/utils/ProcessState.h
new file mode 100644
index 0000000..39584f4
--- /dev/null
+++ b/include/utils/ProcessState.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_PROCESS_STATE_H
+#define ANDROID_PROCESS_STATE_H
+
+#include <utils/IBinder.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+// Global variables
+extern int                 mArgC;
+extern const char* const*  mArgV;
+extern int                 mArgLen;
+
+class IPCThreadState;
+
+class ProcessState : public virtual RefBase
+{
+public:
+    static  sp<ProcessState>    self();
+
+    static  void                setSingleProcess(bool singleProcess);
+
+            void                setContextObject(const sp<IBinder>& object);
+            sp<IBinder>         getContextObject(const sp<IBinder>& caller);
+        
+            void                setContextObject(const sp<IBinder>& object,
+                                                 const String16& name);
+            sp<IBinder>         getContextObject(const String16& name,
+                                                 const sp<IBinder>& caller);
+                                                 
+            bool                supportsProcesses() const;
+
+            void                startThreadPool();
+                        
+    typedef bool (*context_check_func)(const String16& name,
+                                       const sp<IBinder>& caller,
+                                       void* userData);
+        
+            bool                isContextManager(void) const;
+            bool                becomeContextManager(
+                                    context_check_func checkFunc,
+                                    void* userData);
+
+            sp<IBinder>         getStrongProxyForHandle(int32_t handle);
+            wp<IBinder>         getWeakProxyForHandle(int32_t handle);
+            void                expungeHandle(int32_t handle, IBinder* binder);
+
+            void                setArgs(int argc, const char* const argv[]);
+            int                 getArgC() const;
+            const char* const*  getArgV() const;
+
+            void                setArgV0(const char* txt);
+
+            void                spawnPooledThread(bool isMain);
+            
+private:
+    friend class IPCThreadState;
+    
+                                ProcessState();
+                                ~ProcessState();
+
+                                ProcessState(const ProcessState& o);
+            ProcessState&       operator=(const ProcessState& o);
+            
+            struct handle_entry {
+                IBinder* binder;
+                RefBase::weakref_type* refs;
+            };
+            
+            handle_entry*       lookupHandleLocked(int32_t handle);
+
+            int                 mDriverFD;
+            void*               mVMStart;
+            
+    mutable Mutex               mLock;  // protects everything below.
+            
+            Vector<handle_entry>mHandleToObject;
+
+            bool                mManagesContexts;
+            context_check_func  mBinderContextCheckFunc;
+            void*               mBinderContextUserData;
+            
+            KeyedVector<String16, sp<IBinder> >
+                                mContexts;
+
+
+            String8             mRootDir;
+            bool                mThreadPoolStarted;
+    volatile int32_t            mThreadPoolSeq;
+};
+    
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_PROCESS_STATE_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
new file mode 100644
index 0000000..cbda0fd
--- /dev/null
+++ b/include/utils/RefBase.h
@@ -0,0 +1,550 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_REF_BASE_H
+#define ANDROID_REF_BASE_H
+
+#include <cutils/atomic.h>
+#include <utils/TextOutput.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+template<typename T> class wp;
+
+// ---------------------------------------------------------------------------
+
+#define COMPARE(_op_)                                           \
+inline bool operator _op_ (const sp<T>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+inline bool operator _op_ (const wp<T>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+inline bool operator _op_ (const T* o) const {                  \
+    return m_ptr _op_ o;                                        \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const sp<U>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const wp<U>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const U* o) const {                  \
+    return m_ptr _op_ o;                                        \
+}
+
+// ---------------------------------------------------------------------------
+
+class RefBase
+{
+public:
+            void            incStrong(const void* id) const;
+            void            decStrong(const void* id) const;
+    
+            void            forceIncStrong(const void* id) const;
+
+            //! DEBUGGING ONLY: Get current strong ref count.
+            int32_t         getStrongCount() const;
+
+    class weakref_type
+    {
+    public:
+        RefBase*            refBase() const;
+        
+        void                incWeak(const void* id);
+        void                decWeak(const void* id);
+        
+        bool                attemptIncStrong(const void* id);
+        
+        //! This is only safe if you have set OBJECT_LIFETIME_FOREVER.
+        bool                attemptIncWeak(const void* id);
+
+        //! DEBUGGING ONLY: Get current weak ref count.
+        int32_t             getWeakCount() const;
+
+        //! DEBUGGING ONLY: Print references held on object.
+        void                printRefs() const;
+
+        //! DEBUGGING ONLY: Enable tracking for this object.
+        // enable -- enable/disable tracking
+        // retain -- when tracking is enable, if true, then we save a stack trace
+        //           for each reference and dereference; when retain == false, we
+        //           match up references and dereferences and keep only the 
+        //           outstanding ones.
+        
+        void                trackMe(bool enable, bool retain);
+    };
+    
+            weakref_type*   createWeak(const void* id) const;
+            
+            weakref_type*   getWeakRefs() const;
+
+            //! DEBUGGING ONLY: Print references held on object.
+    inline  void            printRefs() const { getWeakRefs()->printRefs(); }
+
+            //! DEBUGGING ONLY: Enable tracking of object.
+    inline  void            trackMe(bool enable, bool retain)
+    { 
+        getWeakRefs()->trackMe(enable, retain); 
+    }
+
+protected:
+                            RefBase();
+    virtual                 ~RefBase();
+    
+    //! Flags for extendObjectLifetime()
+    enum {
+        OBJECT_LIFETIME_WEAK    = 0x0001,
+        OBJECT_LIFETIME_FOREVER = 0x0003
+    };
+    
+            void            extendObjectLifetime(int32_t mode);
+            
+    //! Flags for onIncStrongAttempted()
+    enum {
+        FIRST_INC_STRONG = 0x0001
+    };
+    
+    virtual void            onFirstRef();
+    virtual void            onLastStrongRef(const void* id);
+    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
+    virtual void            onLastWeakRef(const void* id);
+
+private:
+    friend class weakref_type;
+    class weakref_impl;
+    
+                            RefBase(const RefBase& o);
+            RefBase&        operator=(const RefBase& o);
+            
+        weakref_impl* const mRefs;
+};
+
+// ---------------------------------------------------------------------------
+
+template <class T>
+class LightRefBase
+{
+public:
+    inline LightRefBase() : mCount(0) { }
+    inline void incStrong(const void* id) const {
+        android_atomic_inc(&mCount);
+    }
+    inline void decStrong(const void* id) const {
+        if (android_atomic_dec(&mCount) == 1) {
+            delete static_cast<const T*>(this);
+        }
+    }
+    
+protected:
+    inline ~LightRefBase() { }
+    
+private:
+    mutable volatile int32_t mCount;
+};
+
+// ---------------------------------------------------------------------------
+
+template <typename T>
+class sp
+{
+public:
+    typedef typename RefBase::weakref_type weakref_type;
+    
+    inline sp() : m_ptr(0) { }
+
+    sp(T* other);
+    sp(const sp<T>& other);
+    template<typename U> sp(U* other);
+    template<typename U> sp(const sp<U>& other);
+
+    ~sp();
+    
+    // Assignment
+
+    sp& operator = (T* other);
+    sp& operator = (const sp<T>& other);
+    
+    template<typename U> sp& operator = (const sp<U>& other);
+    template<typename U> sp& operator = (U* other);
+    
+    //! Special optimization for use by ProcessState (and nobody else).
+    void force_set(T* other);
+    
+    // Reset
+    
+    void clear();
+    
+    // Accessors
+
+    inline  T&      operator* () const  { return *m_ptr; }
+    inline  T*      operator-> () const { return m_ptr;  }
+    inline  T*      get() const         { return m_ptr; }
+
+    // Operators
+        
+    COMPARE(==)
+    COMPARE(!=)
+    COMPARE(>)
+    COMPARE(<)
+    COMPARE(<=)
+    COMPARE(>=)
+
+private:    
+    template<typename Y> friend class sp;
+    template<typename Y> friend class wp;
+
+    // Optimization for wp::promote().
+    sp(T* p, weakref_type* refs);
+    
+    T*              m_ptr;
+};
+
+template <typename T>
+TextOutput& operator<<(TextOutput& to, const sp<T>& val);
+
+// ---------------------------------------------------------------------------
+
+template <typename T>
+class wp
+{
+public:
+    typedef typename RefBase::weakref_type weakref_type;
+    
+    inline wp() : m_ptr(0) { }
+
+    wp(T* other);
+    wp(const wp<T>& other);
+    wp(const sp<T>& other);
+    template<typename U> wp(U* other);
+    template<typename U> wp(const sp<U>& other);
+    template<typename U> wp(const wp<U>& other);
+
+    ~wp();
+    
+    // Assignment
+
+    wp& operator = (T* other);
+    wp& operator = (const wp<T>& other);
+    wp& operator = (const sp<T>& other);
+    
+    template<typename U> wp& operator = (U* other);
+    template<typename U> wp& operator = (const wp<U>& other);
+    template<typename U> wp& operator = (const sp<U>& other);
+    
+    void set_object_and_refs(T* other, weakref_type* refs);
+
+    // promotion to sp
+    
+    sp<T> promote() const;
+
+    // Reset
+    
+    void clear();
+
+    // Accessors
+    
+    inline  weakref_type* get_refs() const { return m_refs; }
+    
+    inline  T* unsafe_get() const { return m_ptr; }
+
+    // Operators
+        
+    COMPARE(==)
+    COMPARE(!=)
+    COMPARE(>)
+    COMPARE(<)
+    COMPARE(<=)
+    COMPARE(>=)
+
+private:
+    template<typename Y> friend class sp;
+    template<typename Y> friend class wp;
+
+    T*              m_ptr;
+    weakref_type*   m_refs;
+};
+
+template <typename T>
+TextOutput& operator<<(TextOutput& to, const wp<T>& val);
+
+#undef COMPARE
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts below here.
+
+template<typename T>
+sp<T>::sp(T* other)
+    : m_ptr(other)
+{
+    if (other) other->incStrong(this);
+}
+
+template<typename T>
+sp<T>::sp(const sp<T>& other)
+    : m_ptr(other.m_ptr)
+{
+    if (m_ptr) m_ptr->incStrong(this);
+}
+
+template<typename T> template<typename U>
+sp<T>::sp(U* other) : m_ptr(other)
+{
+    if (other) other->incStrong(this);
+}
+
+template<typename T> template<typename U>
+sp<T>::sp(const sp<U>& other)
+    : m_ptr(other.m_ptr)
+{
+    if (m_ptr) m_ptr->incStrong(this);
+}
+
+template<typename T>
+sp<T>::~sp()
+{
+    if (m_ptr) m_ptr->decStrong(this);
+}
+
+template<typename T>
+sp<T>& sp<T>::operator = (const sp<T>& other) {
+    if (other.m_ptr) other.m_ptr->incStrong(this);
+    if (m_ptr) m_ptr->decStrong(this);
+    m_ptr = other.m_ptr;
+    return *this;
+}
+
+template<typename T>
+sp<T>& sp<T>::operator = (T* other)
+{
+    if (other) other->incStrong(this);
+    if (m_ptr) m_ptr->decStrong(this);
+    m_ptr = other;
+    return *this;
+}
+
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator = (const sp<U>& other)
+{
+    if (other.m_ptr) other.m_ptr->incStrong(this);
+    if (m_ptr) m_ptr->decStrong(this);
+    m_ptr = other.m_ptr;
+    return *this;
+}
+
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator = (U* other)
+{
+    if (other) other->incStrong(this);
+    if (m_ptr) m_ptr->decStrong(this);
+    m_ptr = other;
+    return *this;
+}
+
+template<typename T>    
+void sp<T>::force_set(T* other)
+{
+    other->forceIncStrong(this);
+    m_ptr = other;
+}
+
+template<typename T>
+void sp<T>::clear()
+{
+    if (m_ptr) {
+        m_ptr->decStrong(this);
+        m_ptr = 0;
+    }
+}
+
+template<typename T>
+sp<T>::sp(T* p, weakref_type* refs)
+    : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)
+{
+}
+
+template <typename T>
+inline TextOutput& operator<<(TextOutput& to, const sp<T>& val)
+{
+    to << "sp<>(" << val.get() << ")";
+    return to;
+}
+
+// ---------------------------------------------------------------------------
+
+template<typename T>
+wp<T>::wp(T* other)
+    : m_ptr(other)
+{
+    if (other) m_refs = other->createWeak(this);
+}
+
+template<typename T>
+wp<T>::wp(const wp<T>& other)
+    : m_ptr(other.m_ptr), m_refs(other.m_refs)
+{
+    if (m_ptr) m_refs->incWeak(this);
+}
+
+template<typename T>
+wp<T>::wp(const sp<T>& other)
+    : m_ptr(other.m_ptr)
+{
+    if (m_ptr) {
+        m_refs = m_ptr->createWeak(this);
+    }
+}
+
+template<typename T> template<typename U>
+wp<T>::wp(U* other)
+    : m_ptr(other)
+{
+    if (other) m_refs = other->createWeak(this);
+}
+
+template<typename T> template<typename U>
+wp<T>::wp(const wp<U>& other)
+    : m_ptr(other.m_ptr)
+{
+    if (m_ptr) {
+        m_refs = other.m_refs;
+        m_refs->incWeak(this);
+    }
+}
+
+template<typename T> template<typename U>
+wp<T>::wp(const sp<U>& other)
+    : m_ptr(other.m_ptr)
+{
+    if (m_ptr) {
+        m_refs = m_ptr->createWeak(this);
+    }
+}
+
+template<typename T>
+wp<T>::~wp()
+{
+    if (m_ptr) m_refs->decWeak(this);
+}
+
+template<typename T>
+wp<T>& wp<T>::operator = (T* other)
+{
+    weakref_type* newRefs =
+        other ? other->createWeak(this) : 0;
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = other;
+    m_refs = newRefs;
+    return *this;
+}
+
+template<typename T>
+wp<T>& wp<T>::operator = (const wp<T>& other)
+{
+    if (other.m_ptr) other.m_refs->incWeak(this);
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = other.m_ptr;
+    m_refs = other.m_refs;
+    return *this;
+}
+
+template<typename T>
+wp<T>& wp<T>::operator = (const sp<T>& other)
+{
+    weakref_type* newRefs =
+        other != NULL ? other->createWeak(this) : 0;
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = other.get();
+    m_refs = newRefs;
+    return *this;
+}
+
+template<typename T> template<typename U>
+wp<T>& wp<T>::operator = (U* other)
+{
+    weakref_type* newRefs =
+        other ? other->createWeak(this) : 0;
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = other;
+    m_refs = newRefs;
+    return *this;
+}
+
+template<typename T> template<typename U>
+wp<T>& wp<T>::operator = (const wp<U>& other)
+{
+    if (other.m_ptr) other.m_refs->incWeak(this);
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = other.m_ptr;
+    m_refs = other.m_refs;
+    return *this;
+}
+
+template<typename T> template<typename U>
+wp<T>& wp<T>::operator = (const sp<U>& other)
+{
+    weakref_type* newRefs =
+        other != NULL ? other->createWeak(this) : 0;
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = other.get();
+    m_refs = newRefs;
+    return *this;
+}
+
+template<typename T>
+void wp<T>::set_object_and_refs(T* other, weakref_type* refs)
+{
+    if (other) refs->incWeak(this);
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = other;
+    m_refs = refs;
+}
+
+template<typename T>
+sp<T> wp<T>::promote() const
+{
+    return sp<T>(m_ptr, m_refs);
+}
+
+template<typename T>
+void wp<T>::clear()
+{
+    if (m_ptr) {
+        m_refs->decWeak(this);
+        m_ptr = 0;
+    }
+}
+
+template <typename T>
+inline TextOutput& operator<<(TextOutput& to, const wp<T>& val)
+{
+    to << "wp<>(" << val.unsafe_get() << ")";
+    return to;
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_REF_BASE_H
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
new file mode 100644
index 0000000..7d3fcf2
--- /dev/null
+++ b/include/utils/ResourceTypes.h
@@ -0,0 +1,1720 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Definitions of resource data structures.
+//
+#ifndef _LIBS_UTILS_RESOURCE_TYPES_H
+#define _LIBS_UTILS_RESOURCE_TYPES_H
+
+#include <utils/Asset.h>
+#include <utils/ByteOrder.h>
+#include <utils/Errors.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+#include <utils/threads.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+
+/** ********************************************************************
+ *  PNG Extensions
+ *
+ *  New private chunks that may be placed in PNG images.
+ *
+ *********************************************************************** */
+
+/**
+ * This chunk specifies how to split an image into segments for
+ * scaling.
+ *
+ * There are J horizontal and K vertical segments.  These segments divide
+ * the image into J*K regions as follows (where J=4 and K=3):
+ *
+ *      F0   S0    F1     S1
+ *   +-----+----+------+-------+
+ * S2|  0  |  1 |  2   |   3   |
+ *   +-----+----+------+-------+
+ *   |     |    |      |       |
+ *   |     |    |      |       |
+ * F2|  4  |  5 |  6   |   7   |
+ *   |     |    |      |       |
+ *   |     |    |      |       |
+ *   +-----+----+------+-------+
+ * S3|  8  |  9 |  10  |   11  |
+ *   +-----+----+------+-------+
+ *
+ * Each horizontal and vertical segment is considered to by either
+ * stretchable (marked by the Sx labels) or fixed (marked by the Fy
+ * labels), in the horizontal or vertical axis, respectively. In the
+ * above example, the first is horizontal segment (F0) is fixed, the
+ * next is stretchable and then they continue to alternate. Note that
+ * the segment list for each axis can begin or end with a stretchable
+ * or fixed segment.
+ *
+ * The relative sizes of the stretchy segments indicates the relative
+ * amount of stretchiness of the regions bordered by the segments.  For
+ * example, regions 3, 7 and 11 above will take up more horizontal space
+ * than regions 1, 5 and 9 since the horizonal segment associated with
+ * the first set of regions is larger than the other set of regions.  The
+ * ratios of the amount of horizontal (or vertical) space taken by any
+ * two stretchable slices is exactly the ratio of their corresponding
+ * segment lengths.
+ *
+ * xDivs and yDivs point to arrays of horizontal and vertical pixel
+ * indices.  The first pair of Divs (in either array) indicate the
+ * starting and ending points of the first stretchable segment in that
+ * axis. The next pair specifies the next stretchable segment, etc. So
+ * in the above example xDiv[0] and xDiv[1] specify the horizontal
+ * coordinates for the regions labeled 1, 5 and 9.  xDiv[2] and
+ * xDiv[3] specify the coordinates for regions 3, 7 and 11. Note that
+ * the leftmost slices always start at x=0 and the rightmost slices
+ * always end at the end of the image. So, for example, the regions 0,
+ * 4 and 8 (which are fixed along the X axis) start at x value 0 and
+ * go to xDiv[0] amd slices 2, 6 and 10 start at xDiv[1] and end at
+ * xDiv[2].
+ *
+ * The array pointed to by the colors field lists contains hints for
+ * each of the regions.  They are ordered according left-to-right and
+ * top-to-bottom as indicated above. For each segment that is a solid
+ * color the array entry will contain that color value; otherwise it
+ * will contain NO_COLOR.  Segments that are completely transparent
+ * will always have the value TRANSPARENT_COLOR.
+ *
+ * The PNG chunk type is "npTc".
+ */
+struct Res_png_9patch
+{
+    Res_png_9patch() : wasDeserialized(false), xDivs(NULL),
+                       yDivs(NULL), colors(NULL) { }
+
+    int8_t wasDeserialized;
+    int8_t numXDivs;
+    int8_t numYDivs;
+    int8_t numColors;
+
+    // These tell where the next section of a patch starts.
+    // For example, the first patch includes the pixels from
+    // 0 to xDivs[0]-1 and the second patch includes the pixels
+    // from xDivs[0] to xDivs[1]-1.
+    // Note: allocation/free of these pointers is left to the caller.
+    int32_t* xDivs;
+    int32_t* yDivs;
+
+    int32_t paddingLeft, paddingRight;
+    int32_t paddingTop, paddingBottom;
+
+    enum {
+        // The 9 patch segment is not a solid color.
+        NO_COLOR = 0x00000001,
+
+        // The 9 patch segment is completely transparent.
+        TRANSPARENT_COLOR = 0x00000000
+    };
+    // Note: allocation/free of this pointer is left to the caller.
+    uint32_t* colors;
+
+    // Convert data from device representation to PNG file representation.
+    void deviceToFile();
+    // Convert data from PNG file representation to device representation.
+    void fileToDevice();
+    // Serialize/Marshall the patch data into a newly malloc-ed block
+    void* serialize();
+    // Serialize/Marshall the patch data
+    void serialize(void* outData);
+    // Deserialize/Unmarshall the patch data
+    static Res_png_9patch* deserialize(const void* data);
+    // Compute the size of the serialized data structure
+    size_t serializedSize();
+};
+
+/** ********************************************************************
+ *  Base Types
+ *
+ *  These are standard types that are shared between multiple specific
+ *  resource types.
+ *
+ *********************************************************************** */
+
+/**
+ * Header that appears at the front of every data chunk in a resource.
+ */
+struct ResChunk_header
+{
+    // Type identifier for this chunk.  The meaning of this value depends
+    // on the containing chunk.
+    uint16_t type;
+
+    // Size of the chunk header (in bytes).  Adding this value to
+    // the address of the chunk allows you to find its associated data
+    // (if any).
+    uint16_t headerSize;
+
+    // Total size of this chunk (in bytes).  This is the chunkSize plus
+    // the size of any data associated with the chunk.  Adding this value
+    // to the chunk allows you to completely skip its contents (including
+    // any child chunks).  If this value is the same as chunkSize, there is
+    // no data associated with the chunk.
+    uint32_t size;
+};
+
+enum {
+    RES_NULL_TYPE               = 0x0000,
+    RES_STRING_POOL_TYPE        = 0x0001,
+    RES_TABLE_TYPE              = 0x0002,
+    RES_XML_TYPE                = 0x0003,
+
+    // Chunk types in RES_XML_TYPE
+    RES_XML_FIRST_CHUNK_TYPE    = 0x0100,
+    RES_XML_START_NAMESPACE_TYPE= 0x0100,
+    RES_XML_END_NAMESPACE_TYPE  = 0x0101,
+    RES_XML_START_ELEMENT_TYPE  = 0x0102,
+    RES_XML_END_ELEMENT_TYPE    = 0x0103,
+    RES_XML_CDATA_TYPE          = 0x0104,
+    RES_XML_LAST_CHUNK_TYPE     = 0x017f,
+    // This contains a uint32_t array mapping strings in the string
+    // pool back to resource identifiers.  It is optional.
+    RES_XML_RESOURCE_MAP_TYPE   = 0x0180,
+
+    // Chunk types in RES_TABLE_TYPE
+    RES_TABLE_PACKAGE_TYPE      = 0x0200,
+    RES_TABLE_TYPE_TYPE         = 0x0201,
+    RES_TABLE_TYPE_SPEC_TYPE    = 0x0202
+};
+
+/**
+ * Macros for building/splitting resource identifiers.
+ */
+#define Res_VALIDID(resid) (resid != 0)
+#define Res_CHECKID(resid) ((resid&0xFFFF0000) != 0)
+#define Res_MAKEID(package, type, entry) \
+    (((package+1)<<24) | (((type+1)&0xFF)<<16) | (entry&0xFFFF))
+#define Res_GETPACKAGE(id) ((id>>24)-1)
+#define Res_GETTYPE(id) (((id>>16)&0xFF)-1)
+#define Res_GETENTRY(id) (id&0xFFFF)
+
+#define Res_INTERNALID(resid) ((resid&0xFFFF0000) != 0 && (resid&0xFF0000) == 0)
+#define Res_MAKEINTERNAL(entry) (0x01000000 | (entry&0xFFFF))
+#define Res_MAKEARRAY(entry) (0x02000000 | (entry&0xFFFF))
+
+#define Res_MAXPACKAGE 255
+
+/**
+ * Representation of a value in a resource, supplying type
+ * information.
+ */
+struct Res_value
+{
+    // Number of bytes in this structure.
+    uint16_t size;
+
+    // Always set to 0.
+    uint8_t res0;
+        
+    // Type of the data value.
+    enum {
+        // Contains no data.
+        TYPE_NULL = 0x00,
+        // The 'data' holds a ResTable_ref, a reference to another resource
+        // table entry.
+        TYPE_REFERENCE = 0x01,
+        // The 'data' holds an attribute resource identifier.
+        TYPE_ATTRIBUTE = 0x02,
+        // The 'data' holds an index into the containing resource table's
+        // global value string pool.
+        TYPE_STRING = 0x03,
+        // The 'data' holds a single-precision floating point number.
+        TYPE_FLOAT = 0x04,
+        // The 'data' holds a complex number encoding a dimension value,
+        // such as "100in".
+        TYPE_DIMENSION = 0x05,
+        // The 'data' holds a complex number encoding a fraction of a
+        // container.
+        TYPE_FRACTION = 0x06,
+
+        // Beginning of integer flavors...
+        TYPE_FIRST_INT = 0x10,
+
+        // The 'data' is a raw integer value of the form n..n.
+        TYPE_INT_DEC = 0x10,
+        // The 'data' is a raw integer value of the form 0xn..n.
+        TYPE_INT_HEX = 0x11,
+        // The 'data' is either 0 or 1, for input "false" or "true" respectively.
+        TYPE_INT_BOOLEAN = 0x12,
+
+        // Beginning of color integer flavors...
+        TYPE_FIRST_COLOR_INT = 0x1c,
+
+        // The 'data' is a raw integer value of the form #aarrggbb.
+        TYPE_INT_COLOR_ARGB8 = 0x1c,
+        // The 'data' is a raw integer value of the form #rrggbb.
+        TYPE_INT_COLOR_RGB8 = 0x1d,
+        // The 'data' is a raw integer value of the form #argb.
+        TYPE_INT_COLOR_ARGB4 = 0x1e,
+        // The 'data' is a raw integer value of the form #rgb.
+        TYPE_INT_COLOR_RGB4 = 0x1f,
+
+        // ...end of integer flavors.
+        TYPE_LAST_COLOR_INT = 0x1f,
+
+        // ...end of integer flavors.
+        TYPE_LAST_INT = 0x1f
+    };
+    uint8_t dataType;
+
+    // Structure of complex data values (TYPE_UNIT and TYPE_FRACTION)
+    enum {
+        // Where the unit type information is.  This gives us 16 possible
+        // types, as defined below.
+        COMPLEX_UNIT_SHIFT = 0,
+        COMPLEX_UNIT_MASK = 0xf,
+
+        // TYPE_DIMENSION: Value is raw pixels.
+        COMPLEX_UNIT_PX = 0,
+        // TYPE_DIMENSION: Value is Device Independent Pixels.
+        COMPLEX_UNIT_DIP = 1,
+        // TYPE_DIMENSION: Value is a Scaled device independent Pixels.
+        COMPLEX_UNIT_SP = 2,
+        // TYPE_DIMENSION: Value is in points.
+        COMPLEX_UNIT_PT = 3,
+        // TYPE_DIMENSION: Value is in inches.
+        COMPLEX_UNIT_IN = 4,
+        // TYPE_DIMENSION: Value is in millimeters.
+        COMPLEX_UNIT_MM = 5,
+
+        // TYPE_FRACTION: A basic fraction of the overall size.
+        COMPLEX_UNIT_FRACTION = 0,
+        // TYPE_FRACTION: A fraction of the parent size.
+        COMPLEX_UNIT_FRACTION_PARENT = 1,
+
+        // Where the radix information is, telling where the decimal place
+        // appears in the mantissa.  This give us 4 possible fixed point
+        // representations as defined below.
+        COMPLEX_RADIX_SHIFT = 4,
+        COMPLEX_RADIX_MASK = 0x3,
+
+        // The mantissa is an integral number -- i.e., 0xnnnnnn.0
+        COMPLEX_RADIX_23p0 = 0,
+        // The mantissa magnitude is 16 bits -- i.e, 0xnnnn.nn
+        COMPLEX_RADIX_16p7 = 1,
+        // The mantissa magnitude is 8 bits -- i.e, 0xnn.nnnn
+        COMPLEX_RADIX_8p15 = 2,
+        // The mantissa magnitude is 0 bits -- i.e, 0x0.nnnnnn
+        COMPLEX_RADIX_0p23 = 3,
+
+        // Where the actual value is.  This gives us 23 bits of
+        // precision.  The top bit is the sign.
+        COMPLEX_MANTISSA_SHIFT = 8,
+        COMPLEX_MANTISSA_MASK = 0xffffff
+    };
+
+    // The data for this item, as interpreted according to dataType.
+    uint32_t data;
+
+    void copyFrom_dtoh(const Res_value& src);
+};
+
+/**
+ *  This is a reference to a unique entry (a ResTable_entry structure)
+ *  in a resource table.  The value is structured as: 0xpptteeee,
+ *  where pp is the package index, tt is the type index in that
+ *  package, and eeee is the entry index in that type.  The package
+ *  and type values start at 1 for the first item, to help catch cases
+ *  where they have not been supplied.
+ */
+struct ResTable_ref
+{
+    uint32_t ident;
+};
+
+/**
+ * Reference to a string in a string pool.
+ */
+struct ResStringPool_ref
+{
+    // Index into the string pool table (uint32_t-offset from the indices
+    // immediately after ResStringPool_header) at which to find the location
+    // of the string data in the pool.
+    uint32_t index;
+};
+
+/** ********************************************************************
+ *  String Pool
+ *
+ *  A set of strings that can be references by others through a
+ *  ResStringPool_ref.
+ *
+ *********************************************************************** */
+
+/**
+ * Definition for a pool of strings.  The data of this chunk is an
+ * array of uint32_t providing indices into the pool, relative to
+ * stringsStart.  At stringsStart are all of the UTF-16 strings
+ * concatenated together; each starts with a uint16_t of the string's
+ * length and each ends with a 0x0000 terminator.  If a string is >
+ * 32767 characters, the high bit of the length is set meaning to take
+ * those 15 bits as a high word and it will be followed by another
+ * uint16_t containing the low word.
+ *
+ * If styleCount is not zero, then immediately following the array of
+ * uint32_t indices into the string table is another array of indices
+ * into a style table starting at stylesStart.  Each entry in the
+ * style table is an array of ResStringPool_span structures.
+ */
+struct ResStringPool_header
+{
+    struct ResChunk_header header;
+
+    // Number of strings in this pool (number of uint32_t indices that follow
+    // in the data).
+    uint32_t stringCount;
+
+    // Number of style span arrays in the pool (number of uint32_t indices
+    // follow the string indices).
+    uint32_t styleCount;
+
+    // Flags.
+    enum {
+        // If set, the string index is sorted by the string values (based
+        // on strcmp16()).
+        SORTED_FLAG = 1<<0
+    };
+    uint32_t flags;
+
+    // Index from header of the string data.
+    uint32_t stringsStart;
+
+    // Index from header of the style data.
+    uint32_t stylesStart;
+};
+
+/**
+ * This structure defines a span of style information associated with
+ * a string in the pool.
+ */
+struct ResStringPool_span
+{
+    enum {
+        END = 0xFFFFFFFF
+    };
+
+    // This is the name of the span -- that is, the name of the XML
+    // tag that defined it.  The special value END (0xFFFFFFFF) indicates
+    // the end of an array of spans.
+    ResStringPool_ref name;
+
+    // The range of characters in the string that this span applies to.
+    uint32_t firstChar, lastChar;
+};
+
+/**
+ * Convenience class for accessing data in a ResStringPool resource.
+ */
+class ResStringPool
+{
+public:
+    ResStringPool();
+    ResStringPool(const void* data, size_t size, bool copyData=false);
+    ~ResStringPool();
+
+    status_t setTo(const void* data, size_t size, bool copyData=false);
+
+    status_t getError() const;
+
+    void uninit();
+
+    inline const char16_t* stringAt(const ResStringPool_ref& ref, size_t* outLen) const {
+        return stringAt(ref.index, outLen);
+    }
+    const char16_t* stringAt(size_t idx, size_t* outLen) const;
+
+    const ResStringPool_span* styleAt(const ResStringPool_ref& ref) const;
+    const ResStringPool_span* styleAt(size_t idx) const;
+
+    ssize_t indexOfString(const char16_t* str, size_t strLen) const;
+
+    size_t size() const;
+
+private:
+    status_t                    mError;
+    void*                       mOwnedData;
+    const ResStringPool_header* mHeader;
+    size_t                      mSize;
+    const uint32_t*             mEntries;
+    const uint32_t*             mEntryStyles;
+    const char16_t*             mStrings;
+    uint32_t                    mStringPoolSize;    // number of uint16_t
+    const uint32_t*             mStyles;
+    uint32_t                    mStylePoolSize;    // number of uint32_t
+};
+
+/** ********************************************************************
+ *  XML Tree
+ *
+ *  Binary representation of an XML document.  This is designed to
+ *  express everything in an XML document, in a form that is much
+ *  easier to parse on the device.
+ *
+ *********************************************************************** */
+
+/**
+ * XML tree header.  This appears at the front of an XML tree,
+ * describing its content.  It is followed by a flat array of
+ * ResXMLTree_node structures; the hierarchy of the XML document
+ * is described by the occurrance of RES_XML_START_ELEMENT_TYPE
+ * and corresponding RES_XML_END_ELEMENT_TYPE nodes in the array.
+ */
+struct ResXMLTree_header
+{
+    struct ResChunk_header header;
+};
+
+/**
+ * Basic XML tree node.  A single item in the XML document.  Extended info
+ * about the node can be found after header.headerSize.
+ */
+struct ResXMLTree_node
+{
+    struct ResChunk_header header;
+
+    // Line number in original source file at which this element appeared.
+    uint32_t lineNumber;
+
+    // Optional XML comment that was associated with this element; -1 if none.
+    struct ResStringPool_ref comment;
+};
+
+/**
+ * Extended XML tree node for CDATA tags -- includes the CDATA string.
+ * Appears header.headerSize bytes after a ResXMLTree_node.
+ */
+struct ResXMLTree_cdataExt
+{
+    // The raw CDATA character data.
+    struct ResStringPool_ref data;
+    
+    // The typed value of the character data if this is a CDATA node.
+    struct Res_value typedData;
+};
+
+/**
+ * Extended XML tree node for namespace start/end nodes.
+ * Appears header.headerSize bytes after a ResXMLTree_node.
+ */
+struct ResXMLTree_namespaceExt
+{
+    // The prefix of the namespace.
+    struct ResStringPool_ref prefix;
+    
+    // The URI of the namespace.
+    struct ResStringPool_ref uri;
+};
+
+/**
+ * Extended XML tree node for element start/end nodes.
+ * Appears header.headerSize bytes after a ResXMLTree_node.
+ */
+struct ResXMLTree_endElementExt
+{
+    // String of the full namespace of this element.
+    struct ResStringPool_ref ns;
+    
+    // String name of this node if it is an ELEMENT; the raw
+    // character data if this is a CDATA node.
+    struct ResStringPool_ref name;
+};
+
+/**
+ * Extended XML tree node for start tags -- includes attribute
+ * information.
+ * Appears header.headerSize bytes after a ResXMLTree_node.
+ */
+struct ResXMLTree_attrExt
+{
+    // String of the full namespace of this element.
+    struct ResStringPool_ref ns;
+    
+    // String name of this node if it is an ELEMENT; the raw
+    // character data if this is a CDATA node.
+    struct ResStringPool_ref name;
+    
+    // Byte offset from the start of this structure where the attributes start.
+    uint16_t attributeStart;
+    
+    // Size of the ResXMLTree_attribute structures that follow.
+    uint16_t attributeSize;
+    
+    // Number of attributes associated with an ELEMENT.  These are
+    // available as an array of ResXMLTree_attribute structures
+    // immediately following this node.
+    uint16_t attributeCount;
+    
+    // Index (1-based) of the "id" attribute. 0 if none.
+    uint16_t idIndex;
+    
+    // Index (1-based) of the "class" attribute. 0 if none.
+    uint16_t classIndex;
+    
+    // Index (1-based) of the "style" attribute. 0 if none.
+    uint16_t styleIndex;
+};
+
+struct ResXMLTree_attribute
+{
+    // Namespace of this attribute.
+    struct ResStringPool_ref ns;
+    
+    // Name of this attribute.
+    struct ResStringPool_ref name;
+
+    // The original raw string value of this attribute.
+    struct ResStringPool_ref rawValue;
+    
+    // Processesd typed value of this attribute.
+    struct Res_value typedValue;
+};
+
+class ResXMLTree;
+
+class ResXMLParser
+{
+public:
+    ResXMLParser(const ResXMLTree& tree);
+
+    enum event_code_t {
+        BAD_DOCUMENT = -1,
+        START_DOCUMENT = 0,
+        END_DOCUMENT = 1,
+        
+        FIRST_CHUNK_CODE = RES_XML_FIRST_CHUNK_TYPE, 
+        
+        START_NAMESPACE = RES_XML_START_NAMESPACE_TYPE,
+        END_NAMESPACE = RES_XML_END_NAMESPACE_TYPE,
+        START_TAG = RES_XML_START_ELEMENT_TYPE,
+        END_TAG = RES_XML_END_ELEMENT_TYPE,
+        TEXT = RES_XML_CDATA_TYPE
+    };
+
+    struct ResXMLPosition
+    {
+        event_code_t                eventCode;
+        const ResXMLTree_node*      curNode;
+        const void*                 curExt;
+    };
+
+    void restart();
+
+    event_code_t getEventType() const;
+    // Note, unlike XmlPullParser, the first call to next() will return
+    // START_TAG of the first element.
+    event_code_t next();
+
+    // These are available for all nodes:
+    const int32_t getCommentID() const;
+    const uint16_t* getComment(size_t* outLen) const;
+    const uint32_t getLineNumber() const;
+    
+    // This is available for TEXT:
+    const int32_t getTextID() const;
+    const uint16_t* getText(size_t* outLen) const;
+    ssize_t getTextValue(Res_value* outValue) const;
+    
+    // These are available for START_NAMESPACE and END_NAMESPACE:
+    const int32_t getNamespacePrefixID() const;
+    const uint16_t* getNamespacePrefix(size_t* outLen) const;
+    const int32_t getNamespaceUriID() const;
+    const uint16_t* getNamespaceUri(size_t* outLen) const;
+    
+    // These are available for START_TAG and END_TAG:
+    const int32_t getElementNamespaceID() const;
+    const uint16_t* getElementNamespace(size_t* outLen) const;
+    const int32_t getElementNameID() const;
+    const uint16_t* getElementName(size_t* outLen) const;
+    
+    // Remaining methods are for retrieving information about attributes
+    // associated with a START_TAG:
+    
+    size_t getAttributeCount() const;
+    
+    // Returns -1 if no namespace, -2 if idx out of range.
+    const int32_t getAttributeNamespaceID(size_t idx) const;
+    const uint16_t* getAttributeNamespace(size_t idx, size_t* outLen) const;
+    
+    const int32_t getAttributeNameID(size_t idx) const;
+    const uint16_t* getAttributeName(size_t idx, size_t* outLen) const;
+    const uint32_t getAttributeNameResID(size_t idx) const;
+    
+    const int32_t getAttributeValueStringID(size_t idx) const;
+    const uint16_t* getAttributeStringValue(size_t idx, size_t* outLen) const;
+    
+    int32_t getAttributeDataType(size_t idx) const;
+    int32_t getAttributeData(size_t idx) const;
+    ssize_t getAttributeValue(size_t idx, Res_value* outValue) const;
+
+    ssize_t indexOfAttribute(const char* ns, const char* attr) const;
+    ssize_t indexOfAttribute(const char16_t* ns, size_t nsLen,
+                             const char16_t* attr, size_t attrLen) const;
+
+    ssize_t indexOfID() const;
+    ssize_t indexOfClass() const;
+    ssize_t indexOfStyle() const;
+
+    void getPosition(ResXMLPosition* pos) const;
+    void setPosition(const ResXMLPosition& pos);
+
+private:
+    friend class ResXMLTree;
+    
+    event_code_t nextNode();
+
+    const ResXMLTree&           mTree;
+    event_code_t                mEventCode;
+    const ResXMLTree_node*      mCurNode;
+    const void*                 mCurExt;
+};
+
+/**
+ * Convenience class for accessing data in a ResXMLTree resource.
+ */
+class ResXMLTree : public ResXMLParser
+{
+public:
+    ResXMLTree();
+    ResXMLTree(const void* data, size_t size, bool copyData=false);
+    ~ResXMLTree();
+
+    status_t setTo(const void* data, size_t size, bool copyData=false);
+
+    status_t getError() const;
+
+    void uninit();
+
+    const ResStringPool& getStrings() const;
+
+private:
+    friend class ResXMLParser;
+
+    status_t validateNode(const ResXMLTree_node* node) const;
+
+    status_t                    mError;
+    void*                       mOwnedData;
+    const ResXMLTree_header*    mHeader;
+    size_t                      mSize;
+    const uint8_t*              mDataEnd;
+    ResStringPool               mStrings;
+    const uint32_t*             mResIds;
+    size_t                      mNumResIds;
+    const ResXMLTree_node*      mRootNode;
+    const void*                 mRootExt;
+    event_code_t                mRootCode;
+};
+
+/** ********************************************************************
+ *  RESOURCE TABLE
+ *
+ *********************************************************************** */
+
+/**
+ * Header for a resource table.  Its data contains a series of
+ * additional chunks:
+ *   * A ResStringPool_header containing all table values.
+ *   * One or more ResTable_package chunks.
+ *
+ * Specific entries within a resource table can be uniquely identified
+ * with a single integer as defined by the ResTable_ref structure.
+ */
+struct ResTable_header
+{
+    struct ResChunk_header header;
+
+    // The number of ResTable_package structures.
+    uint32_t packageCount;
+};
+
+/**
+ * A collection of resource data types within a package.  Followed by
+ * one or more ResTable_type and ResTable_typeSpec structures containing the
+ * entry values for each resource type.
+ */
+struct ResTable_package
+{
+    struct ResChunk_header header;
+
+    // If this is a base package, its ID.  Package IDs start
+    // at 1 (corresponding to the value of the package bits in a
+    // resource identifier).  0 means this is not a base package.
+    uint32_t id;
+
+    // Actual name of this package, \0-terminated.
+    char16_t name[128];
+
+    // Offset to a ResStringPool_header defining the resource
+    // type symbol table.  If zero, this package is inheriting from
+    // another base package (overriding specific values in it).
+    uint32_t typeStrings;
+
+    // Last index into typeStrings that is for public use by others.
+    uint32_t lastPublicType;
+
+    // Offset to a ResStringPool_header defining the resource
+    // key symbol table.  If zero, this package is inheriting from
+    // another base package (overriding specific values in it).
+    uint32_t keyStrings;
+
+    // Last index into keyStrings that is for public use by others.
+    uint32_t lastPublicKey;
+};
+
+/**
+ * Describes a particular resource configuration.
+ */
+struct ResTable_config
+{
+    // Number of bytes in this structure.
+    uint32_t size;
+    
+    union {
+        struct {
+            // Mobile country code (from SIM).  0 means "any".
+            uint16_t mcc;
+            // Mobile network code (from SIM).  0 means "any".
+            uint16_t mnc;
+        };
+        uint32_t imsi;
+    };
+    
+    union {
+        struct {
+            // \0\0 means "any".  Otherwise, en, fr, etc.
+            char language[2];
+            
+            // \0\0 means "any".  Otherwise, US, CA, etc.
+            char country[2];
+        };
+        uint32_t locale;
+    };
+    
+    enum {
+        ORIENTATION_ANY  = 0x0000,
+        ORIENTATION_PORT = 0x0001,
+        ORIENTATION_LAND = 0x0002,
+        ORIENTATION_SQUARE = 0x0002,
+    };
+    
+    enum {
+        TOUCHSCREEN_ANY  = 0x0000,
+        TOUCHSCREEN_NOTOUCH  = 0x0001,
+        TOUCHSCREEN_STYLUS  = 0x0002,
+        TOUCHSCREEN_FINGER  = 0x0003,
+    };
+    
+    enum {
+        DENSITY_ANY = 0
+    };
+    
+    union {
+        struct {
+            uint8_t orientation;
+            uint8_t touchscreen;
+            uint16_t density;
+        };
+        uint32_t screenType;
+    };
+    
+    enum {
+        KEYBOARD_ANY  = 0x0000,
+        KEYBOARD_NOKEYS  = 0x0001,
+        KEYBOARD_QWERTY  = 0x0002,
+        KEYBOARD_12KEY  = 0x0003,
+    };
+    
+    enum {
+        NAVIGATION_ANY  = 0x0000,
+        NAVIGATION_NONAV  = 0x0001,
+        NAVIGATION_DPAD  = 0x0002,
+        NAVIGATION_TRACKBALL  = 0x0003,
+        NAVIGATION_WHEEL  = 0x0004,
+    };
+    
+    enum {
+        MASK_KEYSHIDDEN = 0x0003,
+        SHIFT_KEYSHIDDEN = 0,
+        KEYSHIDDEN_ANY = 0x0000,
+        KEYSHIDDEN_NO = 0x0001,
+        KEYSHIDDEN_YES = 0x0002,
+        KEYSHIDDEN_SOFT = 0x0003,
+    };
+    
+    union {
+        struct {
+            uint8_t keyboard;
+            uint8_t navigation;
+            uint8_t inputFlags;
+            uint8_t pad0;
+        };
+        uint32_t input;
+    };
+    
+    enum {
+        SCREENWIDTH_ANY = 0
+    };
+    
+    enum {
+        SCREENHEIGHT_ANY = 0
+    };
+    
+    union {
+        struct {
+            uint16_t screenWidth;
+            uint16_t screenHeight;
+        };
+        uint32_t screenSize;
+    };
+    
+    enum {
+        SDKVERSION_ANY = 0
+    };
+    
+    enum {
+        MINORVERSION_ANY = 0
+    };
+    
+    union {
+        struct {
+            uint16_t sdkVersion;
+            // For now minorVersion must always be 0!!!  Its meaning
+            // is currently undefined.
+            uint16_t minorVersion;
+        };
+        uint32_t version;
+    };
+    
+    inline void copyFromDeviceNoSwap(const ResTable_config& o) {
+        const size_t size = dtohl(o.size);
+        if (size >= sizeof(ResTable_config)) {
+            *this = o;
+        } else {
+            memcpy(this, &o, size);
+            memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size);
+        }
+    }
+    
+    inline void copyFromDtoH(const ResTable_config& o) {
+        copyFromDeviceNoSwap(o);
+        size = sizeof(ResTable_config);
+        mcc = dtohs(mcc);
+        mnc = dtohs(mnc);
+        density = dtohs(density);
+        screenWidth = dtohs(screenWidth);
+        screenHeight = dtohs(screenHeight);
+        sdkVersion = dtohs(sdkVersion);
+        minorVersion = dtohs(minorVersion);
+    }
+    
+    inline void swapHtoD() {
+        size = htodl(size);
+        mcc = htods(mcc);
+        mnc = htods(mnc);
+        density = htods(density);
+        screenWidth = htods(screenWidth);
+        screenHeight = htods(screenHeight);
+        sdkVersion = htods(sdkVersion);
+        minorVersion = htods(minorVersion);
+    }
+    
+    inline int compare(const ResTable_config& o) const {
+        int32_t diff = (int32_t)(imsi - o.imsi);
+        if (diff != 0) return diff;
+        diff = (int32_t)(locale - o.locale);
+        if (diff != 0) return diff;
+        diff = (int32_t)(screenType - o.screenType);
+        if (diff != 0) return diff;
+        diff = (int32_t)(input - o.input);
+        if (diff != 0) return diff;
+        diff = (int32_t)(screenSize - o.screenSize);
+        if (diff != 0) return diff;
+        diff = (int32_t)(version - o.version);
+        return (int)diff;
+    }
+    
+    // Flags indicating a set of config values.  These flag constants must
+    // match the corresponding ones in android.content.pm.ActivityInfo and
+    // attrs_manifest.xml.
+    enum {
+        CONFIG_MCC = 0x0001,
+        CONFIG_MNC = 0x0002,
+        CONFIG_LOCALE = 0x0004,
+        CONFIG_TOUCHSCREEN = 0x0008,
+        CONFIG_KEYBOARD = 0x0010,
+        CONFIG_KEYBOARD_HIDDEN = 0x0020,
+        CONFIG_NAVIGATION = 0x0040,
+        CONFIG_ORIENTATION = 0x0080,
+        CONFIG_DENSITY = 0x0100,
+        CONFIG_SCREEN_SIZE = 0x0200,
+        CONFIG_VERSION = 0x0400
+    };
+    
+    // Compare two configuration, returning CONFIG_* flags set for each value
+    // that is different.
+    inline int diff(const ResTable_config& o) const {
+        int diffs = 0;
+        if (mcc != o.mcc) diffs |= CONFIG_MCC;
+        if (mnc != o.mnc) diffs |= CONFIG_MNC;
+        if (locale != o.locale) diffs |= CONFIG_LOCALE;
+        if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
+        if (density != o.density) diffs |= CONFIG_DENSITY;
+        if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
+        if (((inputFlags^o.inputFlags)&MASK_KEYSHIDDEN) != 0) diffs |= CONFIG_KEYBOARD_HIDDEN;
+        if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD;
+        if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
+        if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
+        if (version != o.version) diffs |= CONFIG_VERSION;
+        return diffs;
+    }
+    
+    // Return true if 'this' is more specific than 'o'.  Optionally, if
+    // 'requested' is null, then they will also be compared against the
+    // requested configuration and true will only be returned if 'this'
+    // is a better candidate than 'o' for the configuration.  This assumes that
+    // match() has already been used to remove any configurations that don't
+    // match the requested configuration at all; if they are not first filtered,
+    // non-matching results can be considered better than matching ones.
+    inline bool
+    isBetterThan(const ResTable_config& o, const ResTable_config* requested = NULL) const {
+        // The order of the following tests defines the importance of one
+        // configuration parameter over another.  Those tests first are more
+        // important, trumping any values in those following them.
+        if (imsi != 0 && (!requested || requested->imsi != 0)) {
+            if (mcc != 0 && (!requested || requested->mcc != 0)) {
+                if (o.mcc == 0) {
+                    return true;
+                }
+            }
+            if (mnc != 0 && (!requested || requested->mnc != 0)) {
+                if (o.mnc == 0) {
+                    return true;
+                }
+            }
+        }
+        if (locale != 0 && (!requested || requested->locale != 0)) {
+            if (language[0] != 0 && (!requested || requested->language[0] != 0)) {
+                if (o.language[0] == 0) {
+                    return true;
+                }
+            }
+            if (country[0] != 0 && (!requested || requested->country[0] != 0)) {
+                if (o.country[0] == 0) {
+                    return true;
+                }
+            }
+        }
+        if (screenType != 0 && (!requested || requested->screenType != 0)) {
+            if (orientation != 0 && (!requested || requested->orientation != 0)) {
+                if (o.orientation == 0) {
+                    return true;
+                }
+            }
+            if (density != 0 && (!requested || requested->density != 0)) {
+                if (o.density == 0) {
+                    return true;
+                }
+            }
+            if (touchscreen != 0 && (!requested || requested->touchscreen != 0)) {
+                if (o.touchscreen == 0) {
+                    return true;
+                }
+            }
+        }
+        if (input != 0 && (!requested || requested->input != 0)) {
+            const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
+            const int reqKeysHidden = requested
+                    ? requested->inputFlags&MASK_KEYSHIDDEN : 0;
+            if (keysHidden != 0 && reqKeysHidden != 0) {
+                const int oKeysHidden = o.inputFlags&MASK_KEYSHIDDEN;
+                //LOGI("isBetterThan keysHidden: cur=%d, given=%d, config=%d\n",
+                //        keysHidden, oKeysHidden, reqKeysHidden);
+                if (oKeysHidden == 0) {
+                    //LOGI("Better because 0!");
+                    return true;
+                }
+                // For compatibility, we count KEYSHIDDEN_NO as being
+                // the same as KEYSHIDDEN_SOFT.  Here we disambiguate these
+                // may making an exact match more specific.
+                if (keysHidden == reqKeysHidden && oKeysHidden != reqKeysHidden) {
+                    // The current configuration is an exact match, and
+                    // the given one is not, so the current one is better.
+                    //LOGI("Better because other not same!");
+                    return true;
+                }
+            }
+            if (keyboard != 0 && (!requested || requested->keyboard != 0)) {
+                if (o.keyboard == 0) {
+                    return true;
+                }
+            }
+            if (navigation != 0 && (!requested || requested->navigation != 0)) {
+                if (o.navigation == 0) {
+                    return true;
+                }
+            }
+        }
+        if (screenSize != 0 && (!requested || requested->screenSize != 0)) {
+            if (screenWidth != 0 && (!requested || requested->screenWidth != 0)) {
+                if (o.screenWidth == 0) {
+                    return true;
+                }
+            }
+            if (screenHeight != 0 && (!requested || requested->screenHeight != 0)) {
+                if (o.screenHeight == 0) {
+                    return true;
+                }
+            }
+        }
+        if (version != 0 && (!requested || requested->version != 0)) {
+            if (sdkVersion != 0 && (!requested || requested->sdkVersion != 0)) {
+                if (o.sdkVersion == 0) {
+                    return true;
+                }
+            }
+            if (minorVersion != 0 && (!requested || requested->minorVersion != 0)) {
+                if (o.minorVersion == 0) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    
+    // Return true if 'this' can be considered a match for the parameters in 
+    // 'settings'.
+    // Note this is asymetric.  A default piece of data will match every request
+    // but a request for the default should not match odd specifics
+    // (ie, request with no mcc should not match a particular mcc's data)
+    // settings is the requested settings
+    inline bool match(const ResTable_config& settings) const {
+        if (imsi != 0) {
+            if ((settings.mcc != 0 && mcc != 0
+                 && mcc != settings.mcc) || 
+                (settings.mcc == 0 && mcc != 0)) {
+                return false;
+            }
+            if ((settings.mnc != 0 && mnc != 0
+                 && mnc != settings.mnc) ||
+                (settings.mnc == 0 && mnc != 0)) {
+                return false;
+            }
+        }
+        if (locale != 0) {
+            if (settings.language[0] != 0 && language[0] != 0
+                && (language[0] != settings.language[0]
+                    || language[1] != settings.language[1])) {
+                return false;
+            }
+            if (settings.country[0] != 0 && country[0] != 0
+                && (country[0] != settings.country[0]
+                    || country[1] != settings.country[1])) {
+                return false;
+            }
+        }
+        if (screenType != 0) {
+            if (settings.orientation != 0 && orientation != 0
+                && orientation != settings.orientation) {
+                return false;
+            }
+            // Density not taken into account, always match, no matter what
+            // density is specified for the resource
+            if (settings.touchscreen != 0 && touchscreen != 0
+                && touchscreen != settings.touchscreen) {
+                return false;
+            }
+        }
+        if (input != 0) {
+            const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
+            const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
+            if (setKeysHidden != 0 && keysHidden != 0
+                && keysHidden != setKeysHidden) {
+                // For compatibility, we count a request for KEYSHIDDEN_NO as also
+                // matching the more recent KEYSHIDDEN_SOFT.  Basically
+                // KEYSHIDDEN_NO means there is some kind of keyboard available.
+                //LOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
+                if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) {
+                    //LOGI("No match!");
+                    return false;
+                }
+            }
+            if (settings.keyboard != 0 && keyboard != 0
+                && keyboard != settings.keyboard) {
+                return false;
+            }
+            if (settings.navigation != 0 && navigation != 0
+                && navigation != settings.navigation) {
+                return false;
+            }
+        }
+        if (screenSize != 0) {
+            if (settings.screenWidth != 0 && screenWidth != 0
+                && screenWidth != settings.screenWidth) {
+                return false;
+            }
+            if (settings.screenHeight != 0 && screenHeight != 0
+                && screenHeight != settings.screenHeight) {
+                return false;
+            }
+        }
+        if (version != 0) {
+            if (settings.sdkVersion != 0 && sdkVersion != 0
+                && sdkVersion != settings.sdkVersion) {
+                return false;
+            }
+            if (settings.minorVersion != 0 && minorVersion != 0
+                && minorVersion != settings.minorVersion) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    void getLocale(char str[6]) const {
+        memset(str, 0, 6);
+        if (language[0]) {
+            str[0] = language[0];
+            str[1] = language[1];
+            if (country[0]) {
+                str[2] = '_';
+                str[3] = country[0];
+                str[4] = country[1];
+            }
+        }
+    }
+
+    String8 toString() const {
+        char buf[200];
+        sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=0x%02x touch=0x%02x dens=0x%02x "
+                "kbd=0x%02x nav=0x%02x input=0x%02x screenW=0x%04x screenH=0x%04x vers=%d.%d",
+                mcc, mnc,
+                language[0] ? language[0] : '-', language[1] ? language[1] : '-',
+                country[0] ? country[0] : '-', country[1] ? country[1] : '-',
+                orientation, touchscreen, density, keyboard, navigation, inputFlags,
+                screenWidth, screenHeight, sdkVersion, minorVersion);
+        return String8(buf);
+    }
+};
+
+/**
+ * A specification of the resources defined by a particular type.
+ *
+ * There should be one of these chunks for each resource type.
+ *
+ * This structure is followed by an array of integers providing the set of
+ * configuation change flags (ResTable_config::CONFIG_*) that have multiple
+ * resources for that configuration.  In addition, the high bit is set if that
+ * resource has been made public.
+ */
+struct ResTable_typeSpec
+{
+    struct ResChunk_header header;
+
+    // The type identifier this chunk is holding.  Type IDs start
+    // at 1 (corresponding to the value of the type bits in a
+    // resource identifier).  0 is invalid.
+    uint8_t id;
+    
+    // Must be 0.
+    uint8_t res0;
+    // Must be 0.
+    uint16_t res1;
+    
+    // Number of uint32_t entry configuration masks that follow.
+    uint32_t entryCount;
+
+    enum {
+        // Additional flag indicating an entry is public.
+        SPEC_PUBLIC = 0x40000000
+    };
+};
+
+/**
+ * A collection of resource entries for a particular resource data
+ * type. Followed by an array of uint32_t defining the resource
+ * values, corresponding to the array of type strings in the
+ * ResTable_package::typeStrings string block. Each of these hold an
+ * index from entriesStart; a value of NO_ENTRY means that entry is
+ * not defined.
+ *
+ * There may be multiple of these chunks for a particular resource type,
+ * supply different configuration variations for the resource values of
+ * that type.
+ *
+ * It would be nice to have an additional ordered index of entries, so
+ * we can do a binary search if trying to find a resource by string name.
+ */
+struct ResTable_type
+{
+    struct ResChunk_header header;
+
+    enum {
+        NO_ENTRY = 0xFFFFFFFF
+    };
+    
+    // The type identifier this chunk is holding.  Type IDs start
+    // at 1 (corresponding to the value of the type bits in a
+    // resource identifier).  0 is invalid.
+    uint8_t id;
+    
+    // Must be 0.
+    uint8_t res0;
+    // Must be 0.
+    uint16_t res1;
+    
+    // Number of uint32_t entry indices that follow.
+    uint32_t entryCount;
+
+    // Offset from header where ResTable_entry data starts.
+    uint32_t entriesStart;
+    
+    // Configuration this collection of entries is designed for.
+    ResTable_config config;
+};
+
+/**
+ * This is the beginning of information about an entry in the resource
+ * table.  It holds the reference to the name of this entry, and is
+ * immediately followed by one of:
+ *   * A Res_value structures, if FLAG_COMPLEX is -not- set.
+ *   * An array of ResTable_map structures, if FLAG_COMPLEX is set.
+ *     These supply a set of name/value mappings of data.
+ */
+struct ResTable_entry
+{
+    // Number of bytes in this structure.
+    uint16_t size;
+
+    enum {
+        // If set, this is a complex entry, holding a set of name/value
+        // mappings.  It is followed by an array of ResTable_map structures.
+        FLAG_COMPLEX = 0x0001,
+        // If set, this resource has been declared public, so libraries
+        // are allowed to reference it.
+        FLAG_PUBLIC = 0x0002
+    };
+    uint16_t flags;
+    
+    // Reference into ResTable_package::keyStrings identifying this entry.
+    struct ResStringPool_ref key;
+};
+
+/**
+ * Extended form of a ResTable_entry for map entries, defining a parent map
+ * resource from which to inherit values.
+ */
+struct ResTable_map_entry : public ResTable_entry
+{
+    // Resource identifier of the parent mapping, or 0 if there is none.
+    ResTable_ref parent;
+    // Number of name/value pairs that follow for FLAG_COMPLEX.
+    uint32_t count;
+};
+
+/**
+ * A single name/value mapping that is part of a complex resource
+ * entry.
+ */
+struct ResTable_map
+{
+    // The resource identifier defining this mapping's name.  For attribute
+    // resources, 'name' can be one of the following special resource types
+    // to supply meta-data about the attribute; for all other resource types
+    // it must be an attribute resource.
+    ResTable_ref name;
+
+    // Special values for 'name' when defining attribute resources.
+    enum {
+        // This entry holds the attribute's type code.
+        ATTR_TYPE = Res_MAKEINTERNAL(0),
+
+        // For integral attributes, this is the minimum value it can hold.
+        ATTR_MIN = Res_MAKEINTERNAL(1),
+
+        // For integral attributes, this is the maximum value it can hold.
+        ATTR_MAX = Res_MAKEINTERNAL(2),
+
+        // Localization of this resource is can be encouraged or required with
+        // an aapt flag if this is set
+        ATTR_L10N = Res_MAKEINTERNAL(3),
+
+        // for plural support, see android.content.res.PluralRules#attrForQuantity(int)
+        ATTR_OTHER = Res_MAKEINTERNAL(4),
+        ATTR_ZERO = Res_MAKEINTERNAL(5),
+        ATTR_ONE = Res_MAKEINTERNAL(6),
+        ATTR_TWO = Res_MAKEINTERNAL(7),
+        ATTR_FEW = Res_MAKEINTERNAL(8),
+        ATTR_MANY = Res_MAKEINTERNAL(9)
+        
+    };
+
+    // Bit mask of allowed types, for use with ATTR_TYPE.
+    enum {
+        // No type has been defined for this attribute, use generic
+        // type handling.  The low 16 bits are for types that can be
+        // handled generically; the upper 16 require additional information
+        // in the bag so can not be handled generically for TYPE_ANY.
+        TYPE_ANY = 0x0000FFFF,
+
+        // Attribute holds a references to another resource.
+        TYPE_REFERENCE = 1<<0,
+
+        // Attribute holds a generic string.
+        TYPE_STRING = 1<<1,
+
+        // Attribute holds an integer value.  ATTR_MIN and ATTR_MIN can
+        // optionally specify a constrained range of possible integer values.
+        TYPE_INTEGER = 1<<2,
+
+        // Attribute holds a boolean integer.
+        TYPE_BOOLEAN = 1<<3,
+
+        // Attribute holds a color value.
+        TYPE_COLOR = 1<<4,
+
+        // Attribute holds a floating point value.
+        TYPE_FLOAT = 1<<5,
+
+        // Attribute holds a dimension value, such as "20px".
+        TYPE_DIMENSION = 1<<6,
+
+        // Attribute holds a fraction value, such as "20%".
+        TYPE_FRACTION = 1<<7,
+
+        // Attribute holds an enumeration.  The enumeration values are
+        // supplied as additional entries in the map.
+        TYPE_ENUM = 1<<16,
+
+        // Attribute holds a bitmaks of flags.  The flag bit values are
+        // supplied as additional entries in the map.
+        TYPE_FLAGS = 1<<17
+    };
+
+    // Enum of localization modes, for use with ATTR_L10N.
+    enum {
+        L10N_NOT_REQUIRED = 0,
+        L10N_SUGGESTED    = 1
+    };
+    
+    // This mapping's value.
+    Res_value value;
+};
+
+/**
+ * Convenience class for accessing data in a ResTable resource.
+ */
+class ResTable
+{
+public:
+    ResTable();
+    ResTable(const void* data, size_t size, void* cookie,
+             bool copyData=false);
+    ~ResTable();
+
+    status_t add(const void* data, size_t size, void* cookie,
+                 bool copyData=false);
+    status_t add(Asset* asset, void* cookie,
+                 bool copyData=false);
+
+    status_t getError() const;
+
+    void uninit();
+
+    struct resource_name
+    {
+        const char16_t* package;
+        size_t packageLen;
+        const char16_t* type;
+        size_t typeLen;
+        const char16_t* name;
+        size_t nameLen;
+    };
+
+    bool getResourceName(uint32_t resID, resource_name* outName) const;
+
+    /**
+     * Retrieve the value of a resource.  If the resource is found, returns a
+     * value >= 0 indicating the table it is in (for use with
+     * getTableStringBlock() and getTableCookie()) and fills in 'outValue'.  If
+     * not found, returns a negative error code.
+     *
+     * Note that this function does not do reference traversal.  If you want
+     * to follow references to other resources to get the "real" value to
+     * use, you need to call resolveReference() after this function.
+     *
+     * @param resID The desired resoruce identifier.
+     * @param outValue Filled in with the resource data that was found.
+     *
+     * @return ssize_t Either a >= 0 table index or a negative error code.
+     */
+    ssize_t getResource(uint32_t resID, Res_value* outValue, bool mayBeBag=false,
+            uint32_t* outSpecFlags=NULL, ResTable_config* outConfig=NULL) const;
+
+    inline ssize_t getResource(const ResTable_ref& res, Res_value* outValue,
+            uint32_t* outSpecFlags=NULL) const {
+        return getResource(res.ident, outValue, false, outSpecFlags, NULL);
+    }
+
+    ssize_t resolveReference(Res_value* inOutValue,
+                             ssize_t blockIndex,
+                             uint32_t* outLastRef = NULL,
+                             uint32_t* inoutTypeSpecFlags = NULL) const;
+
+    enum {
+        TMP_BUFFER_SIZE = 16
+    };
+    const char16_t* valueToString(const Res_value* value, size_t stringBlock,
+                                  char16_t tmpBuffer[TMP_BUFFER_SIZE],
+                                  size_t* outLen);
+
+    struct bag_entry {
+        ssize_t stringBlock;
+        ResTable_map map;
+    };
+
+    /**
+     * Retrieve the bag of a resource.  If the resoruce is found, returns the
+     * number of bags it contains and 'outBag' points to an array of their
+     * values.  If not found, a negative error code is returned.
+     *
+     * Note that this function -does- do reference traversal of the bag data.
+     *
+     * @param resID The desired resource identifier.
+     * @param outBag Filled inm with a pointer to the bag mappings.
+     *
+     * @return ssize_t Either a >= 0 bag count of negative error code.
+     */
+    ssize_t lockBag(uint32_t resID, const bag_entry** outBag) const;
+
+    void unlockBag(const bag_entry* bag) const;
+
+    void lock() const;
+
+    ssize_t getBagLocked(uint32_t resID, const bag_entry** outBag,
+            uint32_t* outTypeSpecFlags=NULL) const;
+
+    void unlock() const;
+
+    class Theme {
+    public:
+        Theme(const ResTable& table);
+        ~Theme();
+
+        inline const ResTable& getResTable() const { return mTable; }
+
+        status_t applyStyle(uint32_t resID, bool force=false);
+        status_t setTo(const Theme& other);
+
+        /**
+         * Retrieve a value in the theme.  If the theme defines this
+         * value, returns a value >= 0 indicating the table it is in
+         * (for use with getTableStringBlock() and getTableCookie) and
+         * fills in 'outValue'.  If not found, returns a negative error
+         * code.
+         *
+         * Note that this function does not do reference traversal.  If you want
+         * to follow references to other resources to get the "real" value to
+         * use, you need to call resolveReference() after this function.
+         *
+         * @param resID A resource identifier naming the desired theme
+         *              attribute.
+         * @param outValue Filled in with the theme value that was
+         *                 found.
+         *
+         * @return ssize_t Either a >= 0 table index or a negative error code.
+         */
+        ssize_t getAttribute(uint32_t resID, Res_value* outValue,
+                uint32_t* outTypeSpecFlags = NULL) const;
+
+        /**
+         * This is like ResTable::resolveReference(), but also takes
+         * care of resolving attribute references to the theme.
+         */
+        ssize_t resolveAttributeReference(Res_value* inOutValue,
+                ssize_t blockIndex, uint32_t* outLastRef = NULL,
+                uint32_t* inoutTypeSpecFlags = NULL) const;
+
+        void dumpToLog() const;
+        
+    private:
+        Theme(const Theme&);
+        Theme& operator=(const Theme&);
+
+        struct theme_entry {
+            ssize_t stringBlock;
+            uint32_t typeSpecFlags;
+            Res_value value;
+        };
+        struct type_info {
+            size_t numEntries;
+            theme_entry* entries;
+        };
+        struct package_info {
+            size_t numTypes;
+            type_info types[];
+        };
+
+        void free_package(package_info* pi);
+        package_info* copy_package(package_info* pi);
+
+        const ResTable& mTable;
+        package_info*   mPackages[Res_MAXPACKAGE];
+    };
+
+    void setParameters(const ResTable_config* params);
+    void getParameters(ResTable_config* params) const;
+
+    // Retrieve an identifier (which can be passed to getResource)
+    // for a given resource name.  The 'name' can be fully qualified
+    // (<package>:<type>.<basename>) or the package or type components
+    // can be dropped if default values are supplied here.
+    //
+    // Returns 0 if no such resource was found, else a valid resource ID.
+    uint32_t identifierForName(const char16_t* name, size_t nameLen,
+                               const char16_t* type = 0, size_t typeLen = 0,
+                               const char16_t* defPackage = 0,
+                               size_t defPackageLen = 0,
+                               uint32_t* outTypeSpecFlags = NULL) const;
+
+    static bool expandResourceRef(const uint16_t* refStr, size_t refLen,
+                                  String16* outPackage,
+                                  String16* outType,
+                                  String16* outName,
+                                  const String16* defType = NULL,
+                                  const String16* defPackage = NULL,
+                                  const char** outErrorMsg = NULL);
+
+    static bool stringToInt(const char16_t* s, size_t len, Res_value* outValue);
+    static bool stringToFloat(const char16_t* s, size_t len, Res_value* outValue);
+
+    // Used with stringToValue.
+    class Accessor
+    {
+    public:
+        inline virtual ~Accessor() { }
+
+        virtual uint32_t getCustomResource(const String16& package,
+                                           const String16& type,
+                                           const String16& name) const = 0;
+        virtual uint32_t getCustomResourceWithCreation(const String16& package,
+                                                       const String16& type,
+                                                       const String16& name,
+                                                       const bool createIfNeeded = false) = 0;
+        virtual uint32_t getRemappedPackage(uint32_t origPackage) const = 0;
+        virtual bool getAttributeType(uint32_t attrID, uint32_t* outType) = 0;
+        virtual bool getAttributeMin(uint32_t attrID, uint32_t* outMin) = 0;
+        virtual bool getAttributeMax(uint32_t attrID, uint32_t* outMax) = 0;
+        virtual bool getAttributeEnum(uint32_t attrID,
+                                      const char16_t* name, size_t nameLen,
+                                      Res_value* outValue) = 0;
+        virtual bool getAttributeFlags(uint32_t attrID,
+                                       const char16_t* name, size_t nameLen,
+                                       Res_value* outValue) = 0;
+        virtual uint32_t getAttributeL10N(uint32_t attrID) = 0;
+        virtual bool getLocalizationSetting() = 0;
+        virtual void reportError(void* accessorCookie, const char* fmt, ...) = 0;
+    };
+
+    // Convert a string to a resource value.  Handles standard "@res",
+    // "#color", "123", and "0x1bd" types; performs escaping of strings.
+    // The resulting value is placed in 'outValue'; if it is a string type,
+    // 'outString' receives the string.  If 'attrID' is supplied, the value is
+    // type checked against this attribute and it is used to perform enum
+    // evaluation.  If 'acccessor' is supplied, it will be used to attempt to
+    // resolve resources that do not exist in this ResTable.  If 'attrType' is
+    // supplied, the value will be type checked for this format if 'attrID'
+    // is not supplied or found.
+    bool stringToValue(Res_value* outValue, String16* outString,
+                       const char16_t* s, size_t len,
+                       bool preserveSpaces, bool coerceType,
+                       uint32_t attrID = 0,
+                       const String16* defType = NULL,
+                       const String16* defPackage = NULL,
+                       Accessor* accessor = NULL,
+                       void* accessorCookie = NULL,
+                       uint32_t attrType = ResTable_map::TYPE_ANY,
+                       bool enforcePrivate = true) const;
+
+    // Perform processing of escapes and quotes in a string.
+    static bool collectString(String16* outString,
+                              const char16_t* s, size_t len,
+                              bool preserveSpaces,
+                              const char** outErrorMsg = NULL,
+                              bool append = false);
+
+    size_t getBasePackageCount() const;
+    const char16_t* getBasePackageName(size_t idx) const;
+    uint32_t getBasePackageId(size_t idx) const;
+
+    size_t getTableCount() const;
+    const ResStringPool* getTableStringBlock(size_t index) const;
+    void* getTableCookie(size_t index) const;
+
+    // Return the configurations (ResTable_config) that we know about
+    void getConfigurations(Vector<ResTable_config>* configs) const;
+
+    void getLocales(Vector<String8>* locales) const;
+
+#ifndef HAVE_ANDROID_OS
+    void print() const;
+#endif
+
+private:
+    struct Header;
+    struct Type;
+    struct Package;
+    struct PackageGroup;
+    struct bag_set;
+
+    status_t add(const void* data, size_t size, void* cookie,
+                 Asset* asset, bool copyData);
+
+    ssize_t getResourcePackageIndex(uint32_t resID) const;
+    ssize_t getEntry(
+        const Package* package, int typeIndex, int entryIndex,
+        const ResTable_config* config,
+        const ResTable_type** outType, const ResTable_entry** outEntry,
+        const Type** outTypeClass) const;
+    status_t parsePackage(
+        const ResTable_package* const pkg, const Header* const header);
+
+    mutable Mutex               mLock;
+
+    status_t                    mError;
+
+    ResTable_config             mParams;
+
+    // Array of all resource tables.
+    Vector<Header*>             mHeaders;
+
+    // Array of packages in all resource tables.
+    Vector<PackageGroup*>       mPackageGroups;
+
+    // Mapping from resource package IDs to indices into the internal
+    // package array.
+    uint8_t                     mPackageMap[256];
+};
+
+}   // namespace android
+
+#endif // _LIBS_UTILS_RESOURCE_TYPES_H
diff --git a/include/utils/SharedBuffer.h b/include/utils/SharedBuffer.h
new file mode 100644
index 0000000..24508b0
--- /dev/null
+++ b/include/utils/SharedBuffer.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_SHARED_BUFFER_H
+#define ANDROID_SHARED_BUFFER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class SharedBuffer
+{
+public:
+
+    /* flags to use with release() */
+    enum {
+        eKeepStorage = 0x00000001
+    };
+
+    /*! allocate a buffer of size 'size' and acquire() it.
+     *  call release() to free it.
+     */
+    static          SharedBuffer*           alloc(size_t size);
+    
+    /*! free the memory associated with the SharedBuffer.
+     * Fails if there are any users associated with this SharedBuffer.
+     * In other words, the buffer must have been release by all its
+     * users.
+     */
+    static          ssize_t                 dealloc(const SharedBuffer* released);
+    
+    //! get the SharedBuffer from the data pointer
+    static  inline  const SharedBuffer*     sharedBuffer(const void* data);
+
+    //! access the data for read
+    inline          const void*             data() const;
+    
+    //! access the data for read/write
+    inline          void*                   data();
+
+    //! get size of the buffer
+    inline          size_t                  size() const;
+ 
+    //! get back a SharedBuffer object from its data
+    static  inline  SharedBuffer*           bufferFromData(void* data);
+    
+    //! get back a SharedBuffer object from its data
+    static  inline  const SharedBuffer*     bufferFromData(const void* data);
+
+    //! get the size of a SharedBuffer object from its data
+    static  inline  size_t                  sizeFromData(const void* data);
+    
+    //! edit the buffer (get a writtable, or non-const, version of it)
+                    SharedBuffer*           edit() const;
+
+    //! edit the buffer, resizing if needed
+                    SharedBuffer*           editResize(size_t size) const;
+
+    //! like edit() but fails if a copy is required
+                    SharedBuffer*           attemptEdit() const;
+    
+    //! resize and edit the buffer, loose it's content.
+                    SharedBuffer*           reset(size_t size) const;
+
+    //! acquire/release a reference on this buffer
+                    void                    acquire() const;
+                    
+    /*! release a reference on this buffer, with the option of not
+     * freeing the memory associated with it if it was the last reference
+     * returns the previous reference count
+     */     
+                    int32_t                 release(uint32_t flags = 0) const;
+    
+    //! returns wether or not we're the only owner
+    inline          bool                    onlyOwner() const;
+    
+
+private:
+        inline SharedBuffer() { }
+        inline ~SharedBuffer() { }
+        inline SharedBuffer(const SharedBuffer&);
+ 
+        // 16 bytes. must be sized to preserve correct alingment.
+        mutable int32_t        mRefs;
+                size_t         mSize;
+                uint32_t       mReserved[2];
+};
+
+// ---------------------------------------------------------------------------
+
+const SharedBuffer* SharedBuffer::sharedBuffer(const void* data) {
+    return data ? reinterpret_cast<const SharedBuffer *>(data)-1 : 0;
+}
+
+const void* SharedBuffer::data() const {
+    return this + 1;
+}
+
+void* SharedBuffer::data() {
+    return this + 1;
+}
+
+size_t SharedBuffer::size() const {
+    return mSize;
+}
+
+SharedBuffer* SharedBuffer::bufferFromData(void* data)
+{
+    return ((SharedBuffer*)data)-1;
+}
+    
+const SharedBuffer* SharedBuffer::bufferFromData(const void* data)
+{
+    return ((const SharedBuffer*)data)-1;
+}
+
+size_t SharedBuffer::sizeFromData(const void* data)
+{
+    return (((const SharedBuffer*)data)-1)->mSize;
+}
+
+bool SharedBuffer::onlyOwner() const {
+    return (mRefs == 1);
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_VECTOR_H
diff --git a/include/utils/Socket.h b/include/utils/Socket.h
new file mode 100644
index 0000000..8b7f406
--- /dev/null
+++ b/include/utils/Socket.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Socket class.  Modeled after Java classes.
+//
+#ifndef _RUNTIME_SOCKET_H
+#define _RUNTIME_SOCKET_H
+
+#include <utils/inet_address.h>
+#include <sys/types.h>
+
+namespace android {
+
+/*
+ * Basic socket class, needed to abstract away the differences between
+ * BSD sockets and WinSock.  This establishes a streaming network
+ * connection (TCP/IP) to somebody.
+ */
+class Socket {
+public:
+    Socket(void);
+    ~Socket(void);
+
+    // Create a connection to somewhere.
+    // Return 0 on success.
+    int connect(const char* host, int port);
+    int connect(const InetAddress* addr, int port);
+
+
+    // Close the socket.  Don't try to use this object again after
+    // calling this.  Returns false on failure.
+    bool close(void);
+
+    // If we created the socket without an address, we can use these
+    // to finish the connection.  Returns 0 on success.
+    int bind(const SocketAddress& bindPoint);
+    int connect(const SocketAddress& endPoint);
+
+    // Here we deviate from the traditional object-oriented fanciness
+    // and just provide read/write operators instead of getters for
+    // objects that abstract a stream.
+    //
+    // Standard read/write semantics.
+    int read(void* buf, ssize_t len) const;
+    int write(const void* buf, ssize_t len) const;
+
+    // This must be called once, at program startup.
+    static bool bootInit(void);
+    static void finalShutdown(void);
+
+private:
+    // Internal function that establishes a connection.
+    int doConnect(const InetSocketAddress& addr);
+
+    unsigned long   mSock;      // holds SOCKET or int
+
+    static bool     mBootInitialized;
+};
+
+
+// debug -- unit tests
+void TestSockets(void);
+
+}; // namespace android
+
+#endif // _RUNTIME_SOCKET_H
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
new file mode 100644
index 0000000..c8a6153
--- /dev/null
+++ b/include/utils/SortedVector.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_SORTED_VECTOR_H
+#define ANDROID_SORTED_VECTOR_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Vector.h>
+#include <utils/VectorImpl.h>
+#include <utils/TypeHelpers.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+template <class TYPE>
+class SortedVector : private SortedVectorImpl
+{
+public:
+            typedef TYPE    value_type;
+    
+    /*! 
+     * Constructors and destructors
+     */
+    
+                            SortedVector();
+                            SortedVector(const SortedVector<TYPE>& rhs);
+    virtual                 ~SortedVector();
+
+    /*! copy operator */
+    const SortedVector<TYPE>&   operator = (const SortedVector<TYPE>& rhs) const;    
+    SortedVector<TYPE>&         operator = (const SortedVector<TYPE>& rhs);    
+
+    /*
+     * empty the vector
+     */
+
+    inline  void            clear()             { VectorImpl::clear(); }
+
+    /*! 
+     * vector stats
+     */
+
+    //! returns number of items in the vector
+    inline  size_t          size() const                { return VectorImpl::size(); }
+    //! returns wether or not the vector is empty
+    inline  bool            isEmpty() const             { return VectorImpl::isEmpty(); }
+    //! returns how many items can be stored without reallocating the backing store
+    inline  size_t          capacity() const            { return VectorImpl::capacity(); }
+    //! setst the capacity. capacity can never be reduced less than size()
+    inline  ssize_t         setCapacity(size_t size)    { return VectorImpl::setCapacity(size); }
+
+    /*! 
+     * C-style array access
+     */
+     
+    //! read-only C-style access 
+    inline  const TYPE*     array() const;
+
+    //! read-write C-style access. BE VERY CAREFUL when modifying the array
+    //! you ust keep it sorted! You usually don't use this function.
+            TYPE*           editArray();
+
+            //! finds the index of an item
+            ssize_t         indexOf(const TYPE& item) const;
+            
+            //! finds where this item should be inserted
+            size_t          orderOf(const TYPE& item) const;
+            
+    
+    /*! 
+     * accessors
+     */
+
+    //! read-only access to an item at a given index
+    inline  const TYPE&     operator [] (size_t index) const;
+    //! alternate name for operator []
+    inline  const TYPE&     itemAt(size_t index) const;
+    //! stack-usage of the vector. returns the top of the stack (last element)
+            const TYPE&     top() const;
+    //! same as operator [], but allows to access the vector backward (from the end) with a negative index
+            const TYPE&     mirrorItemAt(ssize_t index) const;
+
+    /*!
+     * modifing the array
+     */
+
+            //! add an item in the right place (and replace the one that is there)
+            ssize_t         add(const TYPE& item);
+            
+            //! editItemAt() MUST NOT change the order of this item
+            TYPE&           editItemAt(size_t index) {
+                return *( static_cast<TYPE *>(VectorImpl::editItemLocation(index)) );
+            }
+
+            //! merges a vector into this one
+            ssize_t         merge(const Vector<TYPE>& vector);
+            ssize_t         merge(const SortedVector<TYPE>& vector);
+            
+            //! removes an item
+            ssize_t         remove(const TYPE&);
+
+    //! remove several items
+    inline  ssize_t         removeItemsAt(size_t index, size_t count = 1);
+    //! remove one item
+    inline  ssize_t         removeAt(size_t index)  { return removeItemsAt(index); }
+            
+protected:
+    virtual void    do_construct(void* storage, size_t num) const;
+    virtual void    do_destroy(void* storage, size_t num) const;
+    virtual void    do_copy(void* dest, const void* from, size_t num) const;
+    virtual void    do_splat(void* dest, const void* item, size_t num) const;
+    virtual void    do_move_forward(void* dest, const void* from, size_t num) const;
+    virtual void    do_move_backward(void* dest, const void* from, size_t num) const;
+    virtual int     do_compare(const void* lhs, const void* rhs) const;
+};
+
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts from here...
+// ---------------------------------------------------------------------------
+
+template<class TYPE> inline
+SortedVector<TYPE>::SortedVector()
+    : SortedVectorImpl(sizeof(TYPE),
+                ((traits<TYPE>::has_trivial_ctor   ? HAS_TRIVIAL_CTOR   : 0)
+                |(traits<TYPE>::has_trivial_dtor   ? HAS_TRIVIAL_DTOR   : 0)
+                |(traits<TYPE>::has_trivial_copy   ? HAS_TRIVIAL_COPY   : 0)
+                |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
+                )
+{
+}
+
+template<class TYPE> inline
+SortedVector<TYPE>::SortedVector(const SortedVector<TYPE>& rhs)
+    : SortedVectorImpl(rhs) {
+}
+
+template<class TYPE> inline
+SortedVector<TYPE>::~SortedVector() {
+    finish_vector();
+}
+
+template<class TYPE> inline
+SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
+    SortedVectorImpl::operator = (rhs);
+    return *this; 
+}
+
+template<class TYPE> inline
+const SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
+    SortedVectorImpl::operator = (rhs);
+    return *this; 
+}
+
+template<class TYPE> inline
+const TYPE* SortedVector<TYPE>::array() const {
+    return static_cast<const TYPE *>(arrayImpl());
+}
+
+template<class TYPE> inline
+TYPE* SortedVector<TYPE>::editArray() {
+    return static_cast<TYPE *>(editArrayImpl());
+}
+
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::operator[](size_t index) const {
+    assert( index<size() );
+    return *(array() + index);
+}
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::itemAt(size_t index) const {
+    return operator[](index);
+}
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::mirrorItemAt(ssize_t index) const {
+    assert( (index>0 ? index : -index)<size() );
+    return *(array() + ((index<0) ? (size()-index) : index));
+}
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::top() const {
+    return *(array() + size() - 1);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::add(const TYPE& item) {
+    return SortedVectorImpl::add(&item);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::indexOf(const TYPE& item) const {
+    return SortedVectorImpl::indexOf(&item);
+}
+
+template<class TYPE> inline
+size_t SortedVector<TYPE>::orderOf(const TYPE& item) const {
+    return SortedVectorImpl::orderOf(&item);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::merge(const Vector<TYPE>& vector) {
+    return SortedVectorImpl::merge(reinterpret_cast<const VectorImpl&>(vector));
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::merge(const SortedVector<TYPE>& vector) {
+    return SortedVectorImpl::merge(reinterpret_cast<const SortedVectorImpl&>(vector));
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::remove(const TYPE& item) {
+    return SortedVectorImpl::remove(&item);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::removeItemsAt(size_t index, size_t count) {
+    return VectorImpl::removeItemsAt(index, count);
+}
+
+// ---------------------------------------------------------------------------
+
+template<class TYPE>
+void SortedVector<TYPE>::do_construct(void* storage, size_t num) const {
+    construct_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_destroy(void* storage, size_t num) const {
+    destroy_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
+    copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
+    splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
+    move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
+    move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+int SortedVector<TYPE>::do_compare(const void* lhs, const void* rhs) const {
+    return compare_type( *reinterpret_cast<const TYPE*>(lhs), *reinterpret_cast<const TYPE*>(rhs) );
+}
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_SORTED_VECTOR_H
diff --git a/include/utils/StopWatch.h b/include/utils/StopWatch.h
new file mode 100644
index 0000000..cc0bebc
--- /dev/null
+++ b/include/utils/StopWatch.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_STOPWATCH_H
+#define ANDROID_STOPWATCH_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Timers.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class StopWatch
+{
+public:
+        StopWatch(  const char *name,
+                    int clock = SYSTEM_TIME_MONOTONIC,
+                    uint32_t flags = 0);
+        ~StopWatch();
+        
+        const char* name() const;
+        nsecs_t     lap();
+        nsecs_t     elapsedTime() const;
+        
+private:
+    const char*     mName;
+    int             mClock;
+    uint32_t        mFlags;
+    
+    struct lap_t {
+        nsecs_t     soFar;
+        nsecs_t     thisLap;
+    };
+    
+    nsecs_t         mStartTime;
+    lap_t           mLaps[8];
+    int             mNumLaps;
+};
+
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STOPWATCH_H
diff --git a/include/utils/String16.h b/include/utils/String16.h
new file mode 100644
index 0000000..a2d22ee
--- /dev/null
+++ b/include/utils/String16.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_STRING16_H
+#define ANDROID_STRING16_H
+
+#include <utils/Errors.h>
+#include <utils/SharedBuffer.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+// ---------------------------------------------------------------------------
+
+extern "C" {
+
+typedef uint16_t char16_t;
+
+// Standard string functions on char16 strings.
+int strcmp16(const char16_t *, const char16_t *);
+int strncmp16(const char16_t *s1, const char16_t *s2, size_t n);
+size_t strlen16(const char16_t *);
+size_t strnlen16(const char16_t *, size_t);
+char16_t *strcpy16(char16_t *, const char16_t *);
+char16_t *strncpy16(char16_t *, const char16_t *, size_t);
+
+// Version of comparison that supports embedded nulls.
+// This is different than strncmp() because we don't stop
+// at a nul character and consider the strings to be different
+// if the lengths are different (thus we need to supply the
+// lengths of both strings).  This can also be used when
+// your string is not nul-terminated as it will have the
+// equivalent result as strcmp16 (unlike strncmp16).
+int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2);
+
+// Version of strzcmp16 for comparing strings in different endianness.
+int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2);
+
+}
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class String8;
+class TextOutput;
+
+//! This is a string holding UTF-16 characters.
+class String16
+{
+public:
+                                String16();
+                                String16(const String16& o);
+                                String16(const String16& o,
+                                         size_t len,
+                                         size_t begin=0);
+    explicit                    String16(const char16_t* o);
+    explicit                    String16(const char16_t* o, size_t len);
+    explicit                    String16(const String8& o);
+    explicit                    String16(const char* o);
+    explicit                    String16(const char* o, size_t len);
+
+                                ~String16();
+    
+    inline  const char16_t*     string() const;
+    inline  size_t              size() const;
+    
+    inline  const SharedBuffer* sharedBuffer() const;
+    
+            void                setTo(const String16& other);
+            status_t            setTo(const char16_t* other);
+            status_t            setTo(const char16_t* other, size_t len);
+            status_t            setTo(const String16& other,
+                                      size_t len,
+                                      size_t begin=0);
+    
+            status_t            append(const String16& other);
+            status_t            append(const char16_t* other, size_t len);
+            
+    inline  String16&           operator=(const String16& other);
+    
+    inline  String16&           operator+=(const String16& other);
+    inline  String16            operator+(const String16& other) const;
+
+            status_t            insert(size_t pos, const char16_t* chrs);
+            status_t            insert(size_t pos,
+                                       const char16_t* chrs, size_t len);
+
+            ssize_t             findFirst(char16_t c) const;
+            ssize_t             findLast(char16_t c) const;
+
+            bool                startsWith(const String16& prefix) const;
+            bool                startsWith(const char16_t* prefix) const;
+            
+            status_t            makeLower();
+
+            status_t            replaceAll(char16_t replaceThis,
+                                           char16_t withThis);
+
+            status_t            remove(size_t len, size_t begin=0);
+
+    inline  int                 compare(const String16& other) const;
+
+    inline  bool                operator<(const String16& other) const;
+    inline  bool                operator<=(const String16& other) const;
+    inline  bool                operator==(const String16& other) const;
+    inline  bool                operator!=(const String16& other) const;
+    inline  bool                operator>=(const String16& other) const;
+    inline  bool                operator>(const String16& other) const;
+    
+    inline  bool                operator<(const char16_t* other) const;
+    inline  bool                operator<=(const char16_t* other) const;
+    inline  bool                operator==(const char16_t* other) const;
+    inline  bool                operator!=(const char16_t* other) const;
+    inline  bool                operator>=(const char16_t* other) const;
+    inline  bool                operator>(const char16_t* other) const;
+    
+    inline                      operator const char16_t*() const;
+    
+private:
+            const char16_t*     mString;
+};
+
+TextOutput& operator<<(TextOutput& to, const String16& val);
+
+// ---------------------------------------------------------------------------
+// No user servicable parts below.
+
+inline int compare_type(const String16& lhs, const String16& rhs)
+{
+    return lhs.compare(rhs);
+}
+
+inline int strictly_order_type(const String16& lhs, const String16& rhs)
+{
+    return compare_type(lhs, rhs) < 0;
+}
+
+inline const char16_t* String16::string() const
+{
+    return mString;
+}
+
+inline size_t String16::size() const
+{
+    return SharedBuffer::sizeFromData(mString)/sizeof(char16_t)-1;
+}
+
+inline const SharedBuffer* String16::sharedBuffer() const
+{
+    return SharedBuffer::bufferFromData(mString);
+}
+
+inline String16& String16::operator=(const String16& other)
+{
+    setTo(other);
+    return *this;
+}
+
+inline String16& String16::operator+=(const String16& other)
+{
+    append(other);
+    return *this;
+}
+
+inline String16 String16::operator+(const String16& other) const
+{
+    String16 tmp;
+    tmp += other;
+    return tmp;
+}
+
+inline int String16::compare(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size());
+}
+
+inline bool String16::operator<(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size()) < 0;
+}
+
+inline bool String16::operator<=(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size()) <= 0;
+}
+
+inline bool String16::operator==(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size()) == 0;
+}
+
+inline bool String16::operator!=(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size()) != 0;
+}
+
+inline bool String16::operator>=(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size()) >= 0;
+}
+
+inline bool String16::operator>(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size()) > 0;
+}
+
+inline bool String16::operator<(const char16_t* other) const
+{
+    return strcmp16(mString, other) < 0;
+}
+
+inline bool String16::operator<=(const char16_t* other) const
+{
+    return strcmp16(mString, other) <= 0;
+}
+
+inline bool String16::operator==(const char16_t* other) const
+{
+    return strcmp16(mString, other) == 0;
+}
+
+inline bool String16::operator!=(const char16_t* other) const
+{
+    return strcmp16(mString, other) != 0;
+}
+
+inline bool String16::operator>=(const char16_t* other) const
+{
+    return strcmp16(mString, other) >= 0;
+}
+
+inline bool String16::operator>(const char16_t* other) const
+{
+    return strcmp16(mString, other) > 0;
+}
+
+inline String16::operator const char16_t*() const
+{
+    return mString;
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STRING16_H
diff --git a/include/utils/String8.h b/include/utils/String8.h
new file mode 100644
index 0000000..c49faf6
--- /dev/null
+++ b/include/utils/String8.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_STRING8_H
+#define ANDROID_STRING8_H
+
+#include <utils/Errors.h>
+
+// Need this for the char16_t type; String8.h should not
+// be depedent on the String16 class.
+#include <utils/String16.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class TextOutput;
+
+//! This is a string holding UTF-8 characters.
+class String8
+{
+public:
+                                String8();
+                                String8(const String8& o);
+    explicit                    String8(const char* o);
+    explicit                    String8(const char* o, size_t numChars);
+    
+    explicit                    String8(const String16& o);
+    explicit                    String8(const char16_t* o);
+    explicit                    String8(const char16_t* o, size_t numChars);
+    
+                                ~String8();
+    
+    inline  const char*         string() const;
+    inline  size_t              size() const;
+    inline  size_t              length() const;
+    inline  size_t              bytes() const;
+    
+    inline  const SharedBuffer* sharedBuffer() const;
+    
+            void                setTo(const String8& other);
+            status_t            setTo(const char* other);
+            status_t            setTo(const char* other, size_t numChars);
+            status_t            setTo(const char16_t* other, size_t numChars);
+    
+            status_t            append(const String8& other);
+            status_t            append(const char* other);
+            status_t            append(const char* other, size_t numChars);
+
+    inline  String8&            operator=(const String8& other);
+    inline  String8&            operator=(const char* other);
+    
+    inline  String8&            operator+=(const String8& other);
+    inline  String8             operator+(const String8& other) const;
+    
+    inline  String8&            operator+=(const char* other);
+    inline  String8             operator+(const char* other) const;
+
+    inline  int                 compare(const String8& other) const;
+
+    inline  bool                operator<(const String8& other) const;
+    inline  bool                operator<=(const String8& other) const;
+    inline  bool                operator==(const String8& other) const;
+    inline  bool                operator!=(const String8& other) const;
+    inline  bool                operator>=(const String8& other) const;
+    inline  bool                operator>(const String8& other) const;
+    
+    inline  bool                operator<(const char* other) const;
+    inline  bool                operator<=(const char* other) const;
+    inline  bool                operator==(const char* other) const;
+    inline  bool                operator!=(const char* other) const;
+    inline  bool                operator>=(const char* other) const;
+    inline  bool                operator>(const char* other) const;
+    
+    inline                      operator const char*() const;
+    
+            char*               lockBuffer(size_t size);
+            void                unlockBuffer();
+            status_t            unlockBuffer(size_t size);
+            
+            // return the index of the first byte of other in this at or after
+            // start, or -1 if not found
+            ssize_t             find(const char* other, size_t start = 0) const;
+
+            void                toLower();
+            void                toLower(size_t start, size_t numChars);
+            void                toUpper();
+            void                toUpper(size_t start, size_t numChars);
+            
+    /*
+     * These methods operate on the string as if it were a path name.
+     */
+
+    /*
+     * Set the filename field to a specific value.
+     *
+     * Normalizes the filename, removing a trailing '/' if present.
+     */
+    void setPathName(const char* name);
+    void setPathName(const char* name, size_t numChars);
+
+    /*
+     * Get just the filename component.
+     *
+     * "/tmp/foo/bar.c" --> "bar.c"
+     */
+    String8 getPathLeaf(void) const;
+
+    /*
+     * Remove the last (file name) component, leaving just the directory
+     * name.
+     *
+     * "/tmp/foo/bar.c" --> "/tmp/foo"
+     * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX
+     * "bar.c" --> ""
+     */
+    String8 getPathDir(void) const;
+
+    /*
+     * Retrieve the front (root dir) component.  Optionally also return the
+     * remaining components.
+     *
+     * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c")
+     * "/tmp" --> "tmp" (remain = "")
+     * "bar.c" --> "bar.c" (remain = "")
+     */
+    String8 walkPath(String8* outRemains = NULL) const;
+
+    /*
+     * Return the filename extension.  This is the last '.' and up to
+     * four characters that follow it.  The '.' is included in case we
+     * decide to expand our definition of what constitutes an extension.
+     *
+     * "/tmp/foo/bar.c" --> ".c"
+     * "/tmp" --> ""
+     * "/tmp/foo.bar/baz" --> ""
+     * "foo.jpeg" --> ".jpeg"
+     * "foo." --> ""
+     */
+    String8 getPathExtension(void) const;
+
+    /*
+     * Return the path without the extension.  Rules for what constitutes
+     * an extension are described in the comment for getPathExtension().
+     *
+     * "/tmp/foo/bar.c" --> "/tmp/foo/bar"
+     */
+    String8 getBasePath(void) const;
+
+    /*
+     * Add a component to the pathname.  We guarantee that there is
+     * exactly one path separator between the old path and the new.
+     * If there is no existing name, we just copy the new name in.
+     *
+     * If leaf is a fully qualified path (i.e. starts with '/', it
+     * replaces whatever was there before.
+     */
+    String8& appendPath(const char* leaf);
+    String8& appendPath(const String8& leaf)  { return appendPath(leaf.string()); }
+
+    /*
+     * Like appendPath(), but does not affect this string.  Returns a new one instead.
+     */
+    String8 appendPathCopy(const char* leaf) const
+                                             { String8 p(*this); p.appendPath(leaf); return p; }
+    String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.string()); }
+
+    /*
+     * Converts all separators in this string to /, the default path separator.
+     *
+     * If the default OS separator is backslash, this converts all
+     * backslashes to slashes, in-place. Otherwise it does nothing.
+     * Returns self.
+     */
+    String8& convertToResPath();
+
+private:
+            status_t            real_append(const char* other, size_t numChars);
+            char*               find_extension(void) const;
+
+            const char* mString;
+};
+
+TextOutput& operator<<(TextOutput& to, const String16& val);
+
+// ---------------------------------------------------------------------------
+// No user servicable parts below.
+
+inline int compare_type(const String8& lhs, const String8& rhs)
+{
+    return lhs.compare(rhs);
+}
+
+inline int strictly_order_type(const String8& lhs, const String8& rhs)
+{
+    return compare_type(lhs, rhs) < 0;
+}
+
+inline const char* String8::string() const
+{
+    return mString;
+}
+
+inline size_t String8::length() const
+{
+    return SharedBuffer::sizeFromData(mString)-1;
+}
+
+inline size_t String8::size() const
+{
+    return length();
+}
+
+inline size_t String8::bytes() const
+{
+    return SharedBuffer::sizeFromData(mString)-1;
+}
+
+inline const SharedBuffer* String8::sharedBuffer() const
+{
+    return SharedBuffer::bufferFromData(mString);
+}
+
+inline String8& String8::operator=(const String8& other)
+{
+    setTo(other);
+    return *this;
+}
+
+inline String8& String8::operator=(const char* other)
+{
+    setTo(other);
+    return *this;
+}
+
+inline String8& String8::operator+=(const String8& other)
+{
+    append(other);
+    return *this;
+}
+
+inline String8 String8::operator+(const String8& other) const
+{
+    String8 tmp;
+    tmp += other;
+    return tmp;
+}
+
+inline String8& String8::operator+=(const char* other)
+{
+    append(other);
+    return *this;
+}
+
+inline String8 String8::operator+(const char* other) const
+{
+    String8 tmp;
+    tmp += other;
+    return tmp;
+}
+
+inline int String8::compare(const String8& other) const
+{
+    return strcmp(mString, other.mString);
+}
+
+inline bool String8::operator<(const String8& other) const
+{
+    return strcmp(mString, other.mString) < 0;
+}
+
+inline bool String8::operator<=(const String8& other) const
+{
+    return strcmp(mString, other.mString) <= 0;
+}
+
+inline bool String8::operator==(const String8& other) const
+{
+    return strcmp(mString, other.mString) == 0;
+}
+
+inline bool String8::operator!=(const String8& other) const
+{
+    return strcmp(mString, other.mString) != 0;
+}
+
+inline bool String8::operator>=(const String8& other) const
+{
+    return strcmp(mString, other.mString) >= 0;
+}
+
+inline bool String8::operator>(const String8& other) const
+{
+    return strcmp(mString, other.mString) > 0;
+}
+
+inline bool String8::operator<(const char* other) const
+{
+    return strcmp(mString, other) < 0;
+}
+
+inline bool String8::operator<=(const char* other) const
+{
+    return strcmp(mString, other) <= 0;
+}
+
+inline bool String8::operator==(const char* other) const
+{
+    return strcmp(mString, other) == 0;
+}
+
+inline bool String8::operator!=(const char* other) const
+{
+    return strcmp(mString, other) != 0;
+}
+
+inline bool String8::operator>=(const char* other) const
+{
+    return strcmp(mString, other) >= 0;
+}
+
+inline bool String8::operator>(const char* other) const
+{
+    return strcmp(mString, other) > 0;
+}
+
+inline String8::operator const char*() const
+{
+    return mString;
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STRING8_H
diff --git a/include/utils/SystemClock.h b/include/utils/SystemClock.h
new file mode 100644
index 0000000..7c319be
--- /dev/null
+++ b/include/utils/SystemClock.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_UTILS_SYSTEMCLOCK_H
+#define ANDROID_UTILS_SYSTEMCLOCK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+
+int setCurrentTimeMillis(int64_t millis);
+int64_t uptimeMillis();
+int64_t elapsedRealtime();
+
+}; // namespace android
+
+#endif // ANDROID_UTILS_SYSTEMCLOCK_H
+
diff --git a/include/utils/TextOutput.h b/include/utils/TextOutput.h
new file mode 100644
index 0000000..d8d86ba
--- /dev/null
+++ b/include/utils/TextOutput.h
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_TEXTOUTPUT_H
+#define ANDROID_TEXTOUTPUT_H
+
+#include <utils/Errors.h>
+
+#include <stdint.h>
+#include <string.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class TextOutput
+{
+public:
+                        TextOutput() { }
+    virtual             ~TextOutput() { }
+    
+    virtual status_t    print(const char* txt, size_t len) = 0;
+    virtual void        moveIndent(int delta) = 0;
+    
+    class Bundle {
+    public:
+        inline Bundle(TextOutput& to) : mTO(to) { to.pushBundle(); }
+        inline ~Bundle() { mTO.popBundle(); }
+    private:
+        TextOutput&     mTO;
+    };
+    
+    virtual void        pushBundle() = 0;
+    virtual void        popBundle() = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+// Text output stream for printing to the log (via utils/Log.h).
+extern TextOutput& alog;
+
+// Text output stream for printing to stdout.
+extern TextOutput& aout;
+
+// Text output stream for printing to stderr.
+extern TextOutput& aerr;
+
+typedef TextOutput& (*TextOutputManipFunc)(TextOutput&);
+
+TextOutput& endl(TextOutput& to);
+TextOutput& indent(TextOutput& to);
+TextOutput& dedent(TextOutput& to);
+
+TextOutput& operator<<(TextOutput& to, const char* str);
+TextOutput& operator<<(TextOutput& to, char);     // writes raw character
+TextOutput& operator<<(TextOutput& to, bool);
+TextOutput& operator<<(TextOutput& to, int);
+TextOutput& operator<<(TextOutput& to, long);
+TextOutput& operator<<(TextOutput& to, unsigned int);
+TextOutput& operator<<(TextOutput& to, unsigned long);
+TextOutput& operator<<(TextOutput& to, long long);
+TextOutput& operator<<(TextOutput& to, unsigned long long);
+TextOutput& operator<<(TextOutput& to, float);
+TextOutput& operator<<(TextOutput& to, double);
+TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func);
+TextOutput& operator<<(TextOutput& to, const void*);
+
+class TypeCode 
+{
+public:
+    inline TypeCode(uint32_t code);
+    inline ~TypeCode();
+
+    inline uint32_t typeCode() const;
+    
+private:
+    uint32_t mCode;
+};
+
+TextOutput& operator<<(TextOutput& to, const TypeCode& val);
+
+class HexDump
+{
+public:
+    HexDump(const void *buf, size_t size, size_t bytesPerLine=16);
+    inline ~HexDump();
+    
+    inline HexDump& setBytesPerLine(size_t bytesPerLine);
+    inline HexDump& setSingleLineCutoff(int32_t bytes);
+    inline HexDump& setAlignment(size_t alignment);
+    inline HexDump& setCArrayStyle(bool enabled);
+    
+    inline const void* buffer() const;
+    inline size_t size() const;
+    inline size_t bytesPerLine() const;
+    inline int32_t singleLineCutoff() const;
+    inline size_t alignment() const;
+    inline bool carrayStyle() const;
+
+private:
+    const void* mBuffer;
+    size_t mSize;
+    size_t mBytesPerLine;
+    int32_t mSingleLineCutoff;
+    size_t mAlignment;
+    bool mCArrayStyle;
+};
+
+TextOutput& operator<<(TextOutput& to, const HexDump& val);
+
+// ---------------------------------------------------------------------------
+// No user servicable parts below.
+
+inline TextOutput& endl(TextOutput& to)
+{
+    to.print("\n", 1);
+    return to;
+}
+
+inline TextOutput& indent(TextOutput& to)
+{
+    to.moveIndent(1);
+    return to;
+}
+
+inline TextOutput& dedent(TextOutput& to)
+{
+    to.moveIndent(-1);
+    return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, const char* str)
+{
+    to.print(str, strlen(str));
+    return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, char c)
+{
+    to.print(&c, 1);
+    return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func)
+{
+    return (*func)(to);
+}
+
+inline TypeCode::TypeCode(uint32_t code) : mCode(code) { }
+inline TypeCode::~TypeCode() { }
+inline uint32_t TypeCode::typeCode() const { return mCode; }
+
+inline HexDump::~HexDump() { }
+
+inline HexDump& HexDump::setBytesPerLine(size_t bytesPerLine) {
+    mBytesPerLine = bytesPerLine; return *this;
+}
+inline HexDump& HexDump::setSingleLineCutoff(int32_t bytes) {
+    mSingleLineCutoff = bytes; return *this;
+}
+inline HexDump& HexDump::setAlignment(size_t alignment) {
+    mAlignment = alignment; return *this;
+}
+inline HexDump& HexDump::setCArrayStyle(bool enabled) {
+    mCArrayStyle = enabled; return *this;
+}
+
+inline const void* HexDump::buffer() const { return mBuffer; }
+inline size_t HexDump::size() const { return mSize; }
+inline size_t HexDump::bytesPerLine() const { return mBytesPerLine; }
+inline int32_t HexDump::singleLineCutoff() const { return mSingleLineCutoff; }
+inline size_t HexDump::alignment() const { return mAlignment; }
+inline bool HexDump::carrayStyle() const { return mCArrayStyle; }
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_TEXTOUTPUT_H
diff --git a/include/utils/TimeUtils.h b/include/utils/TimeUtils.h
new file mode 100644
index 0000000..b19e021
--- /dev/null
+++ b/include/utils/TimeUtils.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_TIME_H
+#define ANDROID_TIME_H
+
+#include <time.h>
+#include <cutils/tztime.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+namespace android {
+
+/*
+ * This class is the core implementation of the android.util.Time java
+ * class.  It doesn't implement some of the methods that are implemented
+ * in Java.  They could be done here, but it's not expected that this class
+ * will be used.  If that assumption is incorrect, feel free to update this
+ * file.  The reason to do it here is to not mix the implementation of this
+ * class and the jni glue code.
+ */
+class Time
+{
+public:
+    struct tm t;
+
+    // this object doesn't own this string
+    const char *timezone;
+
+    enum {
+        SEC = 1,
+        MIN = 2,
+        HOUR = 3,
+        MDAY = 4,
+        MON = 5,
+        YEAR = 6,
+        WDAY = 7,
+        YDAY = 8
+    };
+
+    static int compare(Time& a, Time& b);
+
+    Time();
+
+    void switchTimezone(const char *timezone);
+    String8 format(const char *format, const struct strftime_locale *locale) const;
+    void format2445(short* buf, bool hasTime) const;
+    String8 toString() const;
+    void setToNow();
+    int64_t toMillis(bool ignoreDst);
+    void set(int64_t millis);
+
+    inline void set(int sec, int min, int hour, int mday, int mon, int year,
+            int isdst)
+    {
+        this->t.tm_sec = sec;
+        this->t.tm_min = min;
+        this->t.tm_hour = hour;
+        this->t.tm_mday = mday;
+        this->t.tm_mon = mon;
+        this->t.tm_year = year;
+        this->t.tm_isdst = isdst;
+#ifdef HAVE_TM_GMTOFF
+        this->t.tm_gmtoff = 0;
+#endif
+        this->t.tm_wday = 0;
+        this->t.tm_yday = 0;
+    }
+};
+
+}; // namespace android
+
+#endif // ANDROID_TIME_H
diff --git a/include/utils/TimerProbe.h b/include/utils/TimerProbe.h
new file mode 100644
index 0000000..f2e32b2
--- /dev/null
+++ b/include/utils/TimerProbe.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_TIMER_PROBE_H
+#define ANDROID_TIMER_PROBE_H
+
+#if 0 && defined(HAVE_POSIX_CLOCKS)
+#define ENABLE_TIMER_PROBE 1
+#else
+#define ENABLE_TIMER_PROBE 0
+#endif
+
+#if ENABLE_TIMER_PROBE
+
+#include <time.h>
+#include <sys/time.h>
+#include <utils/Vector.h>
+
+#define TIMER_PROBE(tag) \
+    static int _timer_slot_; \
+    android::TimerProbe probe(tag, &_timer_slot_)
+#define TIMER_PROBE_END() probe.end()
+#else
+#define TIMER_PROBE(tag)
+#define TIMER_PROBE_END()
+#endif
+
+#if ENABLE_TIMER_PROBE
+namespace android {
+
+class TimerProbe {
+public:
+    TimerProbe(const char tag[], int* slot);
+    void end();
+    ~TimerProbe();
+private:
+    struct Bucket {
+        int mStart, mReal, mProcess, mThread, mCount;
+        const char* mTag;
+        int* mSlotPtr;
+        int mIndent;
+    };
+    static Vector<Bucket> gBuckets;
+    static TimerProbe* gExecuteChain;
+    static int gIndent;
+    static timespec gRealBase;
+    TimerProbe* mNext;
+    static uint32_t ElapsedTime(const timespec& start, const timespec& end);
+    void print(const timespec& r, const timespec& p, const timespec& t) const;
+    timespec mRealStart, mPStart, mTStart;
+    const char* mTag;
+    int mIndent;
+    int mBucket;
+};
+
+}; // namespace android
+
+#endif
+#endif
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
new file mode 100644
index 0000000..9610399
--- /dev/null
+++ b/include/utils/Timers.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Timer functions.
+//
+#ifndef _LIBS_UTILS_TIMERS_H
+#define _LIBS_UTILS_TIMERS_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+// ------------------------------------------------------------------
+// C API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int64_t nsecs_t;       // nano-seconds
+
+static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs)
+{
+    return secs*1000000000;
+}
+
+static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs)
+{
+    return secs*1000000;
+}
+
+static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs)
+{
+    return secs*1000;
+}
+
+static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs)
+{
+    return secs/1000000000;
+}
+
+static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs)
+{
+    return secs/1000000;
+}
+
+static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs)
+{
+    return secs/1000;
+}
+
+static inline nsecs_t s2ns(nsecs_t v)  {return seconds_to_nanoseconds(v);}
+static inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);}
+static inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);}
+static inline nsecs_t ns2s(nsecs_t v)  {return nanoseconds_to_seconds(v);}
+static inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);}
+static inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);}
+
+static inline nsecs_t seconds(nsecs_t v)      { return s2ns(v); }
+static inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); }
+static inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
+
+enum {
+    SYSTEM_TIME_REALTIME = 0,  // system-wide realtime clock
+    SYSTEM_TIME_MONOTONIC = 1, // monotonic time since unspecified starting point
+    SYSTEM_TIME_PROCESS = 2,   // high-resolution per-process clock
+    SYSTEM_TIME_THREAD = 3     // high-resolution per-thread clock
+};
+    
+// return the system-time according to the specified clock
+#ifdef __cplusplus
+nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC);
+#else
+nsecs_t systemTime(int clock);
+#endif // def __cplusplus
+
+// return the system-time according to the specified clock
+int sleepForInterval(long interval, struct timeval* pNextTick);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+// ------------------------------------------------------------------
+// C++ API
+
+#ifdef __cplusplus
+
+namespace android {
+/*
+ * Time the duration of something.
+ *
+ * Includes some timeval manipulation functions.
+ */
+class DurationTimer {
+public:
+    DurationTimer(void) {}
+    ~DurationTimer(void) {}
+
+    // Start the timer.
+    void start(void);
+    // Stop the timer.
+    void stop(void);
+    // Get the duration in microseconds.
+    long long durationUsecs(void) const;
+
+    // Subtract two timevals.  Returns the difference (ptv1-ptv2) in
+    // microseconds.
+    static long long subtractTimevals(const struct timeval* ptv1,
+        const struct timeval* ptv2);
+
+    // Add the specified amount of time to the timeval.
+    static void addToTimeval(struct timeval* ptv, long usec);
+
+private:
+    struct timeval  mStartWhen;
+    struct timeval  mStopWhen;
+};
+
+}; // android
+#endif // def __cplusplus
+
+#endif // _LIBS_UTILS_TIMERS_H
diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h
new file mode 100644
index 0000000..c04c37f
--- /dev/null
+++ b/include/utils/TypeHelpers.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_TYPE_HELPERS_H
+#define ANDROID_TYPE_HELPERS_H
+
+#include <new>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+/*
+ * Types traits
+ */
+    
+template <typename T> struct trait_trivial_ctor  { enum { value = false }; };
+template <typename T> struct trait_trivial_dtor  { enum { value = false }; };
+template <typename T> struct trait_trivial_copy  { enum { value = false }; };
+template <typename T> struct trait_trivial_assign{ enum { value = false }; };
+
+template <typename T> struct trait_pointer     { enum { value = false }; };    
+template <typename T> struct trait_pointer<T*> { enum { value = true }; };
+
+#define ANDROID_BASIC_TYPES_TRAITS( T )                                       \
+    template<> struct trait_trivial_ctor< T >  { enum { value = true }; };    \
+    template<> struct trait_trivial_dtor< T >  { enum { value = true }; };    \
+    template<> struct trait_trivial_copy< T >  { enum { value = true }; };    \
+    template<> struct trait_trivial_assign< T >{ enum { value = true }; }; 
+
+#define ANDROID_TYPE_TRAITS( T, ctor, dtor, copy, assign )                    \
+    template<> struct trait_trivial_ctor< T >  { enum { value = ctor }; };    \
+    template<> struct trait_trivial_dtor< T >  { enum { value = dtor }; };    \
+    template<> struct trait_trivial_copy< T >  { enum { value = copy }; };    \
+    template<> struct trait_trivial_assign< T >{ enum { value = assign }; }; 
+
+template <typename TYPE>
+struct traits {
+    enum {
+        is_pointer          = trait_pointer<TYPE>::value,
+        has_trivial_ctor    = is_pointer || trait_trivial_ctor<TYPE>::value,
+        has_trivial_dtor    = is_pointer || trait_trivial_dtor<TYPE>::value,
+        has_trivial_copy    = is_pointer || trait_trivial_copy<TYPE>::value,
+        has_trivial_assign  = is_pointer || trait_trivial_assign<TYPE>::value   
+    };
+};
+
+template <typename T, typename U>
+struct aggregate_traits {
+    enum {
+        is_pointer          = false,
+        has_trivial_ctor    = traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
+        has_trivial_dtor    = traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
+        has_trivial_copy    = traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
+        has_trivial_assign  = traits<T>::has_trivial_assign && traits<U>::has_trivial_assign
+    };
+};
+
+// ---------------------------------------------------------------------------
+
+/*
+ * basic types traits
+ */
+ 
+ANDROID_BASIC_TYPES_TRAITS( void );
+ANDROID_BASIC_TYPES_TRAITS( bool );
+ANDROID_BASIC_TYPES_TRAITS( char );
+ANDROID_BASIC_TYPES_TRAITS( unsigned char );
+ANDROID_BASIC_TYPES_TRAITS( short );
+ANDROID_BASIC_TYPES_TRAITS( unsigned short );
+ANDROID_BASIC_TYPES_TRAITS( int );
+ANDROID_BASIC_TYPES_TRAITS( unsigned int );
+ANDROID_BASIC_TYPES_TRAITS( long );
+ANDROID_BASIC_TYPES_TRAITS( unsigned long );
+ANDROID_BASIC_TYPES_TRAITS( long long );
+ANDROID_BASIC_TYPES_TRAITS( unsigned long long );
+ANDROID_BASIC_TYPES_TRAITS( float );
+ANDROID_BASIC_TYPES_TRAITS( double );
+
+// ---------------------------------------------------------------------------
+
+    
+/*
+ * compare and order types
+ */
+
+template<typename TYPE> inline
+int strictly_order_type(const TYPE& lhs, const TYPE& rhs) {
+    return (lhs < rhs) ? 1 : 0;
+}
+
+template<typename TYPE> inline
+int compare_type(const TYPE& lhs, const TYPE& rhs) {
+    return strictly_order_type(rhs, lhs) - strictly_order_type(lhs, rhs);
+}
+
+/*
+ * create, destroy, copy and assign types...
+ */
+ 
+template<typename TYPE> inline
+void construct_type(TYPE* p, size_t n) {
+    if (!traits<TYPE>::has_trivial_ctor) {
+        while (n--) {
+            new(p++) TYPE;
+        }
+    }
+}
+
+template<typename TYPE> inline
+void destroy_type(TYPE* p, size_t n) {
+    if (!traits<TYPE>::has_trivial_dtor) {
+        while (n--) {
+            p->~TYPE();
+            p++;
+        }
+    }
+}
+
+template<typename TYPE> inline
+void copy_type(TYPE* d, const TYPE* s, size_t n) {
+    if (!traits<TYPE>::has_trivial_copy) {
+        while (n--) {
+            new(d) TYPE(*s);
+            d++, s++;
+        }
+    } else {
+        memcpy(d,s,n*sizeof(TYPE));
+    }
+}
+
+template<typename TYPE> inline
+void assign_type(TYPE* d, const TYPE* s, size_t n) {
+    if (!traits<TYPE>::has_trivial_assign) {
+        while (n--) {
+            *d++ = *s++;
+        }
+    } else {
+        memcpy(d,s,n*sizeof(TYPE));
+    }
+}
+
+template<typename TYPE> inline
+void splat_type(TYPE* where, const TYPE* what, size_t n) {
+    if (!traits<TYPE>::has_trivial_copy) {
+        while (n--) {
+            new(where) TYPE(*what);
+            where++;
+        }
+    } else {
+         while (n--) {
+             *where++ = *what;
+        }
+    }
+}
+
+template<typename TYPE> inline
+void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
+    if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
+        d += n;
+        s += n;
+        while (n--) {
+            --d, --s;
+            if (!traits<TYPE>::has_trivial_copy) {
+                new(d) TYPE(*s);
+            } else {
+                *d = *s;
+            }
+            if (!traits<TYPE>::has_trivial_dtor) {
+                s->~TYPE();
+            }
+        }
+    } else {
+        memmove(d,s,n*sizeof(TYPE));
+    }
+}
+
+template<typename TYPE> inline
+void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
+    if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
+        while (n--) {
+            if (!traits<TYPE>::has_trivial_copy) {
+                new(d) TYPE(*s);
+            } else {
+                *d = *s;
+            }
+            if (!traits<TYPE>::has_trivial_dtor) {
+                s->~TYPE();
+            }
+            d++, s++;
+        }
+    } else {
+        memmove(d,s,n*sizeof(TYPE));
+    }
+}
+// ---------------------------------------------------------------------------
+
+/*
+ * a key/value pair
+ */
+
+template <typename KEY, typename VALUE>
+struct key_value_pair_t {
+    KEY     key;
+    VALUE   value;
+    key_value_pair_t() { }
+    key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) { }
+    key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v)  { }
+    key_value_pair_t(const KEY& k) : key(k) { }
+    inline bool operator < (const key_value_pair_t& o) const {
+        return strictly_order_type(key, o.key);
+    }
+};
+
+template<>
+template <typename K, typename V>
+struct trait_trivial_ctor< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_ctor }; };
+template<> 
+template <typename K, typename V>
+struct trait_trivial_dtor< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_dtor }; };
+template<> 
+template <typename K, typename V>
+struct trait_trivial_copy< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
+template<> 
+template <typename K, typename V>
+struct trait_trivial_assign< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_assign};};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_TYPE_HELPERS_H
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
new file mode 100644
index 0000000..be365d8
--- /dev/null
+++ b/include/utils/Vector.h
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_VECTOR_H
+#define ANDROID_VECTOR_H
+
+#include <new>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Log.h>
+#include <utils/VectorImpl.h>
+#include <utils/TypeHelpers.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+/*!
+ * The main templated vector class ensuring type safety
+ * while making use of VectorImpl.
+ * This is the class users want to use.
+ */
+
+template <class TYPE>
+class Vector : private VectorImpl
+{
+public:
+            typedef TYPE    value_type;
+    
+    /*! 
+     * Constructors and destructors
+     */
+    
+                            Vector();
+                            Vector(const Vector<TYPE>& rhs);
+    virtual                 ~Vector();
+
+    /*! copy operator */
+            const Vector<TYPE>&     operator = (const Vector<TYPE>& rhs) const;
+            Vector<TYPE>&           operator = (const Vector<TYPE>& rhs);    
+
+    /*
+     * empty the vector
+     */
+
+    inline  void            clear()             { VectorImpl::clear(); }
+
+    /*! 
+     * vector stats
+     */
+
+    //! returns number of items in the vector
+    inline  size_t          size() const                { return VectorImpl::size(); }
+    //! returns wether or not the vector is empty
+    inline  bool            isEmpty() const             { return VectorImpl::isEmpty(); }
+    //! returns how many items can be stored without reallocating the backing store
+    inline  size_t          capacity() const            { return VectorImpl::capacity(); }
+    //! setst the capacity. capacity can never be reduced less than size()
+    inline  ssize_t         setCapacity(size_t size)    { return VectorImpl::setCapacity(size); }
+
+    /*! 
+     * C-style array access
+     */
+     
+    //! read-only C-style access 
+    inline  const TYPE*     array() const;
+    //! read-write C-style access
+            TYPE*           editArray();
+    
+    /*! 
+     * accessors
+     */
+
+    //! read-only access to an item at a given index
+    inline  const TYPE&     operator [] (size_t index) const;
+    //! alternate name for operator []
+    inline  const TYPE&     itemAt(size_t index) const;
+    //! stack-usage of the vector. returns the top of the stack (last element)
+            const TYPE&     top() const;
+    //! same as operator [], but allows to access the vector backward (from the end) with a negative index
+            const TYPE&     mirrorItemAt(ssize_t index) const;
+
+    /*!
+     * modifing the array
+     */
+
+    //! copy-on write support, grants write access to an item
+            TYPE&           editItemAt(size_t index);
+    //! grants right acces to the top of the stack (last element)
+            TYPE&           editTop();
+
+            /*! 
+             * append/insert another vector
+             */
+            
+    //! insert another vector at a given index
+            ssize_t         insertVectorAt(const Vector<TYPE>& vector, size_t index);
+
+    //! append another vector at the end of this one
+            ssize_t         appendVector(const Vector<TYPE>& vector);
+
+
+            /*! 
+             * add/insert/replace items
+             */
+             
+    //! insert one or several items initialized with their default constructor
+    inline  ssize_t         insertAt(size_t index, size_t numItems = 1);
+    //! insert on onr several items initialized from a prototype item
+            ssize_t         insertAt(const TYPE& prototype_item, size_t index, size_t numItems = 1);
+    //! pop the top of the stack (removes the last element). No-op if the stack's empty
+    inline  void            pop();
+    //! pushes an item initialized with its default constructor
+    inline  void            push();
+    //! pushes an item on the top of the stack
+            void            push(const TYPE& item);
+    //! same as push() but returns the index the item was added at (or an error)
+    inline  ssize_t         add();
+    //! same as push() but returns the index the item was added at (or an error)
+            ssize_t         add(const TYPE& item);            
+    //! replace an item with a new one initialized with its default constructor
+    inline  ssize_t         replaceAt(size_t index);
+    //! replace an item with a new one
+            ssize_t         replaceAt(const TYPE& item, size_t index);
+
+    /*!
+     * remove items
+     */
+
+    //! remove several items
+    inline  ssize_t         removeItemsAt(size_t index, size_t count = 1);
+    //! remove one item
+    inline  ssize_t         removeAt(size_t index)  { return removeItemsAt(index); }
+
+    /*!
+     * sort (stable) the array
+     */
+     
+     typedef int (*compar_t)(const TYPE* lhs, const TYPE* rhs);
+     typedef int (*compar_r_t)(const TYPE* lhs, const TYPE* rhs, void* state);
+     
+     inline status_t        sort(compar_t cmp);
+     inline status_t        sort(compar_r_t cmp, void* state);
+
+protected:
+    virtual void    do_construct(void* storage, size_t num) const;
+    virtual void    do_destroy(void* storage, size_t num) const;
+    virtual void    do_copy(void* dest, const void* from, size_t num) const;
+    virtual void    do_splat(void* dest, const void* item, size_t num) const;
+    virtual void    do_move_forward(void* dest, const void* from, size_t num) const;
+    virtual void    do_move_backward(void* dest, const void* from, size_t num) const;
+};
+
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts from here...
+// ---------------------------------------------------------------------------
+
+template<class TYPE> inline
+Vector<TYPE>::Vector()
+    : VectorImpl(sizeof(TYPE),
+                ((traits<TYPE>::has_trivial_ctor   ? HAS_TRIVIAL_CTOR   : 0)
+                |(traits<TYPE>::has_trivial_dtor   ? HAS_TRIVIAL_DTOR   : 0)
+                |(traits<TYPE>::has_trivial_copy   ? HAS_TRIVIAL_COPY   : 0)
+                |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
+                )
+{
+}
+
+template<class TYPE> inline
+Vector<TYPE>::Vector(const Vector<TYPE>& rhs)
+    : VectorImpl(rhs) {
+}
+
+template<class TYPE> inline
+Vector<TYPE>::~Vector() {
+    finish_vector();
+}
+
+template<class TYPE> inline
+Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) {
+    VectorImpl::operator = (rhs);
+    return *this; 
+}
+
+template<class TYPE> inline
+const Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) const {
+    VectorImpl::operator = (rhs);
+    return *this; 
+}
+
+template<class TYPE> inline
+const TYPE* Vector<TYPE>::array() const {
+    return static_cast<const TYPE *>(arrayImpl());
+}
+
+template<class TYPE> inline
+TYPE* Vector<TYPE>::editArray() {
+    return static_cast<TYPE *>(editArrayImpl());
+}
+
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::operator[](size_t index) const {
+    LOG_FATAL_IF( index>=size(),
+                  "itemAt: index %d is past size %d", (int)index, (int)size() );
+    return *(array() + index);
+}
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::itemAt(size_t index) const {
+    return operator[](index);
+}
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::mirrorItemAt(ssize_t index) const {
+    LOG_FATAL_IF( (index>0 ? index : -index)>=size(),
+                  "mirrorItemAt: index %d is past size %d",
+                  (int)index, (int)size() );
+    return *(array() + ((index<0) ? (size()-index) : index));
+}
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::top() const {
+    return *(array() + size() - 1);
+}
+
+template<class TYPE> inline
+TYPE& Vector<TYPE>::editItemAt(size_t index) {
+    return *( static_cast<TYPE *>(editItemLocation(index)) );
+}
+
+template<class TYPE> inline
+TYPE& Vector<TYPE>::editTop() {
+    return *( static_cast<TYPE *>(editItemLocation(size()-1)) );
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertVectorAt(const Vector<TYPE>& vector, size_t index) {
+    return VectorImpl::insertVectorAt(reinterpret_cast<const VectorImpl&>(vector), index);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::appendVector(const Vector<TYPE>& vector) {
+    return VectorImpl::appendVector(reinterpret_cast<const VectorImpl&>(vector));
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertAt(const TYPE& item, size_t index, size_t numItems) {
+    return VectorImpl::insertAt(&item, index, numItems);
+}
+
+template<class TYPE> inline
+void Vector<TYPE>::push(const TYPE& item) {
+    return VectorImpl::push(&item);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::add(const TYPE& item) {
+    return VectorImpl::add(&item);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::replaceAt(const TYPE& item, size_t index) {
+    return VectorImpl::replaceAt(&item, index);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertAt(size_t index, size_t numItems) {
+    return VectorImpl::insertAt(index, numItems);
+}
+
+template<class TYPE> inline
+void Vector<TYPE>::pop() {
+    VectorImpl::pop();
+}
+
+template<class TYPE> inline
+void Vector<TYPE>::push() {
+    VectorImpl::push();
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::add() {
+    return VectorImpl::add();
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::replaceAt(size_t index) {
+    return VectorImpl::replaceAt(index);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::removeItemsAt(size_t index, size_t count) {
+    return VectorImpl::removeItemsAt(index, count);
+}
+
+template<class TYPE> inline
+status_t Vector<TYPE>::sort(Vector<TYPE>::compar_t cmp) {
+    return VectorImpl::sort((VectorImpl::compar_t)cmp);
+}
+
+template<class TYPE> inline
+status_t Vector<TYPE>::sort(Vector<TYPE>::compar_r_t cmp, void* state) {
+    return VectorImpl::sort((VectorImpl::compar_r_t)cmp, state);
+}
+
+// ---------------------------------------------------------------------------
+
+template<class TYPE>
+void Vector<TYPE>::do_construct(void* storage, size_t num) const {
+    construct_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_destroy(void* storage, size_t num) const {
+    destroy_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
+    copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
+    splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
+    move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
+    move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_VECTOR_H
diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h
new file mode 100644
index 0000000..2525229
--- /dev/null
+++ b/include/utils/VectorImpl.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef ANDROID_VECTOR_IMPL_H
+#define ANDROID_VECTOR_IMPL_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts in here...
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+/*!
+ * Implementation of the guts of the vector<> class
+ * this ensures backward binary compatibility and
+ * reduces code size.
+ * For performance reasons, we expose mStorage and mCount
+ * so these fields are set in stone.
+ *
+ */
+
+class VectorImpl
+{
+public:
+    enum { // flags passed to the ctor
+        HAS_TRIVIAL_CTOR    = 0x00000001,
+        HAS_TRIVIAL_DTOR    = 0x00000002,
+        HAS_TRIVIAL_COPY    = 0x00000004,
+        HAS_TRIVIAL_ASSIGN  = 0x00000008
+    };
+
+                            VectorImpl(size_t itemSize, uint32_t flags);
+                            VectorImpl(const VectorImpl& rhs);
+    virtual                 ~VectorImpl();
+
+    /*! must be called from subclasses destructor */
+            void            finish_vector();
+
+            VectorImpl&     operator = (const VectorImpl& rhs);    
+            
+    /*! C-style array access */
+    inline  const void*     arrayImpl() const       { return mStorage; }
+            void*           editArrayImpl();
+            
+    /*! vector stats */
+    inline  size_t          size() const        { return mCount; }
+    inline  bool            isEmpty() const     { return mCount == 0; }
+            size_t          capacity() const;
+            ssize_t         setCapacity(size_t size);
+
+            /*! append/insert another vector */
+            ssize_t         insertVectorAt(const VectorImpl& vector, size_t index);
+            ssize_t         appendVector(const VectorImpl& vector);
+            
+            /*! add/insert/replace items */
+            ssize_t         insertAt(size_t where, size_t numItems = 1);
+            ssize_t         insertAt(const void* item, size_t where, size_t numItems = 1);
+            void            pop();
+            void            push();
+            void            push(const void* item);
+            ssize_t         add();
+            ssize_t         add(const void* item);
+            ssize_t         replaceAt(size_t index);
+            ssize_t         replaceAt(const void* item, size_t index);
+
+            /*! remove items */
+            ssize_t         removeItemsAt(size_t index, size_t count = 1);
+            void            clear();
+
+            const void*     itemLocation(size_t index) const;
+            void*           editItemLocation(size_t index);
+
+            typedef int (*compar_t)(const void* lhs, const void* rhs);
+            typedef int (*compar_r_t)(const void* lhs, const void* rhs, void* state);
+            status_t        sort(compar_t cmp);
+            status_t        sort(compar_r_t cmp, void* state);
+
+protected:
+            size_t          itemSize() const;
+            void            release_storage();
+
+    virtual void            do_construct(void* storage, size_t num) const = 0;
+    virtual void            do_destroy(void* storage, size_t num) const = 0;
+    virtual void            do_copy(void* dest, const void* from, size_t num) const = 0;
+    virtual void            do_splat(void* dest, const void* item, size_t num) const = 0;
+    virtual void            do_move_forward(void* dest, const void* from, size_t num) const = 0;
+    virtual void            do_move_backward(void* dest, const void* from, size_t num) const = 0;
+
+    // take care of FBC...
+    virtual void            reservedVectorImpl1();
+    virtual void            reservedVectorImpl2();
+    virtual void            reservedVectorImpl3();
+    virtual void            reservedVectorImpl4();
+    virtual void            reservedVectorImpl5();
+    virtual void            reservedVectorImpl6();
+    virtual void            reservedVectorImpl7();
+    virtual void            reservedVectorImpl8();
+    
+private:
+        void* _grow(size_t where, size_t amount);
+        void  _shrink(size_t where, size_t amount);
+
+        inline void _do_construct(void* storage, size_t num) const;
+        inline void _do_destroy(void* storage, size_t num) const;
+        inline void _do_copy(void* dest, const void* from, size_t num) const;
+        inline void _do_splat(void* dest, const void* item, size_t num) const;
+        inline void _do_move_forward(void* dest, const void* from, size_t num) const;
+        inline void _do_move_backward(void* dest, const void* from, size_t num) const;
+
+            // These 2 fields are exposed in the inlines below,
+            // so they're set in stone.
+            void *      mStorage;   // base address of the vector
+            size_t      mCount;     // number of items
+
+    const   uint32_t    mFlags;
+    const   size_t      mItemSize;
+};
+
+
+
+class SortedVectorImpl : public VectorImpl
+{
+public:
+                            SortedVectorImpl(size_t itemSize, uint32_t flags);
+                            SortedVectorImpl(const VectorImpl& rhs);
+    virtual                 ~SortedVectorImpl();
+    
+    SortedVectorImpl&     operator = (const SortedVectorImpl& rhs);    
+
+    //! finds the index of an item
+            ssize_t         indexOf(const void* item) const;
+
+    //! finds where this item should be inserted
+            size_t          orderOf(const void* item) const;
+
+    //! add an item in the right place (or replaces it if there is one)
+            ssize_t         add(const void* item);
+
+    //! merges a vector into this one
+            ssize_t         merge(const VectorImpl& vector);
+            ssize_t         merge(const SortedVectorImpl& vector);
+             
+    //! removes an item
+            ssize_t         remove(const void* item);
+        
+protected:
+    virtual int             do_compare(const void* lhs, const void* rhs) const = 0;
+
+    // take care of FBC...
+    virtual void            reservedSortedVectorImpl1();
+    virtual void            reservedSortedVectorImpl2();
+    virtual void            reservedSortedVectorImpl3();
+    virtual void            reservedSortedVectorImpl4();
+    virtual void            reservedSortedVectorImpl5();
+    virtual void            reservedSortedVectorImpl6();
+    virtual void            reservedSortedVectorImpl7();
+    virtual void            reservedSortedVectorImpl8();
+
+private:
+            ssize_t         _indexOrderOf(const void* item, size_t* order = 0) const;
+
+            // these are made private, because they can't be used on a SortedVector
+            // (they don't have an implementation either)
+            ssize_t         add();
+            void            pop();
+            void            push();
+            void            push(const void* item);
+            ssize_t         insertVectorAt(const VectorImpl& vector, size_t index);
+            ssize_t         appendVector(const VectorImpl& vector);
+            ssize_t         insertAt(size_t where, size_t numItems = 1);
+            ssize_t         insertAt(const void* item, size_t where, size_t numItems = 1);
+            ssize_t         replaceAt(size_t index);
+            ssize_t         replaceAt(const void* item, size_t index);
+};
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_VECTOR_IMPL_H
diff --git a/include/utils/ZipEntry.h b/include/utils/ZipEntry.h
new file mode 100644
index 0000000..e4698df
--- /dev/null
+++ b/include/utils/ZipEntry.h
@@ -0,0 +1,345 @@
+/*
+ * 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.
+ */
+
+//
+// Zip archive entries.
+//
+// The ZipEntry class is tightly meshed with the ZipFile class.
+//
+#ifndef __LIBS_ZIPENTRY_H
+#define __LIBS_ZIPENTRY_H
+
+#include "Errors.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+namespace android {
+
+class ZipFile;
+
+/*
+ * ZipEntry objects represent a single entry in a Zip archive.
+ *
+ * You can use one of these to get or set information about an entry, but
+ * there are no functions here for accessing the data itself.  (We could
+ * tuck a pointer to the ZipFile in here for convenience, but that raises
+ * the likelihood of using ZipEntry objects after discarding the ZipFile.)
+ *
+ * File information is stored in two places: next to the file data (the Local
+ * File Header, and possibly a Data Descriptor), and at the end of the file
+ * (the Central Directory Entry).  The two must be kept in sync.
+ */
+class ZipEntry {
+public:
+    friend class ZipFile;
+
+    ZipEntry(void)
+        : mDeleted(false), mMarked(false)
+        {}
+    ~ZipEntry(void) {}
+
+    /*
+     * Returns "true" if the data is compressed.
+     */
+    bool isCompressed(void) const {
+        return mCDE.mCompressionMethod != kCompressStored;
+    }
+    int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
+
+    /*
+     * Return the uncompressed length.
+     */
+    off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
+
+    /*
+     * Return the compressed length.  For uncompressed data, this returns
+     * the same thing as getUncompresesdLen().
+     */
+    off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
+
+    /*
+     * Return the absolute file offset of the start of the compressed or
+     * uncompressed data.
+     */
+    off_t getFileOffset(void) const {
+        return mCDE.mLocalHeaderRelOffset +
+                LocalFileHeader::kLFHLen +
+                mLFH.mFileNameLength +
+                mLFH.mExtraFieldLength;
+    }
+
+    /*
+     * Return the data CRC.
+     */
+    unsigned long getCRC32(void) const { return mCDE.mCRC32; }
+
+    /*
+     * Return file modification time in UNIX seconds-since-epoch.
+     */
+    time_t getModWhen(void) const;
+
+    /*
+     * Return the archived file name.
+     */
+    const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
+
+    /*
+     * Application-defined "mark".  Can be useful when synchronizing the
+     * contents of an archive with contents on disk.
+     */
+    bool getMarked(void) const { return mMarked; }
+    void setMarked(bool val) { mMarked = val; }
+
+    /*
+     * Some basic functions for raw data manipulation.  "LE" means
+     * Little Endian.
+     */
+    static inline unsigned short getShortLE(const unsigned char* buf) {
+        return buf[0] | (buf[1] << 8);
+    }
+    static inline unsigned long getLongLE(const unsigned char* buf) {
+        return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+    }
+    static inline void putShortLE(unsigned char* buf, short val) {
+        buf[0] = (unsigned char) val;
+        buf[1] = (unsigned char) (val >> 8);
+    }
+    static inline void putLongLE(unsigned char* buf, long val) {
+        buf[0] = (unsigned char) val;
+        buf[1] = (unsigned char) (val >> 8);
+        buf[2] = (unsigned char) (val >> 16);
+        buf[3] = (unsigned char) (val >> 24);
+    }
+
+    /* defined for Zip archives */
+    enum {
+        kCompressStored     = 0,        // no compression
+        // shrunk           = 1,
+        // reduced 1        = 2,
+        // reduced 2        = 3,
+        // reduced 3        = 4,
+        // reduced 4        = 5,
+        // imploded         = 6,
+        // tokenized        = 7,
+        kCompressDeflated   = 8,        // standard deflate
+        // Deflate64        = 9,
+        // lib imploded     = 10,
+        // reserved         = 11,
+        // bzip2            = 12,
+    };
+
+    /*
+     * Deletion flag.  If set, the entry will be removed on the next
+     * call to "flush".
+     */
+    bool getDeleted(void) const { return mDeleted; }
+
+protected:
+    /*
+     * Initialize the structure from the file, which is pointing at
+     * our Central Directory entry.
+     */
+    status_t initFromCDE(FILE* fp);
+
+    /*
+     * Initialize the structure for a new file.  We need the filename
+     * and comment so that we can properly size the LFH area.  The
+     * filename is mandatory, the comment is optional.
+     */
+    void initNew(const char* fileName, const char* comment);
+
+    /*
+     * Initialize the structure with the contents of a ZipEntry from
+     * another file.
+     */
+    status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
+
+    /*
+     * Add some pad bytes to the LFH.  We do this by adding or resizing
+     * the "extra" field.
+     */
+    status_t addPadding(int padding);
+
+    /*
+     * Set information about the data for this entry.
+     */
+    void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+        int compressionMethod);
+
+    /*
+     * Set the modification date.
+     */
+    void setModWhen(time_t when);
+
+    /*
+     * Return the offset of the local file header.
+     */
+    off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
+
+    /*
+     * Set the offset of the local file header, relative to the start of
+     * the current file.
+     */
+    void setLFHOffset(off_t offset) {
+        mCDE.mLocalHeaderRelOffset = (long) offset;
+    }
+
+    /* mark for deletion; used by ZipFile::remove() */
+    void setDeleted(void) { mDeleted = true; }
+
+private:
+    /* these are private and not defined */
+    ZipEntry(const ZipEntry& src);
+    ZipEntry& operator=(const ZipEntry& src);
+
+    /* returns "true" if the CDE and the LFH agree */
+    bool compareHeaders(void) const;
+    void copyCDEtoLFH(void);
+
+    bool        mDeleted;       // set if entry is pending deletion
+    bool        mMarked;        // app-defined marker
+
+    /*
+     * Every entry in the Zip archive starts off with one of these.
+     */
+    class LocalFileHeader {
+    public:
+        LocalFileHeader(void) :
+            mVersionToExtract(0),
+            mGPBitFlag(0),
+            mCompressionMethod(0),
+            mLastModFileTime(0),
+            mLastModFileDate(0),
+            mCRC32(0),
+            mCompressedSize(0),
+            mUncompressedSize(0),
+            mFileNameLength(0),
+            mExtraFieldLength(0),
+            mFileName(NULL),
+            mExtraField(NULL)
+        {}
+        virtual ~LocalFileHeader(void) {
+            delete[] mFileName;
+            delete[] mExtraField;
+        }
+
+        status_t read(FILE* fp);
+        status_t write(FILE* fp);
+
+        // unsigned long mSignature;
+        unsigned short  mVersionToExtract;
+        unsigned short  mGPBitFlag;
+        unsigned short  mCompressionMethod;
+        unsigned short  mLastModFileTime;
+        unsigned short  mLastModFileDate;
+        unsigned long   mCRC32;
+        unsigned long   mCompressedSize;
+        unsigned long   mUncompressedSize;
+        unsigned short  mFileNameLength;
+        unsigned short  mExtraFieldLength;
+        unsigned char*  mFileName;
+        unsigned char*  mExtraField;
+
+        enum {
+            kSignature      = 0x04034b50,
+            kLFHLen         = 30,       // LocalFileHdr len, excl. var fields
+        };
+
+        void dump(void) const;
+    };
+
+    /*
+     * Every entry in the Zip archive has one of these in the "central
+     * directory" at the end of the file.
+     */
+    class CentralDirEntry {
+    public:
+        CentralDirEntry(void) :
+            mVersionMadeBy(0),
+            mVersionToExtract(0),
+            mGPBitFlag(0),
+            mCompressionMethod(0),
+            mLastModFileTime(0),
+            mLastModFileDate(0),
+            mCRC32(0),
+            mCompressedSize(0),
+            mUncompressedSize(0),
+            mFileNameLength(0),
+            mExtraFieldLength(0),
+            mFileCommentLength(0),
+            mDiskNumberStart(0),
+            mInternalAttrs(0),
+            mExternalAttrs(0),
+            mLocalHeaderRelOffset(0),
+            mFileName(NULL),
+            mExtraField(NULL),
+            mFileComment(NULL)
+        {}
+        virtual ~CentralDirEntry(void) {
+            delete[] mFileName;
+            delete[] mExtraField;
+            delete[] mFileComment;
+        }
+
+        status_t read(FILE* fp);
+        status_t write(FILE* fp);
+
+        // unsigned long mSignature;
+        unsigned short  mVersionMadeBy;
+        unsigned short  mVersionToExtract;
+        unsigned short  mGPBitFlag;
+        unsigned short  mCompressionMethod;
+        unsigned short  mLastModFileTime;
+        unsigned short  mLastModFileDate;
+        unsigned long   mCRC32;
+        unsigned long   mCompressedSize;
+        unsigned long   mUncompressedSize;
+        unsigned short  mFileNameLength;
+        unsigned short  mExtraFieldLength;
+        unsigned short  mFileCommentLength;
+        unsigned short  mDiskNumberStart;
+        unsigned short  mInternalAttrs;
+        unsigned long   mExternalAttrs;
+        unsigned long   mLocalHeaderRelOffset;
+        unsigned char*  mFileName;
+        unsigned char*  mExtraField;
+        unsigned char*  mFileComment;
+
+        void dump(void) const;
+
+        enum {
+            kSignature      = 0x02014b50,
+            kCDELen         = 46,       // CentralDirEnt len, excl. var fields
+        };
+    };
+
+    enum {
+        //kDataDescriptorSignature  = 0x08074b50,   // currently unused
+        kDataDescriptorLen  = 16,           // four 32-bit fields
+
+        kDefaultVersion     = 20,           // need deflate, nothing much else
+        kDefaultMadeBy      = 0x0317,       // 03=UNIX, 17=spec v2.3
+        kUsesDataDescr      = 0x0008,       // GPBitFlag bit 3
+    };
+
+    LocalFileHeader     mLFH;
+    CentralDirEntry     mCDE;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPENTRY_H
diff --git a/include/utils/ZipFile.h b/include/utils/ZipFile.h
new file mode 100644
index 0000000..44df5bb
--- /dev/null
+++ b/include/utils/ZipFile.h
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ */
+
+//
+// General-purpose Zip archive access.  This class allows both reading and
+// writing to Zip archives, including deletion of existing entries.
+//
+#ifndef __LIBS_ZIPFILE_H
+#define __LIBS_ZIPFILE_H
+
+#include "ZipEntry.h"
+#include "Vector.h"
+#include "Errors.h"
+#include <stdio.h>
+
+namespace android {
+
+/*
+ * Manipulate a Zip archive.
+ *
+ * Some changes will not be visible in the until until "flush" is called.
+ *
+ * The correct way to update a file archive is to make all changes to a
+ * copy of the archive in a temporary file, and then unlink/rename over
+ * the original after everything completes.  Because we're only interested
+ * in using this for packaging, we don't worry about such things.  Crashing
+ * after making changes and before flush() completes could leave us with
+ * an unusable Zip archive.
+ */
+class ZipFile {
+public:
+    ZipFile(void)
+      : mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
+      {}
+    ~ZipFile(void) {
+        if (!mReadOnly)
+            flush();
+        if (mZipFp != NULL)
+            fclose(mZipFp);
+        discardEntries();
+    }
+
+    /*
+     * Open a new or existing archive.
+     */
+    typedef enum {
+        kOpenReadOnly   = 0x01,
+        kOpenReadWrite  = 0x02,
+        kOpenCreate     = 0x04,     // create if it doesn't exist
+        kOpenTruncate   = 0x08,     // if it exists, empty it
+    };
+    status_t open(const char* zipFileName, int flags);
+
+    /*
+     * Add a file to the end of the archive.  Specify whether you want the
+     * library to try to store it compressed.
+     *
+     * If "storageName" is specified, the archive will use that instead
+     * of "fileName".
+     *
+     * If there is already an entry with the same name, the call fails.
+     * Existing entries with the same name must be removed first.
+     *
+     * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+     */
+    status_t add(const char* fileName, int compressionMethod,
+        ZipEntry** ppEntry)
+    {
+        return add(fileName, fileName, compressionMethod, ppEntry);
+    }
+    status_t add(const char* fileName, const char* storageName,
+        int compressionMethod, ZipEntry** ppEntry)
+    {
+        return addCommon(fileName, NULL, 0, storageName,
+                         ZipEntry::kCompressStored,
+                         compressionMethod, ppEntry);
+    }
+
+    /*
+     * Add a file that is already compressed with gzip.
+     *
+     * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+     */
+    status_t addGzip(const char* fileName, const char* storageName,
+        ZipEntry** ppEntry)
+    {
+        return addCommon(fileName, NULL, 0, storageName,
+                         ZipEntry::kCompressDeflated,
+                         ZipEntry::kCompressDeflated, ppEntry);
+    }
+
+    /*
+     * Add a file from an in-memory data buffer.
+     *
+     * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+     */
+    status_t add(const void* data, size_t size, const char* storageName,
+        int compressionMethod, ZipEntry** ppEntry)
+    {
+        return addCommon(NULL, data, size, storageName,
+                         ZipEntry::kCompressStored,
+                         compressionMethod, ppEntry);
+    }
+
+    /*
+     * Add an entry by copying it from another zip file.  If "padding" is
+     * nonzero, the specified number of bytes will be added to the "extra"
+     * field in the header.
+     *
+     * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+     */
+    status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+        int padding, ZipEntry** ppEntry);
+
+    /*
+     * Mark an entry as having been removed.  It is not actually deleted
+     * from the archive or our internal data structures until flush() is
+     * called.
+     */
+    status_t remove(ZipEntry* pEntry);
+
+    /*
+     * Flush changes.  If mNeedCDRewrite is set, this writes the central dir.
+     */
+    status_t flush(void);
+
+    /*
+     * Expand the data into the buffer provided.  The buffer must hold
+     * at least <uncompressed len> bytes.  Variation expands directly
+     * to a file.
+     *
+     * Returns "false" if an error was encountered in the compressed data.
+     */
+    //bool uncompress(const ZipEntry* pEntry, void* buf) const;
+    //bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
+    void* uncompress(const ZipEntry* pEntry);
+
+    /*
+     * Get an entry, by name.  Returns NULL if not found.
+     *
+     * Does not return entries pending deletion.
+     */
+    ZipEntry* getEntryByName(const char* fileName) const;
+
+    /*
+     * Get the Nth entry in the archive.
+     *
+     * This will return an entry that is pending deletion.
+     */
+    int getNumEntries(void) const { return mEntries.size(); }
+    ZipEntry* getEntryByIndex(int idx) const;
+
+private:
+    /* these are private and not defined */
+    ZipFile(const ZipFile& src);
+    ZipFile& operator=(const ZipFile& src);
+
+    class EndOfCentralDir {
+    public:
+        EndOfCentralDir(void) :
+            mDiskNumber(0),
+            mDiskWithCentralDir(0),
+            mNumEntries(0),
+            mTotalNumEntries(0),
+            mCentralDirSize(0),
+            mCentralDirOffset(0),
+            mCommentLen(0),
+            mComment(NULL)
+            {}
+        virtual ~EndOfCentralDir(void) {
+            delete[] mComment;
+        }
+
+        status_t readBuf(const unsigned char* buf, int len);
+        status_t write(FILE* fp);
+
+        //unsigned long   mSignature;
+        unsigned short  mDiskNumber;
+        unsigned short  mDiskWithCentralDir;
+        unsigned short  mNumEntries;
+        unsigned short  mTotalNumEntries;
+        unsigned long   mCentralDirSize;
+        unsigned long   mCentralDirOffset;      // offset from first disk
+        unsigned short  mCommentLen;
+        unsigned char*  mComment;
+
+        enum {
+            kSignature      = 0x06054b50,
+            kEOCDLen        = 22,       // EndOfCentralDir len, excl. comment
+
+            kMaxCommentLen  = 65535,    // longest possible in ushort
+            kMaxEOCDSearch  = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
+
+        };
+
+        void dump(void) const;
+    };
+
+
+    /* read all entries in the central dir */
+    status_t readCentralDir(void);
+
+    /* crunch deleted entries out */
+    status_t crunchArchive(void);
+
+    /* clean up mEntries */
+    void discardEntries(void);
+
+    /* common handler for all "add" functions */
+    status_t addCommon(const char* fileName, const void* data, size_t size,
+        const char* storageName, int sourceType, int compressionMethod,
+        ZipEntry** ppEntry);
+
+    /* copy all of "srcFp" into "dstFp" */
+    status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
+    /* copy all of "data" into "dstFp" */
+    status_t copyDataToFp(FILE* dstFp,
+        const void* data, size_t size, unsigned long* pCRC32);
+    /* copy some of "srcFp" into "dstFp" */
+    status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+        unsigned long* pCRC32);
+    /* like memmove(), but on parts of a single file */
+    status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
+    /* compress all of "srcFp" into "dstFp", using Deflate */
+    status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
+        const void* data, size_t size, unsigned long* pCRC32);
+
+    /* get modification date from a file descriptor */
+    time_t getModTime(int fd);
+
+    /*
+     * We use stdio FILE*, which gives us buffering but makes dealing
+     * with files >2GB awkward.  Until we support Zip64, we're fine.
+     */
+    FILE*           mZipFp;             // Zip file pointer
+
+    /* one of these per file */
+    EndOfCentralDir mEOCD;
+
+    /* did we open this read-only? */
+    bool            mReadOnly;
+
+    /* set this when we trash the central dir */
+    bool            mNeedCDRewrite;
+
+    /*
+     * One ZipEntry per entry in the zip file.  I'm using pointers instead
+     * of objects because it's easier than making operator= work for the
+     * classes and sub-classes.
+     */
+    Vector<ZipEntry*>   mEntries;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPFILE_H
diff --git a/include/utils/ZipFileCRO.h b/include/utils/ZipFileCRO.h
new file mode 100644
index 0000000..30e0036
--- /dev/null
+++ b/include/utils/ZipFileCRO.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+//
+// C API for ead-only access to Zip archives, with minimal heap allocation.
+//
+#ifndef __LIBS_ZIPFILECRO_H
+#define __LIBS_ZIPFILECRO_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Trivial typedef to ensure that ZipFileCRO is not treated as a simple integer.
+ */
+typedef void* ZipFileCRO;
+
+/*
+ * Trivial typedef to ensure that ZipEntryCRO is not treated as a simple
+ * integer.  We use NULL to indicate an invalid value.
+ */
+typedef void* ZipEntryCRO;
+
+extern ZipFileCRO ZipFileXRO_open(const char* path);
+
+extern void ZipFileCRO_destroy(ZipFileCRO zip);
+
+extern ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zip,
+        const char* fileName);
+
+extern bool ZipFileCRO_getEntryInfo(ZipFileCRO zip, ZipEntryCRO entry,
+        int* pMethod, long* pUncompLen,
+        long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32);
+
+extern bool ZipFileCRO_uncompressEntry(ZipFileCRO zip, ZipEntryCRO entry, int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__LIBS_ZIPFILECRO_H*/
diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h
new file mode 100644
index 0000000..51c4f2f
--- /dev/null
+++ b/include/utils/ZipFileRO.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+//
+// Read-only access to Zip archives, with minimal heap allocation.
+//
+// This is similar to the more-complete ZipFile class, but no attempt
+// has been made to make them interchangeable.  This class operates under
+// a very different set of assumptions and constraints.
+//
+#ifndef __LIBS_ZIPFILERO_H
+#define __LIBS_ZIPFILERO_H
+
+#include "Errors.h"
+#include "FileMap.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+namespace android {
+
+/*
+ * Trivial typedef to ensure that ZipEntryRO is not treated as a simple
+ * integer.  We use NULL to indicate an invalid value.
+ */
+typedef void* ZipEntryRO;
+
+/*
+ * Open a Zip archive for reading.
+ *
+ * We want "open" and "find entry by name" to be fast operations, and we
+ * want to use as little memory as possible.  We memory-map the file,
+ * and load a hash table with pointers to the filenames (which aren't
+ * null-terminated).  The other fields are at a fixed offset from the
+ * filename, so we don't need to extract those (but we do need to byte-read
+ * and endian-swap them every time we want them).
+ *
+ * To speed comparisons when doing a lookup by name, we could make the mapping
+ * "private" (copy-on-write) and null-terminate the filenames after verifying
+ * the record structure.  However, this requires a private mapping of
+ * every page that the Central Directory touches.  Easier to tuck a copy
+ * of the string length into the hash table entry.
+ */
+class ZipFileRO {
+public:
+    ZipFileRO()
+        : mFd(-1), mFileMap(NULL), mHashTableSize(-1), mHashTable(NULL)
+        {}
+    ~ZipFileRO() {
+        free(mHashTable);
+        if (mFileMap)
+            mFileMap->release();
+        if (mFd >= 0)
+            close(mFd);
+    }
+
+    /*
+     * Open an archive.
+     */
+    status_t open(const char* zipFileName);
+
+    /*
+     * Find an entry, by name.  Returns the entry identifier, or NULL if
+     * not found.
+     *
+     * If two entries have the same name, one will be chosen at semi-random.
+     */
+    ZipEntryRO findEntryByName(const char* fileName) const;
+
+    /*
+     * Return the #of entries in the Zip archive.
+     */
+    int getNumEntries(void) const {
+        return mNumEntries;
+    }
+
+    /*
+     * Return the Nth entry.  Zip file entries are not stored in sorted
+     * order, and updated entries may appear at the end, so anyone walking
+     * the archive needs to avoid making ordering assumptions.  We take
+     * that further by returning the Nth non-empty entry in the hash table
+     * rather than the Nth entry in the archive.
+     *
+     * Valid values are [0..numEntries).
+     *
+     * [This is currently O(n).  If it needs to be fast we can allocate an
+     * additional data structure or provide an iterator interface.]
+     */
+    ZipEntryRO findEntryByIndex(int idx) const;
+
+    /*
+     * Copy the filename into the supplied buffer.  Returns 0 on success,
+     * -1 if "entry" is invalid, or the filename length if it didn't fit.  The
+     * length, and the returned string, include the null-termination.
+     */
+    int getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) const;
+
+    /*
+     * Get the vital stats for an entry.  Pass in NULL pointers for anything
+     * you don't need.
+     *
+     * "*pOffset" holds the Zip file offset of the entry's data.
+     *
+     * Returns "false" if "entry" is bogus or if the data in the Zip file
+     * appears to be bad.
+     */
+    bool getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen,
+        long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const;
+
+    /*
+     * Create a new FileMap object that maps a subset of the archive.  For
+     * an uncompressed entry this effectively provides a pointer to the
+     * actual data, for a compressed entry this provides the input buffer
+     * for inflate().
+     */
+    FileMap* createEntryFileMap(ZipEntryRO entry) const;
+
+    /*
+     * Uncompress the data into a buffer.  Depending on the compression
+     * format, this is either an "inflate" operation or a memcpy.
+     *
+     * Use "uncompLen" from getEntryInfo() to determine the required
+     * buffer size.
+     *
+     * Returns "true" on success.
+     */
+    bool uncompressEntry(ZipEntryRO entry, void* buffer) const;
+
+    /*
+     * Uncompress the data to an open file descriptor.
+     */
+    bool uncompressEntry(ZipEntryRO entry, int fd) const;
+
+    /* Zip compression methods we support */
+    enum {
+        kCompressStored     = 0,        // no compression
+        kCompressDeflated   = 8,        // standard deflate
+    };
+
+    /*
+     * Utility function: uncompress deflated data, buffer to buffer.
+     */
+    static bool inflateBuffer(void* outBuf, const void* inBuf,
+        long uncompLen, long compLen);
+
+    /*
+     * Utility function: uncompress deflated data, buffer to fd.
+     */
+    static bool inflateBuffer(int fd, const void* inBuf,
+        long uncompLen, long compLen);
+
+    /*
+     * Some basic functions for raw data manipulation.  "LE" means
+     * Little Endian.
+     */
+    static inline unsigned short get2LE(const unsigned char* buf) {
+        return buf[0] | (buf[1] << 8);
+    }
+    static inline unsigned long get4LE(const unsigned char* buf) {
+        return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+    }
+
+private:
+    /* these are private and not defined */ 
+    ZipFileRO(const ZipFileRO& src);
+    ZipFileRO& operator=(const ZipFileRO& src);
+
+    /* parse the archive, prepping internal structures */
+    bool parseZipArchive(void);
+
+    /* add a new entry to the hash table */
+    void addToHash(const char* str, int strLen, unsigned int hash);
+
+    /* compute string hash code */
+    static unsigned int computeHash(const char* str, int len);
+
+    /* convert a ZipEntryRO back to a hash table index */
+    int entryToIndex(const ZipEntryRO entry) const;
+
+    /*
+     * One entry in the hash table.
+     */
+    typedef struct HashEntry {
+        const char*     name;
+        unsigned short  nameLen;
+        //unsigned int    hash;
+    } HashEntry;
+
+    /* open Zip archive */
+    int         mFd;
+
+    /* mapped file */
+    FileMap*    mFileMap;
+
+    /* number of entries in the Zip archive */
+    int         mNumEntries;
+
+    /*
+     * We know how many entries are in the Zip archive, so we have a
+     * fixed-size hash table.  We probe for an empty slot.
+     */
+    int         mHashTableSize;
+    HashEntry*  mHashTable;
+};
+
+}; // namespace android
+
+#endif /*__LIBS_ZIPFILERO_H*/
diff --git a/include/utils/ZipUtils.h b/include/utils/ZipUtils.h
new file mode 100644
index 0000000..42c42b6
--- /dev/null
+++ b/include/utils/ZipUtils.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+//
+// Miscellaneous zip/gzip utility functions.
+//
+#ifndef __LIBS_ZIPUTILS_H
+#define __LIBS_ZIPUTILS_H
+
+#include <stdio.h>
+
+namespace android {
+
+/*
+ * Container class for utility functions, primarily for namespace reasons.
+ */
+class ZipUtils {
+public:
+    /*
+     * General utility function for uncompressing "deflate" data from a file
+     * to a buffer.
+     */
+    static bool inflateToBuffer(int fd, void* buf, long uncompressedLen,
+        long compressedLen);
+    static bool inflateToBuffer(FILE* fp, void* buf, long uncompressedLen,
+        long compressedLen);
+
+    /*
+     * Someday we might want to make this generic and handle bzip2 ".bz2"
+     * files too.
+     *
+     * We could declare gzip to be a sub-class of zip that has exactly
+     * one always-compressed entry, but we currently want to treat Zip
+     * and gzip as distinct, so there's no value.
+     *
+     * The zlib library has some gzip utilities, but it has no interface
+     * for extracting the uncompressed length of the file (you do *not*
+     * want to gzseek to the end).
+     *
+     * Pass in a seeked file pointer for the gzip file.  If this is a gzip
+     * file, we set our return values appropriately and return "true" with
+     * the file seeked to the start of the compressed data.
+     */
+    static bool examineGzip(FILE* fp, int* pCompressionMethod,
+        long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32);
+
+private:
+    ZipUtils() {}
+    ~ZipUtils() {}
+};
+
+}; // namespace android
+
+#endif /*__LIBS_ZIPUTILS_H*/
diff --git a/include/utils/ashmem.h b/include/utils/ashmem.h
new file mode 100644
index 0000000..0854775
--- /dev/null
+++ b/include/utils/ashmem.h
@@ -0,0 +1,41 @@
+/* utils/ashmem.h
+ **
+ ** Copyright 2008 The Android Open Source Project
+ **
+ ** This file is dual licensed.  It may be redistributed and/or modified
+ ** under the terms of the Apache 2.0 License OR version 2 of the GNU
+ ** General Public License.
+ */
+
+#ifndef _UTILS_ASHMEM_H
+#define _UTILS_ASHMEM_H
+
+#include <linux/limits.h>
+#include <linux/ioctl.h>
+
+#define ASHMEM_NAME_LEN		256
+
+#define ASHMEM_NAME_DEF		"dev/ashmem"
+
+/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
+#define ASHMEM_NOT_REAPED	0
+#define ASHMEM_WAS_REAPED	1
+
+/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
+#define ASHMEM_NOW_UNPINNED	0
+#define ASHMEM_NOW_PINNED	1
+
+#define __ASHMEMIOC		0x77
+
+#define ASHMEM_SET_NAME		_IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
+#define ASHMEM_GET_NAME		_IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
+#define ASHMEM_SET_SIZE		_IOW(__ASHMEMIOC, 3, size_t)
+#define ASHMEM_GET_SIZE		_IO(__ASHMEMIOC, 4)
+#define ASHMEM_SET_PROT_MASK	_IOW(__ASHMEMIOC, 5, unsigned long)
+#define ASHMEM_GET_PROT_MASK	_IO(__ASHMEMIOC, 6)
+#define ASHMEM_PIN		_IO(__ASHMEMIOC, 7)
+#define ASHMEM_UNPIN		_IO(__ASHMEMIOC, 8)
+#define ASHMEM_ISPINNED		_IO(__ASHMEMIOC, 9)
+#define ASHMEM_PURGE_ALL_CACHES	_IO(__ASHMEMIOC, 10)
+
+#endif	/* _UTILS_ASHMEM_H */
diff --git a/include/utils/executablepath.h b/include/utils/executablepath.h
new file mode 100644
index 0000000..c979432
--- /dev/null
+++ b/include/utils/executablepath.h
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#ifndef _UTILS_EXECUTABLEPATH_H
+#define _UTILS_EXECUTABLEPATH_H
+
+#include <limits.h>
+
+// returns the path to this executable
+#if __cplusplus
+extern "C"
+#endif
+void executablepath(char s[PATH_MAX]);
+
+#endif // _UTILS_EXECUTABLEPATH_H
diff --git a/include/utils/inet_address.h b/include/utils/inet_address.h
new file mode 100644
index 0000000..dbd8672
--- /dev/null
+++ b/include/utils/inet_address.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Internet address classes.  Modeled after Java classes.
+//
+#ifndef _RUNTIME_INET_ADDRESS_H
+#define _RUNTIME_INET_ADDRESS_H
+
+#ifdef HAVE_ANDROID_OS
+#error DO NOT USE THIS FILE IN THE DEVICE BUILD
+#endif
+
+
+namespace android {
+
+/*
+ * This class holds Internet addresses.  Perhaps more useful is its
+ * ability to look up addresses by name.
+ *
+ * Invoke one of the static factory methods to create a new object.
+ */
+class InetAddress {
+public:
+    virtual ~InetAddress(void);
+
+    // create from w.x.y.z or foo.bar.com notation
+    static InetAddress* getByName(const char* host);
+
+    // copy-construction
+    InetAddress(const InetAddress& orig);
+
+    const void* getAddress(void) const { return mAddress; }
+    int getAddressLength(void) const { return mLength; }
+    const char* getHostName(void) const { return mName; }
+
+private:
+    InetAddress(void);
+    // assignment (private)
+    InetAddress& operator=(const InetAddress& addr);
+
+    // use a void* here so we don't have to expose actual socket headers
+    void*       mAddress;   // this is really a ptr to sockaddr_in
+    int         mLength;
+    char*       mName;
+};
+
+
+/*
+ * Base class for socket addresses.
+ */
+class SocketAddress {
+public:
+    SocketAddress() {}
+    virtual ~SocketAddress() {}
+};
+
+
+/*
+ * Internet address class.  This combines an InetAddress with a port.
+ */
+class InetSocketAddress : public SocketAddress {
+public:
+    InetSocketAddress() :
+        mAddress(0), mPort(-1)
+        {}
+    ~InetSocketAddress(void) {
+        delete mAddress;
+    }
+
+    // Create an address with a host wildcard (useful for servers).
+    bool create(int port);
+    // Create an address with the specified host and port.
+    bool create(const InetAddress* addr, int port);
+    // Create an address with the specified host and port.  Does the
+    // hostname lookup.
+    bool create(const char* host, int port);
+
+    const InetAddress* getAddress(void) const { return mAddress; }
+    const int getPort(void) const { return mPort; }
+    const char* getHostName(void) const { return mAddress->getHostName(); }
+
+private:
+    InetAddress* mAddress;
+    int         mPort;
+};
+
+}; // namespace android
+
+#endif // _RUNTIME_INET_ADDRESS_H
diff --git a/include/utils/misc.h b/include/utils/misc.h
new file mode 100644
index 0000000..62e84b4
--- /dev/null
+++ b/include/utils/misc.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Handy utility functions and portability code.
+//
+#ifndef _LIBS_UTILS_MISC_H
+#define _LIBS_UTILS_MISC_H
+
+#include <sys/time.h>
+#include "utils/Endian.h"
+
+namespace android {
+
+/* get #of elements in a static array */
+#ifndef NELEM
+# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+#endif
+
+/*
+ * Make a copy of the string, using "new[]" instead of "malloc".  Free the
+ * string with delete[].
+ *
+ * Returns NULL if "str" is NULL.
+ */
+char* strdupNew(const char* str);
+
+/*
+ * Concatenate an argument vector into a single string.  If argc is >= 0
+ * it will be used; if it's < 0 then the last element in the arg vector
+ * must be NULL.
+ *
+ * This inserts a space between each argument.
+ *
+ * This does not automatically add double quotes around arguments with
+ * spaces in them.  This practice is necessary for Win32, because Win32's
+ * CreateProcess call is stupid.
+ *
+ * The caller should delete[] the returned string.
+ */
+char* concatArgv(int argc, const char* const argv[]);
+
+/*
+ * Count up the number of arguments in "argv".  The count does not include
+ * the final NULL entry.
+ */
+int countArgv(const char* const argv[]);
+
+/*
+ * Some utility functions for working with files.  These could be made
+ * part of a "File" class.
+ */
+typedef enum FileType {
+    kFileTypeUnknown = 0,
+    kFileTypeNonexistent,       // i.e. ENOENT
+    kFileTypeRegular,
+    kFileTypeDirectory,
+    kFileTypeCharDev,
+    kFileTypeBlockDev,
+    kFileTypeFifo,
+    kFileTypeSymlink,
+    kFileTypeSocket,
+} FileType;
+/* get the file's type; follows symlinks */
+FileType getFileType(const char* fileName);
+/* get the file's modification date; returns -1 w/errno set on failure */
+time_t getFileModDate(const char* fileName);
+
+/*
+ * Round up to the nearest power of 2.  Handy for hash tables.
+ */
+unsigned int roundUpPower2(unsigned int val);
+
+void strreverse(char* begin, char* end);
+void k_itoa(int value, char* str, int base);
+char* itoa(int val, int base);
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_MISC_H
diff --git a/include/utils/ported.h b/include/utils/ported.h
new file mode 100644
index 0000000..eb3be01
--- /dev/null
+++ b/include/utils/ported.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Standard functions ported to the current platform.  Note these are NOT
+// in the "android" namespace.
+//
+#ifndef _LIBS_UTILS_PORTED_H
+#define _LIBS_UTILS_PORTED_H
+
+#include <sys/time.h>       // for timeval
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* library replacement functions */
+#if defined(NEED_GETTIMEOFDAY)
+int gettimeofday(struct timeval* tv, struct timezone* tz);
+#endif
+#if defined(NEED_USLEEP)
+void usleep(unsigned long usec);
+#endif
+#if defined(NEED_PIPE)
+int pipe(int filedes[2]);
+#endif
+#if defined(NEED_SETENV)
+int setenv(const char* name, const char* value, int overwrite);
+void unsetenv(const char* name);
+char* getenv(const char* name);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _LIBS_UTILS_PORTED_H
diff --git a/include/utils/string_array.h b/include/utils/string_array.h
new file mode 100644
index 0000000..064dda2
--- /dev/null
+++ b/include/utils/string_array.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Sortable array of strings.  STL-ish, but STL-free.
+//  
+#ifndef _LIBS_UTILS_STRING_ARRAY_H
+#define _LIBS_UTILS_STRING_ARRAY_H
+
+#include <stdlib.h>
+#include <string.h>
+
+namespace android {
+
+//
+// An expanding array of strings.  Add, get, sort, delete.
+//
+class StringArray {
+public:
+    StringArray()
+        : mMax(0), mCurrent(0), mArray(NULL)
+        {}
+    virtual ~StringArray() {
+        for (int i = 0; i < mCurrent; i++)
+            delete[] mArray[i];
+        delete[] mArray;
+    }
+
+    //
+    // Add a string.  A copy of the string is made.
+    //
+    bool push_back(const char* str) {
+        if (mCurrent >= mMax) {
+            char** tmp;
+
+            if (mMax == 0)
+                mMax = 16;      // initial storage
+            else
+                mMax *= 2;
+
+            tmp = new char*[mMax];
+            if (tmp == NULL)
+                return false;
+
+            memcpy(tmp, mArray, mCurrent * sizeof(char*));
+            delete[] mArray;
+            mArray = tmp;
+        }
+
+        int len = strlen(str);
+        mArray[mCurrent] = new char[len+1];
+        memcpy(mArray[mCurrent], str, len+1);
+        mCurrent++;
+
+        return true;
+    }
+
+    //
+    // Delete an entry.
+    //
+    void erase(int idx) {
+        if (idx < 0 || idx >= mCurrent)
+            return;
+        delete[] mArray[idx];
+        if (idx < mCurrent-1) {
+            memmove(&mArray[idx], &mArray[idx+1],
+                (mCurrent-1 - idx) * sizeof(char*));
+        }
+        mCurrent--;
+    }
+
+    //
+    // Sort the array.
+    //
+    void sort(int (*compare)(const void*, const void*)) {
+        qsort(mArray, mCurrent, sizeof(char*), compare);
+    }
+
+    //
+    // Pass this to the sort routine to do an ascending alphabetical sort.
+    //
+    static int cmpAscendingAlpha(const void* pstr1, const void* pstr2) {
+        return strcmp(*(const char**)pstr1, *(const char**)pstr2);
+    }
+
+    //
+    // Get the #of items in the array.
+    //
+    inline int size(void) const { return mCurrent; }
+
+    //
+    // Return entry N.
+    // [should use operator[] here]
+    //
+    const char* getEntry(int idx) const {
+        if (idx < 0 || idx >= mCurrent)
+            return NULL;
+        return mArray[idx];
+    }
+
+    //
+    // Set entry N to specified string.
+    // [should use operator[] here]
+    //
+    void setEntry(int idx, const char* str) {
+        if (idx < 0 || idx >= mCurrent)
+            return;
+        delete[] mArray[idx];
+        int len = strlen(str);
+        mArray[idx] = new char[len+1];
+        memcpy(mArray[idx], str, len+1);
+    }
+
+private:
+    int     mMax;
+    int     mCurrent;
+    char**  mArray;
+};
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_STRING_ARRAY_H
diff --git a/include/utils/threads.h b/include/utils/threads.h
new file mode 100644
index 0000000..7dca810
--- /dev/null
+++ b/include/utils/threads.h
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef _LIBS_UTILS_THREADS_H
+#define _LIBS_UTILS_THREADS_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <time.h>
+
+// ------------------------------------------------------------------
+// C API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void* android_thread_id_t;
+
+typedef int (*android_thread_func_t)(void*);
+
+enum {
+    /*
+     * ***********************************************
+     * ** Keep in sync with android.os.Process.java **
+     * ***********************************************
+     * 
+     * This maps directly to the "nice" priorites we use in Android.
+     * A thread priority should be chosen inverse-proportinally to
+     * the amount of work the thread is expected to do. The more work
+     * a thread will do, the less favorable priority it should get so that 
+     * it doesn't starve the system. Threads not behaving properly might
+     * be "punished" by the kernel.
+     * Use the levels below when appropriate. Intermediate values are
+     * acceptable, preferably use the {MORE|LESS}_FAVORABLE constants below.
+     */
+    ANDROID_PRIORITY_LOWEST         =  19,
+
+    /* use for background tasks */
+    ANDROID_PRIORITY_BACKGROUND     =  10,
+    
+    /* most threads run at normal priority */
+    ANDROID_PRIORITY_NORMAL         =   0,
+    
+    /* threads currently running a UI that the user is interacting with */
+    ANDROID_PRIORITY_FOREGROUND     =  -2,
+
+    /* the main UI thread has a slightly more favorable priority */
+    ANDROID_PRIORITY_DISPLAY        =  -4,
+    
+    /* ui service treads might want to run at a urgent display (uncommon) */
+    ANDROID_PRIORITY_URGENT_DISPLAY =  -8,
+    
+    /* all normal audio threads */
+    ANDROID_PRIORITY_AUDIO          = -16,
+    
+    /* service audio threads (uncommon) */
+    ANDROID_PRIORITY_URGENT_AUDIO   = -19,
+
+    /* should never be used in practice. regular process might not 
+     * be allowed to use this level */
+    ANDROID_PRIORITY_HIGHEST        = -20,
+
+    ANDROID_PRIORITY_DEFAULT        = ANDROID_PRIORITY_NORMAL,
+    ANDROID_PRIORITY_MORE_FAVORABLE = -1,
+    ANDROID_PRIORITY_LESS_FAVORABLE = +1,
+};
+
+// Create and run a new thread.
+extern int androidCreateThread(android_thread_func_t, void *);
+
+// Create thread with lots of parameters
+extern int androidCreateThreadEtc(android_thread_func_t entryFunction,
+                                  void *userData,
+                                  const char* threadName,
+                                  int32_t threadPriority,
+                                  size_t threadStackSize,
+                                  android_thread_id_t *threadId);
+
+// Get some sort of unique identifier for the current thread.
+extern android_thread_id_t androidGetThreadId();
+
+// Low-level thread creation -- never creates threads that can
+// interact with the Java VM.
+extern int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
+                                     void *userData,
+                                     const char* threadName,
+                                     int32_t threadPriority,
+                                     size_t threadStackSize,
+                                     android_thread_id_t *threadId);
+
+// Used by the Java Runtime to control how threads are created, so that
+// they can be proper and lovely Java threads.
+typedef int (*android_create_thread_fn)(android_thread_func_t entryFunction,
+                                        void *userData,
+                                        const char* threadName,
+                                        int32_t threadPriority,
+                                        size_t threadStackSize,
+                                        android_thread_id_t *threadId);
+
+extern void androidSetCreateThreadFunc(android_create_thread_fn func);
+
+#ifdef __cplusplus
+}
+#endif
+
+// ------------------------------------------------------------------
+// C++ API
+
+#ifdef __cplusplus
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+typedef android_thread_id_t thread_id_t;
+
+typedef android_thread_func_t thread_func_t;
+
+enum {
+    PRIORITY_LOWEST         = ANDROID_PRIORITY_LOWEST,
+    PRIORITY_BACKGROUND     = ANDROID_PRIORITY_BACKGROUND,
+    PRIORITY_NORMAL         = ANDROID_PRIORITY_NORMAL,
+    PRIORITY_FOREGROUND     = ANDROID_PRIORITY_FOREGROUND,
+    PRIORITY_DISPLAY        = ANDROID_PRIORITY_DISPLAY,
+    PRIORITY_URGENT_DISPLAY = ANDROID_PRIORITY_URGENT_DISPLAY,
+    PRIORITY_AUDIO          = ANDROID_PRIORITY_AUDIO,
+    PRIORITY_URGENT_AUDIO   = ANDROID_PRIORITY_URGENT_AUDIO,
+    PRIORITY_HIGHEST        = ANDROID_PRIORITY_HIGHEST,
+    PRIORITY_DEFAULT        = ANDROID_PRIORITY_DEFAULT,
+    PRIORITY_MORE_FAVORABLE = ANDROID_PRIORITY_MORE_FAVORABLE,
+    PRIORITY_LESS_FAVORABLE = ANDROID_PRIORITY_LESS_FAVORABLE,
+};
+
+// Create and run a new thread.
+inline bool createThread(thread_func_t f, void *a) {
+    return androidCreateThread(f, a) ? true : false;
+}
+
+// Create thread with lots of parameters
+inline bool createThreadEtc(thread_func_t entryFunction,
+                            void *userData,
+                            const char* threadName = "android:unnamed_thread",
+                            int32_t threadPriority = PRIORITY_DEFAULT,
+                            size_t threadStackSize = 0,
+                            thread_id_t *threadId = 0)
+{
+    return androidCreateThreadEtc(entryFunction, userData, threadName,
+        threadPriority, threadStackSize, threadId) ? true : false;
+}
+
+// Get some sort of unique identifier for the current thread.
+inline thread_id_t getThreadId() {
+    return androidGetThreadId();
+}
+
+/*
+ * Simple mutex class.  The implementation is system-dependent.
+ *
+ * The mutex must be unlocked by the thread that locked it.  They are not
+ * recursive, i.e. the same thread can't lock it multiple times.
+ */
+class Mutex {
+public:
+                Mutex();
+                Mutex(const char* name);
+                ~Mutex();
+
+    // lock or unlock the mutex
+    status_t    lock();
+    void        unlock();
+
+    // lock if possible; returns 0 on success, error otherwise
+    status_t    tryLock();
+
+    // Manages the mutex automatically. It'll be locked when Autolock is
+    // constructed and released when Autolock goes out of scope.
+    class Autolock {
+    public:
+        inline Autolock(Mutex& mutex) : mpMutex(&mutex) { mutex.lock(); }
+        inline Autolock(Mutex* mutex) : mpMutex(mutex) { mutex->lock(); }
+        inline ~Autolock() { mpMutex->unlock(); }
+    private:
+        Mutex*  mpMutex;
+    };
+
+private:
+    friend class Condition;
+    
+    // A mutex cannot be copied
+                Mutex(const Mutex&);
+    Mutex&      operator = (const Mutex&);
+    void        _init();
+    
+    void*   mState;
+};
+
+/*
+ * Automatic mutex.  Declare one of these at the top of a function.
+ * When the function returns, it will go out of scope, and release the
+ * mutex.
+ */
+ 
+typedef Mutex::Autolock AutoMutex;
+
+
+/*
+ * Condition variable class.  The implementation is system-dependent.
+ *
+ * Condition variables are paired up with mutexes.  Lock the mutex,
+ * call wait(), then either re-wait() if things aren't quite what you want,
+ * or unlock the mutex and continue.  All threads calling wait() must
+ * use the same mutex for a given Condition.
+ */
+class Condition {
+public:
+    Condition();
+    ~Condition();
+    // Wait on the condition variable.  Lock the mutex before calling.
+    status_t wait(Mutex& mutex);
+    // Wait on the condition variable until the given time.  Lock the mutex
+    // before calling.
+    status_t wait(Mutex& mutex, nsecs_t abstime);
+    // same with relative timeout
+    status_t waitRelative(Mutex& mutex, nsecs_t reltime);
+    // Signal the condition variable, allowing one thread to continue.
+    void signal();
+    // Signal the condition variable, allowing all threads to continue.
+    void broadcast();
+
+private:
+    void*   mState;
+};
+
+
+/*
+ * Read/write lock.  The resource can have multiple readers or one writer,
+ * but can't be read and written at the same time.
+ *
+ * The same thread should not call a lock function while it already has
+ * a lock.  (Should be okay for multiple readers.)
+ */
+class ReadWriteLock {
+public:
+    ReadWriteLock()
+        : mNumReaders(0), mNumWriters(0)
+        {}
+    ~ReadWriteLock() {}
+
+    void lockForRead();
+    bool tryLockForRead();
+    void unlockForRead();
+
+    void lockForWrite();
+    bool tryLockForWrite();
+    void unlockForWrite();
+
+private:
+    int         mNumReaders;
+    int         mNumWriters;
+
+    Mutex       mLock;
+    Condition   mReadWaiter;
+    Condition   mWriteWaiter;
+#if defined(PRINT_RENDER_TIMES)
+    DurationTimer mDebugTimer;
+#endif
+};
+
+
+/*
+ * This is our spiffy thread object!
+ */
+
+class Thread : virtual public RefBase
+{
+public:
+    // Create a Thread object, but doesn't create or start the associated
+    // thread. See the run() method.
+                        Thread(bool canCallJava = true);
+    virtual             ~Thread();
+
+    // Start the thread in threadLoop() which needs to be implemented.
+    virtual status_t    run(    const char* name = 0,
+                                int32_t priority = PRIORITY_DEFAULT,
+                                size_t stack = 0);
+    
+    // Ask this object's thread to exit. This function is asynchronous, when the
+    // function returns the thread might still be running. Of course, this
+    // function can be called from a different thread.
+    virtual void        requestExit();
+
+    // Good place to do one-time initializations
+    virtual status_t    readyToRun();
+    
+    // Call requestExit() and wait until this object's thread exits.
+    // BE VERY CAREFUL of deadlocks. In particular, it would be silly to call
+    // this function from this object's thread. Will return WOULD_BLOCK in
+    // that case.
+            status_t    requestExitAndWait();
+
+protected:
+    // exitPending() returns true if requestExit() has been called.
+            bool        exitPending() const;
+    
+private:
+    // Derived class must implemtent threadLoop(). The thread starts its life
+    // here. There are two ways of using the Thread object:
+    // 1) loop: if threadLoop() returns true, it will be called again if
+    //          requestExit() wasn't called.
+    // 2) once: if threadLoop() returns false, the thread will exit upon return.
+    virtual bool        threadLoop() = 0;
+
+private:
+    Thread& operator=(const Thread&);
+    static  int             _threadLoop(void* user);
+    const   bool            mCanCallJava;
+            thread_id_t     mThread;
+            Mutex           mLock;
+            Condition       mThreadExitedCondition;
+            status_t        mStatus;
+    volatile bool           mExitPending;
+    volatile bool           mRunning;
+            sp<Thread>      mHoldSelf;
+};
+
+
+}; // namespace android
+
+#endif  // __cplusplus
+
+#endif // _LIBS_UTILS_THREADS_H
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
new file mode 100644
index 0000000..eb00f8c
--- /dev/null
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -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.
+ */
+
+#include <math.h>
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "A2dpAudioInterface"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "A2dpAudioInterface.h"
+#include "audio/liba2dp.h"
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+A2dpAudioInterface::A2dpAudioInterface() :
+    mOutput(0)
+{
+}
+
+A2dpAudioInterface::~A2dpAudioInterface()
+{
+    delete mOutput;
+}
+
+status_t A2dpAudioInterface::initCheck()
+{
+    return 0;
+}
+
+AudioStreamOut* A2dpAudioInterface::openOutputStream(
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
+{
+    LOGD("A2dpAudioInterface::openOutputStream %d, %d, %d\n", format, channelCount, sampleRate);
+    Mutex::Autolock lock(mLock);
+    status_t err = 0;
+
+    // only one output stream allowed
+    if (mOutput) {
+        if (status)
+            *status = -1;
+        return NULL;
+    }
+
+    // create new output stream
+    A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
+    if ((err = out->set(format, channelCount, sampleRate)) == NO_ERROR) {
+        mOutput = out;
+    } else {
+        delete out;
+    }
+    
+    if (status)
+        *status = err;
+    return mOutput;
+}
+
+AudioStreamIn* A2dpAudioInterface::openInputStream(
+        int format, int channelCount, uint32_t sampleRate, status_t *status,
+        AudioSystem::audio_in_acoustics acoustics)
+{
+    if (status)
+        *status = -1;
+    return NULL;
+}
+
+status_t A2dpAudioInterface::setMicMute(bool state)
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::getMicMute(bool* state)
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::setParameter(const char *key, const char *value)
+{
+    LOGD("setParameter %s,%s\n", key, value);
+    
+    if (!key || !value)
+        return -EINVAL;
+    
+    if (strcmp(key, "a2dp_sink_address") == 0) {        
+        return mOutput->setAddress(value);
+    }
+    if (strcmp(key, "bluetooth_enabled") == 0 &&
+        strcmp(value, "false") == 0) {
+        return mOutput->close();
+    }
+
+    return 0;
+}
+
+status_t A2dpAudioInterface::setVoiceVolume(float v)
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::setMasterVolume(float v)
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::doRouting()
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
+{
+    return 0;
+}
+
+// ----------------------------------------------------------------------------
+
+A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
+    mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL)
+{
+    // use any address by default
+    strncpy(mA2dpAddress, "00:00:00:00:00:00", sizeof(mA2dpAddress));
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
+        int format, int channels, uint32_t rate)
+{
+    LOGD("A2dpAudioStreamOut::set %d, %d, %d\n", format, channels, rate);
+
+    // fix up defaults
+    if (format == 0) format = AudioSystem::PCM_16_BIT;
+    if (channels == 0) channels = channelCount();
+    if (rate == 0) rate = sampleRate();
+
+    // check values
+    if ((format != AudioSystem::PCM_16_BIT) ||
+            (channels != channelCount()) ||
+            (rate != sampleRate()))
+        return BAD_VALUE;
+
+    return NO_ERROR;
+}
+
+A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
+{
+    close();
+}
+
+ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
+{    
+    status_t status = NO_INIT;
+    size_t remaining = bytes;
+
+    if (!mData) {
+        status = a2dp_init(44100, 2, &mData);
+        if (status < 0) {
+            LOGE("a2dp_init failed err: %d\n", status);
+            mData = NULL;
+            goto Error;
+        }
+        a2dp_set_sink(mData, mA2dpAddress);
+    }
+    
+    while (remaining > 0) {
+        status = a2dp_write(mData, buffer, remaining);
+        if (status <= 0) {
+            LOGE("a2dp_write failed err: %d\n", status);
+            goto Error;
+        }
+        remaining -= status;
+        buffer = ((char *)buffer) + status;
+    }
+
+    mStandby = false;
+    
+    return bytes;
+
+Error:
+    // Simulate audio output timing in case of error
+    usleep(bytes * 1000000 / frameSize() / sampleRate());
+
+    return status;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
+{
+    int result = 0;
+
+    if (!mStandby) {
+        result = a2dp_stop(mData);
+        if (result == 0)
+            mStandby = true;
+    }
+
+    return result;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
+{
+    if (strlen(address) < sizeof(mA2dpAddress))
+        return -EINVAL;
+
+    if (strcmp(address, mA2dpAddress)) {
+        strcpy(mA2dpAddress, address);
+        if (mData)
+            a2dp_set_sink(mData, mA2dpAddress);
+    }
+    
+    return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
+{
+    if (mData) {
+        a2dp_cleanup(mData);
+        mData = NULL;
+    }
+    return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
+{
+    return NO_ERROR;
+}
+
+
+}; // namespace android
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
new file mode 100644
index 0000000..a56e8a0
--- /dev/null
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -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.
+ */
+
+#ifndef A2DP_AUDIO_HARDWARE_H
+#define A2DP_AUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+
+namespace android {
+
+class A2dpAudioInterface : public AudioHardwareBase
+{
+    class A2dpAudioStreamOut;
+
+public:
+                        A2dpAudioInterface();
+    virtual             ~A2dpAudioInterface();
+    virtual status_t    initCheck();
+
+    virtual status_t    setVoiceVolume(float volume);
+    virtual status_t    setMasterVolume(float volume);
+
+    // mic mute
+    virtual status_t    setMicMute(bool state);
+    virtual status_t    getMicMute(bool* state);
+
+    // Temporary interface, do not use
+    // TODO: Replace with a more generic key:value get/set mechanism
+    virtual status_t    setParameter(const char *key, const char *value);
+
+    // create I/O streams
+    virtual AudioStreamOut* openOutputStream(
+                                int format=0,
+                                int channelCount=0,
+                                uint32_t sampleRate=0,
+                                status_t *status=0);
+
+    virtual AudioStreamIn* openInputStream(
+                                int format,
+                                int channelCount,
+                                uint32_t sampleRate,
+                                status_t *status,
+                                AudioSystem::audio_in_acoustics acoustics);
+
+protected:
+    virtual status_t    doRouting();
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+private:
+    class A2dpAudioStreamOut : public AudioStreamOut {
+    public:
+                            A2dpAudioStreamOut();
+        virtual             ~A2dpAudioStreamOut();
+                status_t    set(int format,
+                                int channelCount,
+                                uint32_t sampleRate);
+        virtual uint32_t    sampleRate() const { return 44100; }
+        // SBC codec wants a multiple of 512
+        virtual size_t      bufferSize() const { return 512 * 20; }
+        virtual int         channelCount() const { return 2; }
+        virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+        virtual uint32_t    latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; }
+        virtual status_t    setVolume(float volume) { return INVALID_OPERATION; }
+        virtual ssize_t     write(const void* buffer, size_t bytes);
+                status_t    standby();
+                status_t    close();
+        virtual status_t    dump(int fd, const Vector<String16>& args);
+
+    private:
+        friend class A2dpAudioInterface;
+        status_t            setAddress(const char* address);
+
+    private:
+                int         mFd;
+                bool        mStandby;
+                int         mStartCount;
+                int         mRetryCount;
+                char        mA2dpAddress[20];
+                void*       mData;
+    };
+
+    Mutex                   mLock;
+    A2dpAudioStreamOut*     mOutput;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // A2DP_AUDIO_HARDWARE_H
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
new file mode 100644
index 0000000..50d516b
--- /dev/null
+++ b/libs/audioflinger/Android.mk
@@ -0,0 +1,56 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    AudioHardwareGeneric.cpp \
+    AudioHardwareStub.cpp \
+    AudioDumpInterface.cpp \
+    AudioHardwareInterface.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libutils \
+    libmedia \
+    libhardware_legacy
+
+ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
+  LOCAL_CFLAGS += -DGENERIC_AUDIO
+endif
+
+LOCAL_MODULE:= libaudiointerface
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=               \
+    AudioFlinger.cpp            \
+    AudioMixer.cpp.arm          \
+    AudioResampler.cpp.arm      \
+    AudioResamplerSinc.cpp.arm  \
+    AudioResamplerCubic.cpp.arm
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libutils \
+    libmedia \
+    libhardware_legacy
+
+ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
+  LOCAL_STATIC_LIBRARIES += libaudiointerface
+else
+  LOCAL_SHARED_LIBRARIES += libaudio
+endif
+
+LOCAL_MODULE:= libaudioflinger
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+  LOCAL_SRC_FILES += A2dpAudioInterface.cpp
+  LOCAL_SHARED_LIBRARIES += liba2dp
+  LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
+  LOCAL_C_INCLUDES += $(call include-path-for, bluez-libs)
+  LOCAL_C_INCLUDES += $(call include-path-for, bluez-utils)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/audioflinger/AudioBufferProvider.h b/libs/audioflinger/AudioBufferProvider.h
new file mode 100644
index 0000000..1a467c7
--- /dev/null
+++ b/libs/audioflinger/AudioBufferProvider.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_AUDIO_BUFFER_PROVIDER_H
+#define ANDROID_AUDIO_BUFFER_PROVIDER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioBufferProvider
+{
+public:
+
+    struct Buffer {
+        union {
+            void*       raw;
+            short*      i16;
+            int8_t*     i8;
+        };
+        size_t frameCount;
+    };
+    
+    virtual status_t getNextBuffer(Buffer* buffer) = 0;
+    virtual void releaseBuffer(Buffer* buffer) = 0;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_AUDIO_BUFFER_PROVIDER_H
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
new file mode 100644
index 0000000..b4940cb
--- /dev/null
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -0,0 +1,117 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.cpp
+**
+** Copyright 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.
+*/
+
+#define LOG_TAG "AudioFlingerDump"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "AudioDumpInterface.h"
+
+namespace android {
+
+bool gFirst = true;       // true if first write after a standby
+
+// ----------------------------------------------------------------------------
+
+AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
+{
+    if(hw == 0) {
+        LOGE("Dump construct hw = 0");
+    }
+    mFinalInterface = hw;
+    mStreamOut = 0;
+}
+
+
+AudioDumpInterface::~AudioDumpInterface()
+{
+    if(mFinalInterface) delete mFinalInterface;
+    if(mStreamOut) delete mStreamOut;
+}
+
+
+AudioStreamOut* AudioDumpInterface::openOutputStream(
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
+{
+    AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate, status);
+
+    if(outFinal) {
+        mStreamOut =  new AudioStreamOutDump(outFinal);
+        return mStreamOut;
+    } else {
+        LOGE("Dump outFinal=0");
+        return 0;
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+AudioStreamOutDump::AudioStreamOutDump( AudioStreamOut* finalStream)
+{
+    mFinalStream = finalStream;
+    mOutFile = 0;
+}
+
+
+AudioStreamOutDump::~AudioStreamOutDump()
+{
+    Close();
+    delete mFinalStream;
+}
+
+ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
+{
+    ssize_t ret;
+
+    ret = mFinalStream->write(buffer, bytes);
+    if(!mOutFile && gFirst) {
+        gFirst = false;
+        // check if dump file exist
+        mOutFile = fopen(FLINGER_DUMP_NAME, "r");
+        if(mOutFile) {
+            fclose(mOutFile);
+            mOutFile = fopen(FLINGER_DUMP_NAME, "ab");
+        }
+    }
+    if (mOutFile) {
+        fwrite(buffer, bytes, 1, mOutFile);
+    }
+    return ret;
+}
+
+status_t AudioStreamOutDump::standby()
+{
+    Close();
+    gFirst = true;
+    return mFinalStream->standby();
+}
+
+
+void AudioStreamOutDump::Close(void)
+{
+    if(mOutFile) {
+        fclose(mOutFile);
+        mOutFile = 0;
+    }
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
new file mode 100644
index 0000000..9a94102
--- /dev/null
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -0,0 +1,97 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.h
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_AUDIO_DUMP_INTERFACE_H
+#define ANDROID_AUDIO_DUMP_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+namespace android {
+
+#define FLINGER_DUMP_NAME "/data/FlingerOut.pcm" // name of file used for dump
+
+class AudioStreamOutDump : public AudioStreamOut {
+public:
+                        AudioStreamOutDump( AudioStreamOut* FinalStream);
+                        ~AudioStreamOutDump();
+                        virtual ssize_t     write(const void* buffer, size_t bytes);
+
+    virtual uint32_t    sampleRate() const { return mFinalStream->sampleRate(); }
+    virtual size_t      bufferSize() const { return mFinalStream->bufferSize(); }
+    virtual int         channelCount() const { return mFinalStream->channelCount(); }
+    virtual int         format() const { return mFinalStream->format(); }
+    virtual uint32_t    latency() const { return mFinalStream->latency(); }
+    virtual status_t    setVolume(float volume)
+                            { return mFinalStream->setVolume(volume); }
+    virtual status_t    standby();
+    virtual status_t    dump(int fd, const Vector<String16>& args) { return mFinalStream->dump(fd, args); }
+    void                Close(void);
+
+private:
+    AudioStreamOut      *mFinalStream;
+    FILE                *mOutFile;     // output file
+};
+
+
+class AudioDumpInterface : public AudioHardwareBase
+{
+
+public:
+                        AudioDumpInterface(AudioHardwareInterface* hw);
+    virtual AudioStreamOut* openOutputStream(
+                                int format=0,
+                                int channelCount=0,
+                                uint32_t sampleRate=0,
+                                status_t *status=0);
+    virtual             ~AudioDumpInterface();
+
+    virtual status_t    initCheck()
+                            {return mFinalInterface->initCheck();}
+    virtual status_t    setVoiceVolume(float volume)
+                            {return mFinalInterface->setVoiceVolume(volume);}
+    virtual status_t    setMasterVolume(float volume)
+                            {return mFinalInterface->setMasterVolume(volume);}
+
+    // mic mute
+    virtual status_t    setMicMute(bool state)
+                            {return mFinalInterface->setMicMute(state);}
+    virtual status_t    getMicMute(bool* state)
+                            {return mFinalInterface->getMicMute(state);}
+
+    virtual status_t    setParameter(const char* key, const char* value)
+                            {return mFinalInterface->setParameter(key, value);}
+
+    virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status,
+                                            AudioSystem::audio_in_acoustics acoustics)
+                            {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status, acoustics);}
+
+    virtual status_t    dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
+
+protected:
+    virtual status_t    doRouting() {return mFinalInterface->setRouting(mMode, mRoutes[mMode]);}
+
+    AudioHardwareInterface  *mFinalInterface;
+    AudioStreamOutDump      *mStreamOut;
+
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_DUMP_INTERFACE_H
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
new file mode 100644
index 0000000..92c40e9
--- /dev/null
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -0,0 +1,2474 @@
+/* //device/include/server/AudioFlinger/AudioFlinger.cpp
+**
+** Copyright 2007, 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.
+*/
+
+
+#define LOG_TAG "AudioFlinger"
+//#define LOG_NDEBUG 0
+
+#include <math.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <utils/IPCThreadState.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+
+#include <cutils/properties.h>
+
+#include <media/AudioTrack.h>
+#include <media/AudioRecord.h>
+
+#include <private/media/AudioTrackShared.h>
+
+#include <hardware_legacy/AudioHardwareInterface.h>
+
+#include "AudioMixer.h"
+#include "AudioFlinger.h"
+
+#ifdef WITH_A2DP
+#include "A2dpAudioInterface.h"
+#endif
+
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
+static const unsigned long kBufferRecoveryInUsecs = 2000;
+static const unsigned long kMaxBufferRecoveryInUsecs = 20000;
+static const float MAX_GAIN = 4096.0f;
+
+// retry counts for buffer fill timeout
+// 50 * ~20msecs = 1 second
+static const int8_t kMaxTrackRetries = 50;
+static const int8_t kMaxTrackStartupRetries = 50;
+
+static const int kStartSleepTime = 30000;
+static const int kStopSleepTime = 30000;
+
+// Maximum number of pending buffers allocated by OutputTrack::write()
+static const uint8_t kMaxOutputTrackBuffers = 5;
+
+
+#define AUDIOFLINGER_SECURITY_ENABLED 1
+
+// ----------------------------------------------------------------------------
+
+static bool recordingAllowed() {
+#ifndef HAVE_ANDROID_OS
+    return true;
+#endif
+#if AUDIOFLINGER_SECURITY_ENABLED
+    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+    bool ok = checkCallingPermission(String16("android.permission.RECORD_AUDIO"));
+    if (!ok) LOGE("Request requires android.permission.RECORD_AUDIO");
+    return ok;
+#else
+    if (!checkCallingPermission(String16("android.permission.RECORD_AUDIO")))
+        LOGW("WARNING: Need to add android.permission.RECORD_AUDIO to manifest");
+    return true;
+#endif
+}
+
+static bool settingsAllowed() {
+#ifndef HAVE_ANDROID_OS
+    return true;
+#endif
+#if AUDIOFLINGER_SECURITY_ENABLED
+    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+    bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
+    if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
+    return ok;
+#else
+    if (!checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS")))
+        LOGW("WARNING: Need to add android.permission.MODIFY_AUDIO_SETTINGS to manifest");
+    return true;
+#endif
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::AudioFlinger()
+    : BnAudioFlinger(),
+        mAudioHardware(0), mA2dpAudioInterface(0),
+        mA2dpEnabled(false), mA2dpEnabledReq(false),
+        mForcedSpeakerCount(0), mForcedRoute(0), mRouteRestoreTime(0), mMusicMuteSaved(false)
+{
+    mHardwareStatus = AUDIO_HW_IDLE;
+    mAudioHardware = AudioHardwareInterface::create();
+    mHardwareStatus = AUDIO_HW_INIT;
+    if (mAudioHardware->initCheck() == NO_ERROR) {
+        // open 16-bit output stream for s/w mixer
+        mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
+        status_t status;
+        AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+        mHardwareStatus = AUDIO_HW_IDLE;
+        if (hwOutput) {
+            mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE);
+        } else {
+            LOGE("Failed to initialize hardware output stream, status: %d", status);
+        }
+        
+#ifdef WITH_A2DP
+        // Create A2DP interface
+        mA2dpAudioInterface = new A2dpAudioInterface();
+        AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+        if (a2dpOutput) {
+            mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP);
+            if (hwOutput) {  
+                uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate();
+                MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread,
+                                                            hwOutput->sampleRate(),
+                                                            AudioSystem::PCM_16_BIT,
+                                                            hwOutput->channelCount(),
+                                                            frameCount);
+                mHardwareMixerThread->setOuputTrack(a2dpOutTrack);                
+            }
+        } else {
+            LOGE("Failed to initialize A2DP output stream, status: %d", status);
+        }
+#endif
+ 
+        // FIXME - this should come from settings
+        setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+        setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+        setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
+        setMode(AudioSystem::MODE_NORMAL);
+
+        setMasterVolume(1.0f);
+        setMasterMute(false);
+
+        // Start record thread
+        mAudioRecordThread = new AudioRecordThread(mAudioHardware);
+        if (mAudioRecordThread != 0) {
+            mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);            
+        }
+     } else {
+        LOGE("Couldn't even initialize the stubbed audio hardware!");
+    }
+}
+
+AudioFlinger::~AudioFlinger()
+{
+    if (mAudioRecordThread != 0) {
+        mAudioRecordThread->exit();
+        mAudioRecordThread.clear();        
+    }
+    mHardwareMixerThread.clear();
+    delete mAudioHardware;
+    // deleting mA2dpAudioInterface also deletes mA2dpOutput;
+#ifdef WITH_A2DP
+    mA2dpMixerThread.clear();
+    delete mA2dpAudioInterface;
+#endif
+}
+
+
+#ifdef WITH_A2DP
+void AudioFlinger::setA2dpEnabled(bool enable)
+{
+    LOGV_IF(enable, "set output to A2DP\n");
+    LOGV_IF(!enable, "set output to hardware audio\n");
+
+    mA2dpEnabledReq = enable;
+    mA2dpMixerThread->wakeUp();
+}
+#endif // WITH_A2DP
+
+bool AudioFlinger::streamForcedToSpeaker(int streamType)
+{
+    // NOTE that streams listed here must not be routed to A2DP by default:
+    // AudioSystem::routedToA2dpOutput(streamType) == false
+    return (streamType == AudioSystem::RING ||
+            streamType == AudioSystem::ALARM ||
+            streamType == AudioSystem::NOTIFICATION);
+}
+
+status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    result.append("Clients:\n");
+    for (size_t i = 0; i < mClients.size(); ++i) {
+        wp<Client> wClient = mClients.valueAt(i);
+        if (wClient != 0) {
+            sp<Client> client = wClient.promote();
+            if (client != 0) {
+                snprintf(buffer, SIZE, "  pid: %d\n", client->pid());
+                result.append(buffer);
+            }
+        }
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+
+status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Hardware status: %d\n", mHardwareStatus);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "Permission Denial: "
+            "can't dump AudioFlinger from pid=%d, uid=%d\n",
+            IPCThreadState::self()->getCallingPid(),
+            IPCThreadState::self()->getCallingUid());
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
+{
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        dumpPermissionDenial(fd, args);
+    } else {
+        AutoMutex lock(&mLock);
+
+        dumpClients(fd, args);
+        dumpInternals(fd, args);
+        mHardwareMixerThread->dump(fd, args);
+#ifdef WITH_A2DP
+        mA2dpMixerThread->dump(fd, args);
+#endif
+
+        // dump record client
+        if (mAudioRecordThread != 0) mAudioRecordThread->dump(fd, args);
+
+        if (mAudioHardware) {
+            mAudioHardware->dumpState(fd, args);
+        }
+    }
+    return NO_ERROR;
+}
+
+// IAudioFlinger interface
+
+
+sp<IAudioTrack> AudioFlinger::createTrack(
+        pid_t pid,
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int frameCount,
+        uint32_t flags,
+        const sp<IMemory>& sharedBuffer,
+        status_t *status)
+{
+    sp<MixerThread::Track> track;
+    sp<TrackHandle> trackHandle;
+    sp<Client> client;
+    wp<Client> wclient;
+    status_t lStatus;
+
+    if (streamType >= AudioSystem::NUM_STREAM_TYPES) {
+        LOGE("invalid stream type");
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    {
+        Mutex::Autolock _l(mLock);
+
+        wclient = mClients.valueFor(pid);
+
+        if (wclient != NULL) {
+            client = wclient.promote();
+        } else {
+            client = new Client(this, pid);
+            mClients.add(pid, client);
+        }
+#ifdef WITH_A2DP
+        if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) {
+            track = mA2dpMixerThread->createTrack(client, streamType, sampleRate, format,
+                    channelCount, frameCount, sharedBuffer, &lStatus);            
+        } else 
+#endif
+        {
+            track = mHardwareMixerThread->createTrack(client, streamType, sampleRate, format,
+                    channelCount, frameCount, sharedBuffer, &lStatus);            
+        }
+        if (track != NULL) {
+            trackHandle = new TrackHandle(track);
+            lStatus = NO_ERROR;            
+        }
+    }
+
+Exit:
+    if(status) {
+        *status = lStatus;
+    }
+    return trackHandle;
+}
+
+uint32_t AudioFlinger::sampleRate(int output) const
+{
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->sampleRate();
+     }
+#endif
+     return mHardwareMixerThread->sampleRate();
+}
+
+int AudioFlinger::channelCount(int output) const
+{
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->channelCount();
+     }
+#endif
+     return mHardwareMixerThread->channelCount();
+}
+
+int AudioFlinger::format(int output) const
+{
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->format();
+     }
+#endif
+     return mHardwareMixerThread->format();
+}
+
+size_t AudioFlinger::frameCount(int output) const
+{
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->frameCount();
+     }
+#endif
+     return mHardwareMixerThread->frameCount();
+}
+
+uint32_t AudioFlinger::latency(int output) const
+{
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->latency();
+     }
+#endif
+     return mHardwareMixerThread->latency();
+}
+
+status_t AudioFlinger::setMasterVolume(float value)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    // when hw supports master volume, don't scale in sw mixer
+    AutoMutex lock(mHardwareLock);
+    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+    if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
+        value = 1.0f;
+    }
+    mHardwareStatus = AUDIO_HW_IDLE;
+    mHardwareMixerThread->setMasterVolume(value);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setMasterVolume(value);
+#endif
+    
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)
+{
+    status_t err = NO_ERROR;
+
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    if ((mode < AudioSystem::MODE_CURRENT) || (mode >= AudioSystem::NUM_MODES)) {
+        LOGW("Illegal value: setRouting(%d, %u, %u)", mode, routes, mask);
+        return BAD_VALUE;
+    }
+
+#ifdef WITH_A2DP
+    LOGD("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(), IPCThreadState::self()->getCallingPid());
+    if (mode == AudioSystem::MODE_NORMAL && 
+            (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
+        AutoMutex lock(&mLock);
+
+        bool enableA2dp = false;
+        if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
+            enableA2dp = true;
+        }
+        setA2dpEnabled(enableA2dp);
+        LOGV("setOutput done\n");
+    }
+#endif
+
+    // do nothing if only A2DP routing is affected
+    mask &= ~AudioSystem::ROUTE_BLUETOOTH_A2DP;
+    if (mask) {
+        AutoMutex lock(mHardwareLock);
+        mHardwareStatus = AUDIO_HW_GET_ROUTING;
+        uint32_t r;
+        err = mAudioHardware->getRouting(mode, &r);
+        if (err == NO_ERROR) {
+            r = (r & ~mask) | (routes & mask);
+            if (mode == AudioSystem::MODE_NORMAL || 
+                (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
+                mSavedRoute = r;
+                r |= mForcedRoute;
+                LOGV("setRouting mSavedRoute %08x mForcedRoute %08x\n", mSavedRoute, mForcedRoute);
+            }
+            mHardwareStatus = AUDIO_HW_SET_ROUTING;
+            err = mAudioHardware->setRouting(mode, r);
+        }
+        mHardwareStatus = AUDIO_HW_IDLE;
+    }
+    return err;
+}
+
+uint32_t AudioFlinger::getRouting(int mode) const
+{
+    uint32_t routes = 0;
+    if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
+        if (mode == AudioSystem::MODE_NORMAL || 
+            (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
+            routes = mSavedRoute;                
+        } else {
+            mHardwareStatus = AUDIO_HW_GET_ROUTING;
+            mAudioHardware->getRouting(mode, &routes);
+            mHardwareStatus = AUDIO_HW_IDLE;
+        }
+    } else {
+        LOGW("Illegal value: getRouting(%d)", mode);
+    }
+    return routes;
+}
+
+status_t AudioFlinger::setMode(int mode)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) {
+        LOGW("Illegal value: setMode(%d)", mode);
+        return BAD_VALUE;
+    }
+
+    AutoMutex lock(mHardwareLock);
+    mHardwareStatus = AUDIO_HW_SET_MODE;
+    status_t ret = mAudioHardware->setMode(mode);
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return ret;
+}
+
+int AudioFlinger::getMode() const
+{
+    int mode = AudioSystem::MODE_INVALID;
+    mHardwareStatus = AUDIO_HW_SET_MODE;
+    mAudioHardware->getMode(&mode);
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return mode;
+}
+
+status_t AudioFlinger::setMicMute(bool state)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    AutoMutex lock(mHardwareLock);
+    mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
+    status_t ret = mAudioHardware->setMicMute(state);
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return ret;
+}
+
+bool AudioFlinger::getMicMute() const
+{
+    bool state = AudioSystem::MODE_INVALID;
+    mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
+    mAudioHardware->getMicMute(&state);
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return state;
+}
+
+status_t AudioFlinger::setMasterMute(bool muted)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    mHardwareMixerThread->setMasterMute(muted);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setMasterMute(muted);
+#endif
+    return NO_ERROR;
+}
+
+float AudioFlinger::masterVolume() const
+{
+    return mHardwareMixerThread->masterVolume();
+}
+
+bool AudioFlinger::masterMute() const
+{
+    return mHardwareMixerThread->masterMute();
+}
+
+status_t AudioFlinger::setStreamVolume(int stream, float value)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+        return BAD_VALUE;
+    }
+
+    mHardwareMixerThread->setStreamVolume(stream, value);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setStreamVolume(stream, value);
+#endif
+
+    status_t ret = NO_ERROR;
+    if (stream == AudioSystem::VOICE_CALL ||
+        stream == AudioSystem::BLUETOOTH_SCO) {
+        
+        if (stream == AudioSystem::VOICE_CALL) {
+            value = (float)AudioSystem::logToLinear(value)/100.0f;
+        } else { // (type == AudioSystem::BLUETOOTH_SCO)
+            value = 1.0f;
+        }
+
+        AutoMutex lock(mHardwareLock);
+        mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
+        ret = mAudioHardware->setVoiceVolume(value);
+        mHardwareStatus = AUDIO_HW_IDLE;
+    }
+
+    return ret;
+}
+
+status_t AudioFlinger::setStreamMute(int stream, bool muted)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+        return BAD_VALUE;
+    }
+    
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setStreamMute(stream, muted);
+#endif
+    if (stream == AudioSystem::MUSIC) 
+    {
+        AutoMutex lock(&mHardwareLock);
+        if (mForcedRoute != 0)
+            mMusicMuteSaved = muted;
+        else
+            mHardwareMixerThread->setStreamMute(stream, muted);
+    } else {
+        mHardwareMixerThread->setStreamMute(stream, muted);
+    }
+
+    
+
+    return NO_ERROR;
+}
+
+float AudioFlinger::streamVolume(int stream) const
+{
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+        return 0.0f;
+    }
+    return mHardwareMixerThread->streamVolume(stream);
+}
+
+bool AudioFlinger::streamMute(int stream) const
+{
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+        return true;
+    }
+    
+    if (stream == AudioSystem::MUSIC && mForcedRoute != 0) 
+    {
+        return mMusicMuteSaved;
+    }
+    return mHardwareMixerThread->streamMute(stream);
+}
+
+bool AudioFlinger::isMusicActive() const
+{
+ #ifdef WITH_A2DP
+     if (isA2dpEnabled()) {
+         return mA2dpMixerThread->isMusicActive();
+     }
+ #endif
+    return mHardwareMixerThread->isMusicActive();
+}
+
+status_t AudioFlinger::setParameter(const char* key, const char* value)
+{
+    status_t result, result2;
+    AutoMutex lock(mHardwareLock);
+    mHardwareStatus = AUDIO_SET_PARAMETER;
+    
+    LOGV("setParameter() key %s, value %s, tid %d, calling tid %d", key, value, gettid(), IPCThreadState::self()->getCallingPid());
+    result = mAudioHardware->setParameter(key, value);
+    if (mA2dpAudioInterface) {
+        result2 = mA2dpAudioInterface->setParameter(key, value);
+        if (result2)
+            result = result2;
+    }
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return result;
+}
+
+size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
+}
+
+void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
+{
+    
+    LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid());
+    Mutex::Autolock _l(mLock);
+
+    sp<IBinder> binder = client->asBinder();
+    if (mNotificationClients.indexOf(binder) < 0) {
+        LOGV("Adding notification client %p", binder.get());
+        binder->linkToDeath(this);
+        mNotificationClients.add(binder);
+        client->a2dpEnabledChanged(isA2dpEnabled());
+    }
+}
+
+void AudioFlinger::binderDied(const wp<IBinder>& who) {
+    
+    LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
+    Mutex::Autolock _l(mLock);
+
+    IBinder *binder = who.unsafe_get();
+
+    if (binder != NULL) {
+        int index = mNotificationClients.indexOf(binder);
+        if (index >= 0) {
+            LOGV("Removing notification client %p", binder);
+            mNotificationClients.removeAt(index);
+        }
+    }
+}
+
+void AudioFlinger::handleOutputSwitch()
+{
+    if (mA2dpEnabled != mA2dpEnabledReq)
+    {
+        Mutex::Autolock _l(mLock);
+
+        if (mA2dpEnabled != mA2dpEnabledReq)
+        {
+            mA2dpEnabled = mA2dpEnabledReq;
+            SortedVector < sp<MixerThread::Track> > tracks;
+            SortedVector < wp<MixerThread::Track> > activeTracks;
+            
+            // We hold mA2dpMixerThread mLock already 
+            Mutex::Autolock _l(mHardwareMixerThread->mLock);
+            
+            // Transfer tracks playing on MUSIC stream from one mixer to the other
+            if (mA2dpEnabled) {
+                mHardwareMixerThread->getTracks(tracks, activeTracks);
+                mA2dpMixerThread->putTracks(tracks, activeTracks);
+            } else {
+                mA2dpMixerThread->getTracks(tracks, activeTracks);
+                mHardwareMixerThread->putTracks(tracks, activeTracks);
+            }            
+            
+            // Notify AudioSystem of the A2DP activation/deactivation
+            size_t size = mNotificationClients.size();
+            for (size_t i = 0; i < size; i++) {
+                sp<IBinder> binder = mNotificationClients.itemAt(i).promote();
+                if (binder != NULL) {
+                    LOGV("Notifying output change to client %p", binder.get());
+                    sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
+                    client->a2dpEnabledChanged(mA2dpEnabled);
+                }
+            }
+
+            mHardwareMixerThread->wakeUp();
+        }
+    }
+}
+
+void AudioFlinger::removeClient(pid_t pid)
+{
+    LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
+    Mutex::Autolock _l(mLock);
+    mClients.removeItem(pid);
+}
+
+void AudioFlinger::wakeUp()
+{
+    mHardwareMixerThread->wakeUp();
+#ifdef WITH_A2DP
+    mA2dpMixerThread->wakeUp();
+#endif // WITH_A2DP
+}
+
+bool AudioFlinger::isA2dpEnabled() const
+{
+    return mA2dpEnabledReq;
+}
+
+void AudioFlinger::handleForcedSpeakerRoute(int command)
+{
+    switch(command) {
+    case ACTIVE_TRACK_ADDED:
+        {
+            AutoMutex lock(mHardwareLock);
+            if (mForcedSpeakerCount++ == 0) {
+                mRouteRestoreTime = 0;
+                mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
+                if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+                    LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+                    mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
+                    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+                    mAudioHardware->setMasterVolume(0);
+                    usleep(mHardwareMixerThread->latency()*1000);
+                    mHardwareStatus = AUDIO_HW_SET_ROUTING;
+                    mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+                    mHardwareStatus = AUDIO_HW_IDLE;
+                    // delay track start so that audio hardware has time to siwtch routes
+                    usleep(kStartSleepTime);
+                    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+                    mAudioHardware->setMasterVolume(mHardwareMixerThread->masterVolume());
+                    mHardwareStatus = AUDIO_HW_IDLE;
+                }
+                mForcedRoute = AudioSystem::ROUTE_SPEAKER;
+            }
+            LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
+        }
+        break;
+    case ACTIVE_TRACK_REMOVED:
+        {
+            AutoMutex lock(mHardwareLock);
+            if (mForcedSpeakerCount > 0){
+                if (--mForcedSpeakerCount == 0) {
+                    mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000);
+                }
+                LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount);            
+            } else {
+                LOGE("mForcedSpeakerCount is already zero");            
+            }            
+        }
+        break;
+    case CHECK_ROUTE_RESTORE_TIME:
+    case FORCE_ROUTE_RESTORE:
+        if (mRouteRestoreTime) {
+            AutoMutex lock(mHardwareLock);
+            if (mRouteRestoreTime && 
+               (systemTime() > mRouteRestoreTime || command == FORCE_ROUTE_RESTORE)) {
+                mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, mMusicMuteSaved);
+                mForcedRoute = 0;
+                if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+                    mHardwareStatus = AUDIO_HW_SET_ROUTING;
+                    mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute);
+                    mHardwareStatus = AUDIO_HW_IDLE;
+                    LOGV("Route forced to Speaker OFF %08x", mSavedRoute);
+                }
+                mRouteRestoreTime = 0;
+            }
+        }
+        break;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType)
+    :   Thread(false),
+        mAudioFlinger(audioFlinger), mAudioMixer(0), mOutput(output), mOutputType(outputType), 
+        mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
+        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
+        mInWrite(false)
+{
+    mSampleRate = output->sampleRate();
+    mChannelCount = output->channelCount();
+
+    // FIXME - Current mixer implementation only supports stereo output
+    if (mChannelCount == 1) {
+        LOGE("Invalid audio hardware channel count");
+    }
+
+    mFormat = output->format();
+    mFrameCount = output->bufferSize() / output->channelCount() / sizeof(int16_t);
+    mAudioMixer = new AudioMixer(mFrameCount, output->sampleRate());
+
+    // FIXME - Current mixer implementation only supports stereo output: Always
+    // Allocate a stereo buffer even if HW output is mono.
+    mMixBuffer = new int16_t[mFrameCount * 2];
+    memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+}
+
+AudioFlinger::MixerThread::~MixerThread()
+{
+    delete [] mMixBuffer;
+    delete mAudioMixer;
+}
+
+status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    dumpTracks(fd, args);
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Output %d mixer thread tracks\n", mOutputType);
+    result.append(buffer);
+    result.append("   Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        wp<Track> wTrack = mTracks[i];
+        if (wTrack != 0) {
+            sp<Track> track = wTrack.promote();
+            if (track != 0) {
+                track->dump(buffer, SIZE);
+                result.append(buffer);
+            }
+        }
+    }
+
+    snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType);
+    result.append(buffer);
+    result.append("   Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+    for (size_t i = 0; i < mActiveTracks.size(); ++i) {
+        wp<Track> wTrack = mTracks[i];
+        if (wTrack != 0) {
+            sp<Track> track = wTrack.promote();
+            if (track != 0) {
+                track->dump(buffer, SIZE);
+                result.append(buffer);
+            }
+        }
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Output %d mixer thread internals\n", mOutputType);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
+    result.append(buffer);
+    snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "standby: %d\n", mStandby);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// Thread virtuals
+bool AudioFlinger::MixerThread::threadLoop()
+{
+    unsigned long sleepTime = kBufferRecoveryInUsecs;
+    int16_t* curBuf = mMixBuffer;
+    Vector< sp<Track> > tracksToRemove;
+    size_t enabledTracks = 0;
+    nsecs_t standbyTime = systemTime();   
+    size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
+    nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
+
+#ifdef WITH_A2DP
+    bool outputTrackActive = false;
+#endif
+
+    do {
+        enabledTracks = 0;
+        { // scope for the mLock
+        
+            Mutex::Autolock _l(mLock);
+
+#ifdef WITH_A2DP
+            if (mOutputType == AudioSystem::AUDIO_OUTPUT_A2DP) {
+                mAudioFlinger->handleOutputSwitch();
+            }
+            if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) {
+                if (outputTrackActive) {
+                    mOutputTrack->stop();
+                    outputTrackActive = false;
+                }
+            }
+#endif
+
+            const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
+
+            // put audio hardware into standby after short delay
+            if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
+                // wait until we have something to do...
+                LOGV("Audio hardware entering standby, output %d\n", mOutputType);
+//                mAudioFlinger->mHardwareStatus = AUDIO_HW_STANDBY;
+                if (!mStandby) {
+                    mOutput->standby();
+                    mStandby = true;
+                }
+                
+#ifdef WITH_A2DP
+                if (outputTrackActive) {
+                    mOutputTrack->stop();
+                    outputTrackActive = false;
+                }
+#endif
+                if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+                    mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE);
+                }                
+//                mHardwareStatus = AUDIO_HW_IDLE;
+                // we're about to wait, flush the binder command buffer
+                IPCThreadState::self()->flushCommands();
+                mWaitWorkCV.wait(mLock);
+                LOGV("Audio hardware exiting standby, output %d\n", mOutputType);
+                
+                if (mMasterMute == false) {
+                    char value[PROPERTY_VALUE_MAX];
+                    property_get("ro.audio.silent", value, "0");
+                    if (atoi(value)) {
+                        LOGD("Silence is golden");
+                        setMasterMute(true);
+                    }                    
+                }
+                
+                standbyTime = systemTime() + kStandbyTimeInNsecs;
+                continue;
+            }
+
+            // Forced route to speaker is handled by hardware mixer thread
+            if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+                mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME);
+            }
+
+            // find out which tracks need to be processed
+            size_t count = activeTracks.size();
+            for (size_t i=0 ; i<count ; i++) {
+                sp<Track> t = activeTracks[i].promote();
+                if (t == 0) continue;
+
+                Track* const track = t.get();
+                audio_track_cblk_t* cblk = track->cblk();
+
+                // The first time a track is added we wait
+                // for all its buffers to be filled before processing it
+                mAudioMixer->setActiveTrack(track->name());
+                if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+                        !track->isPaused())
+                {
+                    //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+
+                    // compute volume for this track
+                    int16_t left, right;
+                    if (track->isMuted() || mMasterMute || track->isPausing()) {
+                        left = right = 0;
+                        if (track->isPausing()) {
+                            LOGV("paused(%d)", track->name());
+                            track->setPaused();
+                        }
+                    } else {
+                        float typeVolume = mStreamTypes[track->type()].volume;
+                        float v = mMasterVolume * typeVolume;
+                        float v_clamped = v * cblk->volume[0];
+                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+                        left = int16_t(v_clamped);
+                        v_clamped = v * cblk->volume[1];
+                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+                        right = int16_t(v_clamped);
+                    }
+
+                    // XXX: these things DON'T need to be done each time
+                    mAudioMixer->setBufferProvider(track);
+                    mAudioMixer->enable(AudioMixer::MIXING);
+
+                    int param;
+                    if ( track->mFillingUpStatus == Track::FS_FILLED) {
+                        // no ramp for the first volume setting
+                        track->mFillingUpStatus = Track::FS_ACTIVE;
+                        if (track->mState == TrackBase::RESUMING) {
+                            track->mState = TrackBase::ACTIVE;
+                            param = AudioMixer::RAMP_VOLUME;
+                        } else {
+                            param = AudioMixer::VOLUME;
+                        }
+                    } else {
+                        param = AudioMixer::RAMP_VOLUME;
+                    }
+                    mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
+                    mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
+                    mAudioMixer->setParameter(
+                        AudioMixer::TRACK,
+                        AudioMixer::FORMAT, track->format());
+                    mAudioMixer->setParameter(
+                        AudioMixer::TRACK,
+                        AudioMixer::CHANNEL_COUNT, track->channelCount());
+                    mAudioMixer->setParameter(
+                        AudioMixer::RESAMPLE,
+                        AudioMixer::SAMPLE_RATE,
+                        int(cblk->sampleRate));
+
+                    // reset retry count
+                    track->mRetryCount = kMaxTrackRetries;
+                    enabledTracks++;
+                } else {
+                    //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+                    if (track->isStopped()) {
+                        track->reset();
+                    }
+                    if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+                        // We have consumed all the buffers of this track.
+                        // Remove it from the list of active tracks.
+                        LOGV("remove(%d) from active list", track->name());
+                        tracksToRemove.add(track);
+                    } else {
+                        // No buffers for this track. Give it a few chances to
+                        // fill a buffer, then remove it from active list.
+                        if (--(track->mRetryCount) <= 0) {
+                            LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+                            tracksToRemove.add(track);
+                        }
+                    }
+                    // LOGV("disable(%d)", track->name());
+                    mAudioMixer->disable(AudioMixer::MIXING);
+                }
+            }
+
+            // remove all the tracks that need to be...
+            count = tracksToRemove.size();
+            if (UNLIKELY(count)) {
+                for (size_t i=0 ; i<count ; i++) {
+                    const sp<Track>& track = tracksToRemove[i];
+                    removeActiveTrack(track);
+                    if (track->isTerminated()) {
+                        mTracks.remove(track);
+                        deleteTrackName(track->mName);
+                    }
+                }
+            }  
+       }
+        
+        if (LIKELY(enabledTracks)) {
+            // mix buffers...
+            mAudioMixer->process(curBuf);
+
+#ifdef WITH_A2DP
+            if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
+                if (!outputTrackActive) {
+                    LOGV("starting output track in mixer for output %d", mOutputType);
+                    mOutputTrack->start();
+                    outputTrackActive = true;
+                }
+                mOutputTrack->write(curBuf, mFrameCount);
+            }
+#endif
+
+            // output audio to hardware
+            mLastWriteTime = systemTime();
+            mInWrite = true;
+            mOutput->write(curBuf, mixBufferSize);
+            mNumWrites++;
+            mInWrite = false;
+            mStandby = false;
+            nsecs_t temp = systemTime();
+            standbyTime = temp + kStandbyTimeInNsecs;
+            nsecs_t delta = temp - mLastWriteTime;
+            if (delta > maxPeriod) {
+                LOGW("write blocked for %llu msecs", ns2ms(delta));
+                mNumDelayedWrites++;
+            }
+            sleepTime = kBufferRecoveryInUsecs;
+        } else {         
+#ifdef WITH_A2DP
+            if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
+                if (outputTrackActive) {
+                    mOutputTrack->write(curBuf, 0);
+                    if (mOutputTrack->bufferQueueEmpty()) {
+                        mOutputTrack->stop();
+                        outputTrackActive = false;
+                    } else {
+                        standbyTime = systemTime() + kStandbyTimeInNsecs;
+                    }
+                }
+            }
+#endif
+            // There was nothing to mix this round, which means all
+            // active tracks were late. Sleep a little bit to give
+            // them another chance. If we're too late, the audio
+            // hardware will zero-fill for us.
+            //LOGV("no buffers - usleep(%lu)", sleepTime);
+            usleep(sleepTime);
+            if (sleepTime < kMaxBufferRecoveryInUsecs) {
+                sleepTime += kBufferRecoveryInUsecs;
+            }
+        }
+
+        // finally let go of all our tracks, without the lock held
+        // since we can't guarantee the destructors won't acquire that
+        // same lock.
+        tracksToRemove.clear();
+    } while (true);
+
+    return false;
+}
+
+status_t AudioFlinger::MixerThread::readyToRun()
+{
+    if (mSampleRate == 0) {
+        LOGE("No working audio driver found.");
+        return NO_INIT;
+    }
+    LOGI("AudioFlinger's thread ready to run for output %d", mOutputType);
+    return NO_ERROR;
+}
+
+void AudioFlinger::MixerThread::onFirstRef()
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType);
+
+    run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+
+sp<AudioFlinger::MixerThread::Track>  AudioFlinger::MixerThread::createTrack(
+        const sp<AudioFlinger::Client>& client,
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int frameCount,
+        const sp<IMemory>& sharedBuffer,
+        status_t *status)
+{
+    sp<Track> track;
+    status_t lStatus;
+    
+    // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
+        LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    {
+        Mutex::Autolock _l(mLock);
+
+        if (mSampleRate == 0) {
+            LOGE("Audio driver not initialized.");
+            lStatus = NO_INIT;
+            goto Exit;
+        }
+
+        track = new Track(this, client, streamType, sampleRate, format,
+                channelCount, frameCount, sharedBuffer);
+        if (track->getCblk() == NULL) {
+            track.clear();
+            lStatus = NO_MEMORY;
+            goto Exit;
+        }
+        mTracks.add(track);
+        lStatus = NO_ERROR;
+    }
+
+Exit:
+    if(status) {
+        *status = lStatus;
+    }
+    return track;
+}
+
+void AudioFlinger::MixerThread::getTracks(
+        SortedVector < sp<Track> >& tracks,
+        SortedVector < wp<Track> >& activeTracks)
+{
+    size_t size = mTracks.size();
+    LOGV ("MixerThread::getTracks() for output %d, mTracks.size %d, mActiveTracks.size %d", mOutputType,  mTracks.size(), mActiveTracks.size());
+    for (size_t i = 0; i < size; i++) {
+        sp<Track> t = mTracks[i];
+        if (AudioSystem::routedToA2dpOutput(t->mStreamType)) {
+            tracks.add(t);
+            int j = mActiveTracks.indexOf(t);
+            if (j >= 0) {
+                t = mActiveTracks[j].promote();
+                if (t != NULL) {
+                    activeTracks.add(t);                                    
+                }                            
+            }
+        }
+    }
+
+    size = activeTracks.size();
+    for (size_t i = 0; i < size; i++) {
+        removeActiveTrack(activeTracks[i]);
+    }
+    
+    size = tracks.size();
+    for (size_t i = 0; i < size; i++) {
+        sp<Track> t = tracks[i];
+        mTracks.remove(t);
+        deleteTrackName(t->name());
+    }
+}
+
+void AudioFlinger::MixerThread::putTracks(
+        SortedVector < sp<Track> >& tracks,
+        SortedVector < wp<Track> >& activeTracks)
+{
+
+    LOGV ("MixerThread::putTracks() for output %d, tracks.size %d, activeTracks.size %d", mOutputType,  tracks.size(), activeTracks.size());
+
+    size_t size = tracks.size();
+    for (size_t i = 0; i < size ; i++) {
+        sp<Track> t = tracks[i];
+        int name = getTrackName();
+
+        if (name < 0) return;
+        
+        t->mName = name;
+        t->mMixerThread = this;
+        mTracks.add(t);
+
+        int j = activeTracks.indexOf(t);
+        if (j >= 0) {
+            addActiveTrack(t);
+        }            
+    }
+}
+
+uint32_t AudioFlinger::MixerThread::sampleRate() const
+{
+    return mSampleRate;
+}
+
+int AudioFlinger::MixerThread::channelCount() const
+{
+    return mChannelCount;
+}
+
+int AudioFlinger::MixerThread::format() const
+{
+    return mFormat;
+}
+
+size_t AudioFlinger::MixerThread::frameCount() const
+{
+    return mFrameCount;
+}
+
+uint32_t AudioFlinger::MixerThread::latency() const
+{
+    if (mOutput) {
+        return mOutput->latency();
+    }
+    else {
+        return 0;
+    }
+}
+
+status_t AudioFlinger::MixerThread::setMasterVolume(float value)
+{
+    mMasterVolume = value;
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::setMasterMute(bool muted)
+{
+    mMasterMute = muted;
+    return NO_ERROR;
+}
+
+float AudioFlinger::MixerThread::masterVolume() const
+{
+    return mMasterVolume;
+}
+
+bool AudioFlinger::MixerThread::masterMute() const
+{
+    return mMasterMute;
+}
+
+status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value)
+{
+    mStreamTypes[stream].volume = value;
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted)
+{
+    mStreamTypes[stream].mute = muted;
+    return NO_ERROR;
+}
+
+float AudioFlinger::MixerThread::streamVolume(int stream) const
+{
+    return mStreamTypes[stream].volume;
+}
+
+bool AudioFlinger::MixerThread::streamMute(int stream) const
+{
+    return mStreamTypes[stream].mute;
+}
+
+bool AudioFlinger::MixerThread::isMusicActive() const
+{
+    size_t count = mActiveTracks.size();
+    for (size_t i = 0 ; i < count ; ++i) {
+        sp<Track> t = mActiveTracks[i].promote();
+        if (t == 0) continue;
+        Track* const track = t.get();
+        if (t->mStreamType == AudioSystem::MUSIC)
+            return true;
+    }
+    return false;
+}
+
+status_t AudioFlinger::MixerThread::addTrack(const sp<Track>& track)
+{
+    status_t status = ALREADY_EXISTS;
+    Mutex::Autolock _l(mLock);
+
+    // here the track could be either new, or restarted
+    // in both cases "unstop" the track
+    if (track->isPaused()) {
+        track->mState = TrackBase::RESUMING;
+        LOGV("PAUSED => RESUMING (%d)", track->name());
+    } else {
+        track->mState = TrackBase::ACTIVE;
+        LOGV("? => ACTIVE (%d)", track->name());
+    }
+    // set retry count for buffer fill
+    track->mRetryCount = kMaxTrackStartupRetries;
+    if (mActiveTracks.indexOf(track) < 0) {
+        // the track is newly added, make sure it fills up all its
+        // buffers before playing. This is to ensure the client will
+        // effectively get the latency it requested.
+        track->mFillingUpStatus = Track::FS_FILLING;
+        track->mResetDone = false;
+        addActiveTrack(track);
+        status = NO_ERROR;
+    }
+    
+    LOGV("mWaitWorkCV.broadcast");
+    mWaitWorkCV.broadcast();
+
+    return status;
+}
+
+void AudioFlinger::MixerThread::removeTrack(wp<Track> track, int name)
+{
+    Mutex::Autolock _l(mLock);
+    sp<Track> t = track.promote();
+    if (t!=NULL && (t->mState <= TrackBase::STOPPED)) {
+        remove_track_l(track, name);
+    }
+}
+
+void AudioFlinger::MixerThread::remove_track_l(wp<Track> track, int name)
+{
+    sp<Track> t = track.promote();
+    if (t!=NULL) {
+        t->reset();
+    }
+    deleteTrackName(name);
+    removeActiveTrack(track);
+    mWaitWorkCV.broadcast();
+}
+
+void AudioFlinger::MixerThread::destroyTrack(const sp<Track>& track)
+{
+    // NOTE: We're acquiring a strong reference on the track before
+    // acquiring the lock, this is to make sure removing it from
+    // mTracks won't cause the destructor to be called while the lock is
+    // held (note that technically, 'track' could be a reference to an item
+    // in mTracks, which is why we need to do this).
+    sp<Track> keep(track);
+    Mutex::Autolock _l(mLock);
+    track->mState = TrackBase::TERMINATED;
+    if (mActiveTracks.indexOf(track) < 0) {
+        LOGV("remove track (%d) and delete from mixer", track->name());
+        mTracks.remove(track);
+        deleteTrackName(keep->name());
+    }
+}
+
+
+void AudioFlinger::MixerThread::addActiveTrack(const wp<Track>& t)
+{
+    mActiveTracks.add(t);
+
+    // Force routing to speaker for certain stream types
+    // The forced routing to speaker is managed by hardware mixer
+    if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+        sp<Track> track = t.promote();
+        if (track == NULL) return;
+   
+        if (streamForcedToSpeaker(track->type())) {
+            mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED);
+        }        
+    }
+}
+
+void AudioFlinger::MixerThread::removeActiveTrack(const wp<Track>& t)
+{
+    mActiveTracks.remove(t);
+
+    // Force routing to speaker for certain stream types
+    // The forced routing to speaker is managed by hardware mixer
+    if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+        sp<Track> track = t.promote();
+        if (track == NULL) return;
+
+        if (streamForcedToSpeaker(track->type())) {
+            mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
+        }
+    }
+}
+
+int AudioFlinger::MixerThread::getTrackName()
+{
+    return mAudioMixer->getTrackName();
+}
+
+void AudioFlinger::MixerThread::deleteTrackName(int name)
+{
+    mAudioMixer->deleteTrackName(name);
+}
+
+size_t AudioFlinger::MixerThread::getOutputFrameCount() 
+{
+    return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t);
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::TrackBase::TrackBase(
+            const sp<MixerThread>& mixerThread,
+            const sp<Client>& client,
+            int streamType,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int frameCount,
+            uint32_t flags,
+            const sp<IMemory>& sharedBuffer)
+    :   RefBase(),
+        mMixerThread(mixerThread),
+        mClient(client),
+        mStreamType(streamType),
+        mFrameCount(0),
+        mState(IDLE),
+        mClientTid(-1),
+        mFormat(format),
+        mFlags(flags & ~SYSTEM_FLAGS_MASK)
+{
+    mName = mixerThread->getTrackName();
+    LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+    if (mName < 0) {
+        LOGE("no more track names availlable");
+        return;
+    }
+
+    LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
+
+    // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
+   size_t size = sizeof(audio_track_cblk_t);
+   size_t bufferSize = frameCount*channelCount*sizeof(int16_t);
+   if (sharedBuffer == 0) {
+       size += bufferSize;
+   }
+
+   if (client != NULL) {
+        mCblkMemory = client->heap()->allocate(size);
+        if (mCblkMemory != 0) {
+            mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
+            if (mCblk) { // construct the shared structure in-place.
+                new(mCblk) audio_track_cblk_t();
+                // clear all buffers
+                mCblk->frameCount = frameCount;
+                mCblk->sampleRate = sampleRate;
+                mCblk->channels = channelCount;
+                if (sharedBuffer == 0) {
+                    mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+                    memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+                    // Force underrun condition to avoid false underrun callback until first data is
+                    // written to buffer
+                    mCblk->flowControlFlag = 1;
+                } else {
+                    mBuffer = sharedBuffer->pointer();
+                }
+                mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+            }
+        } else {
+            LOGE("not enough memory for AudioTrack size=%u", size);
+            client->heap()->dump("AudioTrack");
+            return;
+        }
+   } else {
+       mCblk = (audio_track_cblk_t *)(new uint8_t[size]);
+       if (mCblk) { // construct the shared structure in-place.
+           new(mCblk) audio_track_cblk_t();
+           // clear all buffers
+           mCblk->frameCount = frameCount;
+           mCblk->sampleRate = sampleRate;
+           mCblk->channels = channelCount;
+           mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+           memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+           // Force underrun condition to avoid false underrun callback until first data is
+           // written to buffer
+           mCblk->flowControlFlag = 1;
+           mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+       }
+   }
+}
+
+AudioFlinger::MixerThread::TrackBase::~TrackBase()
+{
+    if (mCblk) {
+        mCblk->~audio_track_cblk_t();   // destroy our shared-structure.        
+    }
+    mCblkMemory.clear();            // and free the shared memory
+    mClient.clear();
+}
+
+void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+{
+    buffer->raw = 0;
+    mFrameCount = buffer->frameCount;
+    step();
+    buffer->frameCount = 0;
+}
+
+bool AudioFlinger::MixerThread::TrackBase::step() {
+    bool result;
+    audio_track_cblk_t* cblk = this->cblk();
+
+    result = cblk->stepServer(mFrameCount);
+    if (!result) {
+        LOGV("stepServer failed acquiring cblk mutex");
+        mFlags |= STEPSERVER_FAILED;
+    }
+    return result;
+}
+
+void AudioFlinger::MixerThread::TrackBase::reset() {
+    audio_track_cblk_t* cblk = this->cblk();
+
+    cblk->user = 0;
+    cblk->server = 0;
+    cblk->userBase = 0;
+    cblk->serverBase = 0;
+    mFlags &= (uint32_t)(~SYSTEM_FLAGS_MASK);
+    LOGV("TrackBase::reset");
+}
+
+sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const
+{
+    return mCblkMemory;
+}
+
+int AudioFlinger::MixerThread::TrackBase::sampleRate() const {
+    return mCblk->sampleRate;
+}
+
+int AudioFlinger::MixerThread::TrackBase::channelCount() const {
+    return mCblk->channels;
+}
+
+void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+    audio_track_cblk_t* cblk = this->cblk();
+    int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
+    int16_t *bufferEnd = bufferStart + frames * cblk->channels;
+
+    // Check validity of returned pointer in case the track control block would have been corrupted.
+    if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd) {
+        LOGW("TrackBase::getBuffer buffer out of range:\n    start: %p, end %p , mBuffer %p mBufferEnd %p\n    \
+                server %d, serverBase %d, user %d, userBase %d",
+                bufferStart, bufferEnd, mBuffer, mBufferEnd,
+                cblk->server, cblk->serverBase, cblk->user, cblk->userBase);
+        return 0;
+    }
+
+    return bufferStart;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::Track::Track(
+            const sp<MixerThread>& mixerThread,
+            const sp<Client>& client,
+            int streamType,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int frameCount,
+            const sp<IMemory>& sharedBuffer)
+    :   TrackBase(mixerThread, client, streamType, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
+{
+    mVolume[0] = 1.0f;
+    mVolume[1] = 1.0f;
+    mMute = false;
+    mSharedBuffer = sharedBuffer;
+}
+
+AudioFlinger::MixerThread::Track::~Track()
+{
+    wp<Track> weak(this); // never create a strong ref from the dtor
+    mState = TERMINATED;
+    mMixerThread->removeTrack(weak, mName);
+}
+
+void AudioFlinger::MixerThread::Track::destroy()
+{
+    mMixerThread->destroyTrack(this);
+}
+
+void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size)
+{
+    snprintf(buffer, size, "  %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n",
+            mName - AudioMixer::TRACK0,
+            (mClient == NULL) ? getpid() : mClient->pid(),
+            mStreamType,
+            mFormat,
+            mCblk->channels,
+            mFrameCount,
+            mState,
+            mMute,
+            mFillingUpStatus,
+            mCblk->sampleRate,
+            mCblk->volume[0],
+            mCblk->volume[1],
+            mCblk->server,
+            mCblk->user);
+}
+
+status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+     audio_track_cblk_t* cblk = this->cblk();
+     uint32_t framesReady;
+     uint32_t framesReq = buffer->frameCount;
+
+     // Check if last stepServer failed, try to step now
+     if (mFlags & TrackBase::STEPSERVER_FAILED) {
+         if (!step())  goto getNextBuffer_exit;
+         LOGV("stepServer recovered");
+         mFlags &= ~TrackBase::STEPSERVER_FAILED;
+     }
+
+     framesReady = cblk->framesReady();
+
+     if (LIKELY(framesReady)) {
+        uint32_t s = cblk->server;
+        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+        bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd;
+        if (framesReq > framesReady) {
+            framesReq = framesReady;
+        }
+        if (s + framesReq > bufferEnd) {
+            framesReq = bufferEnd - s;
+        }
+
+         buffer->raw = getBuffer(s, framesReq);
+         if (buffer->raw == 0) goto getNextBuffer_exit;
+
+         buffer->frameCount = framesReq;
+        return NO_ERROR;
+     }
+
+getNextBuffer_exit:
+     buffer->raw = 0;
+     buffer->frameCount = 0;
+     return NOT_ENOUGH_DATA;
+}
+
+bool AudioFlinger::MixerThread::Track::isReady() const {
+    if (mFillingUpStatus != FS_FILLING) return true;
+
+    if (mCblk->framesReady() >= mCblk->frameCount ||
+        mCblk->forceReady) {
+        mFillingUpStatus = FS_FILLED;
+        mCblk->forceReady = 0;
+        LOGV("Track::isReady() track %d for output %d", mName, mMixerThread->mOutputType);
+        return true;
+    }
+    return false;
+}
+
+status_t AudioFlinger::MixerThread::Track::start()
+{
+    LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
+    mMixerThread->addTrack(this);
+    return NO_ERROR;
+}
+
+void AudioFlinger::MixerThread::Track::stop()
+{
+    LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
+    Mutex::Autolock _l(mMixerThread->mLock);
+    if (mState > STOPPED) {
+        mState = STOPPED;
+        // If the track is not active (PAUSED and buffers full), flush buffers
+        if (mMixerThread->mActiveTracks.indexOf(this) < 0) {
+            reset();
+        }
+        LOGV("(> STOPPED) => STOPPED (%d)", mName);
+    }
+}
+
+void AudioFlinger::MixerThread::Track::pause()
+{
+    LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+    Mutex::Autolock _l(mMixerThread->mLock);
+    if (mState == ACTIVE || mState == RESUMING) {
+        mState = PAUSING;
+        LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
+    }
+}
+
+void AudioFlinger::MixerThread::Track::flush()
+{
+    LOGV("flush(%d)", mName);
+    Mutex::Autolock _l(mMixerThread->mLock);
+    if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
+        return;
+    }
+    // No point remaining in PAUSED state after a flush => go to
+    // STOPPED state
+    mState = STOPPED;
+
+    // NOTE: reset() will reset cblk->user and cblk->server with
+    // the risk that at the same time, the AudioMixer is trying to read
+    // data. In this case, getNextBuffer() would return a NULL pointer
+    // as audio buffer => the AudioMixer code MUST always test that pointer
+    // returned by getNextBuffer() is not NULL!
+    reset();
+}
+
+void AudioFlinger::MixerThread::Track::reset()
+{
+    // Do not reset twice to avoid discarding data written just after a flush and before
+    // the audioflinger thread detects the track is stopped.
+    if (!mResetDone) {
+        TrackBase::reset();
+        // Force underrun condition to avoid false underrun callback until first data is
+        // written to buffer
+        mCblk->flowControlFlag = 1;
+        mCblk->forceReady = 0;
+        mFillingUpStatus = FS_FILLING;        
+        mResetDone = true;
+    }
+}
+
+void AudioFlinger::MixerThread::Track::mute(bool muted)
+{
+    mMute = muted;
+}
+
+void AudioFlinger::MixerThread::Track::setVolume(float left, float right)
+{
+    mVolume[0] = left;
+    mVolume[1] = right;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::RecordTrack::RecordTrack(
+            const sp<MixerThread>& mixerThread,
+            const sp<Client>& client,
+            int streamType,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int frameCount,
+            uint32_t flags)
+    :   TrackBase(mixerThread, client, streamType, sampleRate, format,
+                  channelCount, frameCount, flags, 0),
+        mOverflow(false)
+{
+}
+
+AudioFlinger::MixerThread::RecordTrack::~RecordTrack()
+{
+    mMixerThread->deleteTrackName(mName);
+}
+
+status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+    audio_track_cblk_t* cblk = this->cblk();
+    uint32_t framesAvail;
+    uint32_t framesReq = buffer->frameCount;
+
+     // Check if last stepServer failed, try to step now
+    if (mFlags & TrackBase::STEPSERVER_FAILED) {
+        if (!step()) goto getNextBuffer_exit;
+        LOGV("stepServer recovered");
+        mFlags &= ~TrackBase::STEPSERVER_FAILED;
+    }
+
+    framesAvail = cblk->framesAvailable_l();
+
+    if (LIKELY(framesAvail)) {
+        uint32_t s = cblk->server;
+        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+        if (framesReq > framesAvail) {
+            framesReq = framesAvail;
+        }
+        if (s + framesReq > bufferEnd) {
+            framesReq = bufferEnd - s;
+        }
+
+        buffer->raw = getBuffer(s, framesReq);
+        if (buffer->raw == 0) goto getNextBuffer_exit;
+
+        buffer->frameCount = framesReq;
+        return NO_ERROR;
+    }
+
+getNextBuffer_exit:
+    buffer->raw = 0;
+    buffer->frameCount = 0;
+    return NOT_ENOUGH_DATA;
+}
+
+status_t AudioFlinger::MixerThread::RecordTrack::start()
+{
+    return mMixerThread->mAudioFlinger->startRecord(this);
+}
+
+void AudioFlinger::MixerThread::RecordTrack::stop()
+{
+    mMixerThread->mAudioFlinger->stopRecord(this);
+    TrackBase::reset();
+    // Force overerrun condition to avoid false overrun callback until first data is
+    // read from buffer
+    mCblk->flowControlFlag = 1;
+}
+
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::OutputTrack::OutputTrack(
+            const sp<MixerThread>& mixerThread,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int frameCount)
+    :   Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL),
+    mOutputMixerThread(mixerThread)
+{
+                
+    mCblk->out = 1;
+    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+    mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+    mOutBuffer.frameCount = 0;
+    mCblk->bufferTimeoutMs = 10;
+    
+    LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p", 
+            mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd);
+    
+}
+
+AudioFlinger::MixerThread::OutputTrack::~OutputTrack()
+{
+    stop();
+}
+
+status_t AudioFlinger::MixerThread::OutputTrack::start()
+{
+    status_t status = Track::start();
+    
+    mRetryCount = 127;
+    return status;
+}
+
+void AudioFlinger::MixerThread::OutputTrack::stop()
+{
+    Track::stop();
+    clearBufferQueue();
+    mOutBuffer.frameCount = 0;
+}
+
+void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames)
+{
+    Buffer *pInBuffer;
+    Buffer inBuffer;
+    uint32_t channels = mCblk->channels;
+        
+    inBuffer.frameCount = frames;
+    inBuffer.i16 = data;
+    
+    if (mCblk->user == 0) {
+        if (mOutputMixerThread->isMusicActive()) {
+            mCblk->forceReady = 1;
+            LOGV("OutputTrack::start() force ready");
+        } else if (mCblk->frameCount > frames){
+            if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+                uint32_t startFrames = (mCblk->frameCount - frames);
+                LOGV("OutputTrack::start() write %d frames", startFrames);
+                pInBuffer = new Buffer;
+                pInBuffer->mBuffer = new int16_t[startFrames * channels];
+                pInBuffer->frameCount = startFrames;
+                pInBuffer->i16 = pInBuffer->mBuffer;
+                memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
+                mBufferQueue.add(pInBuffer);                
+            } else {
+                LOGW ("OutputTrack::write() no more buffers");
+            }
+        }        
+    }
+
+    while (1) { 
+        // First write pending buffers, then new data
+        if (mBufferQueue.size()) {
+            pInBuffer = mBufferQueue.itemAt(0);
+        } else {
+            pInBuffer = &inBuffer;
+        }
+ 
+        if (pInBuffer->frameCount == 0) {
+            break;
+        }
+        
+        if (mOutBuffer.frameCount == 0) {
+            mOutBuffer.frameCount = pInBuffer->frameCount;
+            if (obtainBuffer(&mOutBuffer) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+                break;
+            }
+        }
+            
+        uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount;
+        memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t));
+        mCblk->stepUser(outFrames);
+        pInBuffer->frameCount -= outFrames;
+        pInBuffer->i16 += outFrames * channels;
+        mOutBuffer.frameCount -= outFrames;
+        mOutBuffer.i16 += outFrames * channels;            
+        
+        if (pInBuffer->frameCount == 0) {
+            if (mBufferQueue.size()) {
+                mBufferQueue.removeAt(0);
+                delete [] pInBuffer->mBuffer;
+                delete pInBuffer;
+            } else {
+                break;
+            }
+        }
+    }
+ 
+    // If we could not write all frames, allocate a buffer and queue it for next time.
+    if (inBuffer.frameCount) {
+        if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+            pInBuffer = new Buffer;
+            pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
+            pInBuffer->frameCount = inBuffer.frameCount;
+            pInBuffer->i16 = pInBuffer->mBuffer;
+            memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
+            mBufferQueue.add(pInBuffer);
+        } else {
+            LOGW("OutputTrack::write() no more buffers");
+        }
+    }
+    
+    // Calling write() with a 0 length buffer, means that no more data will be written:
+    // If no more buffers are pending, fill output track buffer to make sure it is started 
+    // by output mixer.
+    if (frames == 0 && mBufferQueue.size() == 0 && mCblk->user < mCblk->frameCount) {
+        frames = mCblk->frameCount - mCblk->user;
+        pInBuffer = new Buffer;
+        pInBuffer->mBuffer = new int16_t[frames * channels];
+        pInBuffer->frameCount = frames;
+        pInBuffer->i16 = pInBuffer->mBuffer;
+        memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
+        mBufferQueue.add(pInBuffer);
+    }
+
+}
+
+status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer)
+{
+    int active;
+    int timeout = 0;
+    status_t result;
+    audio_track_cblk_t* cblk = mCblk;
+    uint32_t framesReq = buffer->frameCount;
+
+    LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
+    buffer->frameCount  = 0;
+    
+    uint32_t framesAvail = cblk->framesAvailable();
+
+    if (framesAvail == 0) {
+        return AudioTrack::NO_MORE_BUFFERS;
+    }
+
+    if (framesReq > framesAvail) {
+        framesReq = framesAvail;
+    }
+
+    uint32_t u = cblk->user;
+    uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
+
+    if (u + framesReq > bufferEnd) {
+        framesReq = bufferEnd - u;
+    }
+
+    buffer->frameCount  = framesReq;
+    buffer->raw         = (void *)cblk->buffer(u);
+    return NO_ERROR;
+}
+
+
+void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue()
+{
+    size_t size = mBufferQueue.size();
+    Buffer *pBuffer;
+    
+    for (size_t i = 0; i < size; i++) {
+        pBuffer = mBufferQueue.itemAt(i);
+        delete [] pBuffer->mBuffer;
+        delete pBuffer;
+    }
+    mBufferQueue.clear();
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
+    :   RefBase(),
+        mAudioFlinger(audioFlinger),
+        mMemoryDealer(new MemoryDealer(1024*1024)),
+        mPid(pid)
+{
+    // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
+}
+
+AudioFlinger::Client::~Client()
+{
+    mAudioFlinger->removeClient(mPid);
+}
+
+const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+{
+    return mMemoryDealer;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track)
+    : BnAudioTrack(),
+      mTrack(track)
+{
+}
+
+AudioFlinger::TrackHandle::~TrackHandle() {
+    // just stop the track on deletion, associated resources
+    // will be freed from the main thread once all pending buffers have
+    // been played. Unless it's not in the active track list, in which
+    // case we free everything now...
+    mTrack->destroy();
+}
+
+status_t AudioFlinger::TrackHandle::start() {
+    return mTrack->start();
+}
+
+void AudioFlinger::TrackHandle::stop() {
+    mTrack->stop();
+}
+
+void AudioFlinger::TrackHandle::flush() {
+    mTrack->flush();
+}
+
+void AudioFlinger::TrackHandle::mute(bool e) {
+    mTrack->mute(e);
+}
+
+void AudioFlinger::TrackHandle::pause() {
+    mTrack->pause();
+}
+
+void AudioFlinger::TrackHandle::setVolume(float left, float right) {
+    mTrack->setVolume(left, right);
+}
+
+sp<IMemory> AudioFlinger::TrackHandle::getCblk() const {
+    return mTrack->getCblk();
+}
+
+status_t AudioFlinger::TrackHandle::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    return BnAudioTrack::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+
+sp<IAudioRecord> AudioFlinger::openRecord(
+        pid_t pid,
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int frameCount,
+        uint32_t flags,
+        status_t *status)
+{
+    sp<AudioRecordThread> thread;
+    sp<MixerThread::RecordTrack> recordTrack;
+    sp<RecordHandle> recordHandle;
+    sp<Client> client;
+    wp<Client> wclient;
+    AudioStreamIn* input = 0;
+    int inFrameCount;
+    size_t inputBufferSize;
+    status_t lStatus;
+
+    // check calling permissions
+    if (!recordingAllowed()) {
+        lStatus = PERMISSION_DENIED;
+        goto Exit;
+    }
+
+    if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) {
+        LOGE("invalid stream type");
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    if (sampleRate > MAX_SAMPLE_RATE) {
+        LOGE("Sample rate out of range");
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    if (mAudioRecordThread == 0) {
+        LOGE("Audio record thread not started");
+        lStatus = NO_INIT;
+        goto Exit;
+    }
+
+
+    // Check that audio input stream accepts requested audio parameters 
+    inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
+    if (inputBufferSize == 0) {
+        lStatus = BAD_VALUE;
+        LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d",  sampleRate, format, channelCount);
+        goto Exit;
+    }
+
+    // add client to list
+    {
+        Mutex::Autolock _l(mLock);
+        wclient = mClients.valueFor(pid);
+        if (wclient != NULL) {
+            client = wclient.promote();
+        } else {
+            client = new Client(this, pid);
+            mClients.add(pid, client);
+        }
+    }
+
+    // frameCount must be a multiple of input buffer size
+    inFrameCount = inputBufferSize/channelCount/sizeof(short);
+    frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
+
+    // create new record track and pass to record thread
+    recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, streamType, sampleRate,
+                                               format, channelCount, frameCount, flags);
+    if (recordTrack->getCblk() == NULL) {
+        recordTrack.clear();
+        lStatus = NO_MEMORY;
+        goto Exit;
+    }
+
+    // return to handle to client
+    recordHandle = new RecordHandle(recordTrack);
+    lStatus = NO_ERROR;
+
+Exit:
+    if (status) {
+        *status = lStatus;
+    }
+    return recordHandle;
+}
+
+status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) {
+    if (mAudioRecordThread != 0) {
+        return mAudioRecordThread->start(recordTrack);        
+    }
+    return NO_INIT;
+}
+
+void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) {
+    if (mAudioRecordThread != 0) {
+        mAudioRecordThread->stop(recordTrack);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack)
+    : BnAudioRecord(),
+    mRecordTrack(recordTrack)
+{
+}
+
+AudioFlinger::RecordHandle::~RecordHandle() {
+    stop();
+}
+
+status_t AudioFlinger::RecordHandle::start() {
+    LOGV("RecordHandle::start()");
+    return mRecordTrack->start();
+}
+
+void AudioFlinger::RecordHandle::stop() {
+    LOGV("RecordHandle::stop()");
+    mRecordTrack->stop();
+}
+
+sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
+    return mRecordTrack->getCblk();
+}
+
+status_t AudioFlinger::RecordHandle::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    return BnAudioRecord::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) :
+    mAudioHardware(audioHardware),
+    mActive(false)
+{
+}
+
+AudioFlinger::AudioRecordThread::~AudioRecordThread()
+{
+}
+
+bool AudioFlinger::AudioRecordThread::threadLoop()
+{
+    LOGV("AudioRecordThread: start record loop");
+    AudioBufferProvider::Buffer buffer;
+    int inBufferSize = 0;
+    int inFrameCount = 0;
+    AudioStreamIn* input = 0;
+
+    mActive = 0;
+    
+    // start recording
+    while (!exitPending()) {
+        if (!mActive) {
+            mLock.lock();
+            if (!mActive && !exitPending()) {
+                LOGV("AudioRecordThread: loop stopping");
+                if (input) {
+                    delete input;
+                    input = 0;
+                }
+                mRecordTrack.clear();
+                mStopped.signal();
+
+                mWaitWorkCV.wait(mLock);
+               
+                LOGV("AudioRecordThread: loop starting");
+                if (mRecordTrack != 0) {
+                    input = mAudioHardware->openInputStream(mRecordTrack->format(), 
+                                    mRecordTrack->channelCount(), 
+                                    mRecordTrack->sampleRate(), 
+                                    &mStartStatus,
+                                    (AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16));
+                    if (input != 0) {
+                        inBufferSize = input->bufferSize();
+                        inFrameCount = inBufferSize/input->frameSize();                        
+                    }
+                } else {
+                    mStartStatus = NO_INIT;
+                }
+                if (mStartStatus !=NO_ERROR) {
+                    LOGW("record start failed, status %d", mStartStatus);
+                    mActive = false;
+                    mRecordTrack.clear();                    
+                }
+                mWaitWorkCV.signal();
+            }
+            mLock.unlock();
+        } else if (mRecordTrack != 0) {
+
+            buffer.frameCount = inFrameCount;
+            if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+                LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
+                ssize_t bytesRead = input->read(buffer.raw, inBufferSize);
+                if (bytesRead < 0) {
+                    LOGE("Error reading audio input");
+                    sleep(1);
+                }
+                mRecordTrack->releaseBuffer(&buffer);
+                mRecordTrack->overflow();
+            }
+
+            // client isn't retrieving buffers fast enough
+            else {
+                if (!mRecordTrack->setOverflow())
+                    LOGW("AudioRecordThread: buffer overflow");
+                // Release the processor for a while before asking for a new buffer.
+                // This will give the application more chance to read from the buffer and
+                // clear the overflow.
+                usleep(5000);
+            }
+        }
+    }
+
+
+    if (input) {
+        delete input;
+    }
+    mRecordTrack.clear();
+    
+    return false;
+}
+
+status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack)
+{
+    LOGV("AudioRecordThread::start");
+    AutoMutex lock(&mLock);
+    mActive = true;
+    // If starting the active track, just reset mActive in case a stop
+    // was pending and exit
+    if (recordTrack == mRecordTrack.get()) return NO_ERROR;
+
+    if (mRecordTrack != 0) return -EBUSY;
+
+    mRecordTrack = recordTrack;
+
+    // signal thread to start
+    LOGV("Signal record thread");
+    mWaitWorkCV.signal();
+    mWaitWorkCV.wait(mLock);
+    LOGV("Record started, status %d", mStartStatus);
+    return mStartStatus;
+}
+
+void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack) {
+    LOGV("AudioRecordThread::stop");
+    AutoMutex lock(&mLock);
+    if (mActive && (recordTrack == mRecordTrack.get())) {
+        mActive = false;
+        mStopped.wait(mLock);
+    }
+}
+
+void AudioFlinger::AudioRecordThread::exit()
+{
+    LOGV("AudioRecordThread::exit");
+    {
+        AutoMutex lock(&mLock);
+        requestExit();
+        mWaitWorkCV.signal();
+    }
+    requestExitAndWait();
+}
+
+status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    pid_t pid = 0;
+
+    if (mRecordTrack != 0 && mRecordTrack->mClient != 0) {
+        snprintf(buffer, SIZE, "Record client pid: %d\n", mRecordTrack->mClient->pid());
+        result.append(buffer);
+    } else {
+        result.append("No record client\n");
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    return BnAudioFlinger::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+void AudioFlinger::instantiate() {
+    defaultServiceManager()->addService(
+            String16("media.audio_flinger"), new AudioFlinger());
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
new file mode 100644
index 0000000..77f064b
--- /dev/null
+++ b/libs/audioflinger/AudioFlinger.h
@@ -0,0 +1,637 @@
+/* //device/include/server/AudioFlinger/AudioFlinger.h
+**
+** Copyright 2007, 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.
+*/
+
+#ifndef ANDROID_AUDIO_FLINGER_H
+#define ANDROID_AUDIO_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <media/IAudioFlinger.h>
+#include <media/IAudioFlingerClient.h>
+#include <media/IAudioTrack.h>
+#include <media/IAudioRecord.h>
+#include <media/AudioTrack.h>
+
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/MemoryDealer.h>
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
+#include <utils/Vector.h>
+
+#include <hardware_legacy/AudioHardwareInterface.h>
+
+#include "AudioBufferProvider.h"
+
+namespace android {
+
+class audio_track_cblk_t;
+class AudioMixer;
+class AudioBuffer;
+
+
+// ----------------------------------------------------------------------------
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+
+// ----------------------------------------------------------------------------
+
+static const nsecs_t kStandbyTimeInNsecs = seconds(3);
+
+class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient 
+{
+public:
+    static void instantiate();
+
+    virtual     status_t    dump(int fd, const Vector<String16>& args);
+
+    // IAudioFlinger interface
+    virtual sp<IAudioTrack> createTrack(
+                                pid_t pid,
+                                int streamType,
+                                uint32_t sampleRate,
+                                int format,
+                                int channelCount,
+                                int frameCount,
+                                uint32_t flags,
+                                const sp<IMemory>& sharedBuffer,
+                                status_t *status);
+
+    virtual     uint32_t    sampleRate(int output) const;
+    virtual     int         channelCount(int output) const;
+    virtual     int         format(int output) const;
+    virtual     size_t      frameCount(int output) const;
+    virtual     uint32_t    latency(int output) const;
+
+    virtual     status_t    setMasterVolume(float value);
+    virtual     status_t    setMasterMute(bool muted);
+
+    virtual     float       masterVolume() const;
+    virtual     bool        masterMute() const;
+
+    virtual     status_t    setStreamVolume(int stream, float value);
+    virtual     status_t    setStreamMute(int stream, bool muted);
+
+    virtual     float       streamVolume(int stream) const;
+    virtual     bool        streamMute(int stream) const;
+
+    virtual     status_t    setRouting(int mode, uint32_t routes, uint32_t mask);
+    virtual     uint32_t    getRouting(int mode) const;
+
+    virtual     status_t    setMode(int mode);
+    virtual     int         getMode() const;
+
+    virtual     status_t    setMicMute(bool state);
+    virtual     bool        getMicMute() const;
+
+    virtual     bool        isMusicActive() const;
+
+    virtual     bool        isA2dpEnabled() const;
+
+    virtual     status_t    setParameter(const char* key, const char* value);
+
+    virtual     void        registerClient(const sp<IAudioFlingerClient>& client);
+    
+    virtual     size_t      getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+    
+    virtual     void        wakeUp();
+    
+    // IBinder::DeathRecipient
+    virtual     void        binderDied(const wp<IBinder>& who);
+
+    enum hardware_call_state {
+        AUDIO_HW_IDLE = 0,
+        AUDIO_HW_INIT,
+        AUDIO_HW_OUTPUT_OPEN,
+        AUDIO_HW_OUTPUT_CLOSE,
+        AUDIO_HW_INPUT_OPEN,
+        AUDIO_HW_INPUT_CLOSE,
+        AUDIO_HW_STANDBY,
+        AUDIO_HW_SET_MASTER_VOLUME,
+        AUDIO_HW_GET_ROUTING,
+        AUDIO_HW_SET_ROUTING,
+        AUDIO_HW_GET_MODE,
+        AUDIO_HW_SET_MODE,
+        AUDIO_HW_GET_MIC_MUTE,
+        AUDIO_HW_SET_MIC_MUTE,
+        AUDIO_SET_VOICE_VOLUME,
+        AUDIO_SET_PARAMETER,
+    };
+
+    // record interface
+    virtual sp<IAudioRecord> openRecord(
+                                pid_t pid,
+                                int streamType,
+                                uint32_t sampleRate,
+                                int format,
+                                int channelCount,
+                                int frameCount,
+                                uint32_t flags,
+                                status_t *status);
+
+    virtual     status_t    onTransact(
+                                uint32_t code,
+                                const Parcel& data,
+                                Parcel* reply,
+                                uint32_t flags);
+
+private:
+                            AudioFlinger();
+    virtual                 ~AudioFlinger();
+    
+    void                    setOutput(int outputType);
+    void                    doSetOutput(int outputType);
+
+#ifdef WITH_A2DP
+    void                    setA2dpEnabled(bool enable);
+#endif
+    static bool             streamForcedToSpeaker(int streamType);
+    
+    // Management of forced route to speaker for certain track types.
+    enum force_speaker_command {
+        ACTIVE_TRACK_ADDED = 0,
+        ACTIVE_TRACK_REMOVED,
+        CHECK_ROUTE_RESTORE_TIME,
+        FORCE_ROUTE_RESTORE
+    };
+    void                    handleForcedSpeakerRoute(int command);
+
+    // Internal dump utilites.
+    status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
+    status_t dumpClients(int fd, const Vector<String16>& args);
+    status_t dumpInternals(int fd, const Vector<String16>& args);
+
+    // --- Client ---
+    class Client : public RefBase {
+    public:
+                            Client(const sp<AudioFlinger>& audioFlinger, pid_t pid);
+        virtual             ~Client();
+        const sp<MemoryDealer>&     heap() const;
+        pid_t               pid() const { return mPid; }
+    private:
+                            Client(const Client&);
+                            Client& operator = (const Client&);
+        sp<AudioFlinger>    mAudioFlinger;
+        sp<MemoryDealer>    mMemoryDealer;
+        pid_t               mPid;
+    };
+
+
+    class TrackHandle;
+    class RecordHandle;
+    class AudioRecordThread;
+
+    
+    // --- MixerThread ---
+    class MixerThread : public Thread {
+    public:
+        
+        // --- Track ---
+
+        // base for record and playback
+        class TrackBase : public AudioBufferProvider, public RefBase {
+
+        public:
+            enum track_state {
+                IDLE,
+                TERMINATED,
+                STOPPED,
+                RESUMING,
+                ACTIVE,
+                PAUSING,
+                PAUSED
+            };
+
+            enum track_flags {
+                STEPSERVER_FAILED = 0x01, //  StepServer could not acquire cblk->lock mutex
+                SYSTEM_FLAGS_MASK = 0x0000ffffUL,
+                // The upper 16 bits are used for track-specific flags.
+            };
+
+                                TrackBase(const sp<MixerThread>& mixerThread,
+                                        const sp<Client>& client,
+                                        int streamType,
+                                        uint32_t sampleRate,
+                                        int format,
+                                        int channelCount,
+                                        int frameCount,
+                                        uint32_t flags,
+                                        const sp<IMemory>& sharedBuffer);
+                                ~TrackBase();
+
+            virtual status_t    start() = 0;
+            virtual void        stop() = 0;
+                    sp<IMemory> getCblk() const;
+
+        protected:
+            friend class MixerThread;
+            friend class RecordHandle;
+            friend class AudioRecordThread;
+
+                                TrackBase(const TrackBase&);
+                                TrackBase& operator = (const TrackBase&);
+
+            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
+            virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+
+            audio_track_cblk_t* cblk() const {
+                return mCblk;
+            }
+
+            int type() const {
+                return mStreamType;
+            }
+
+            int format() const {
+                return mFormat;
+            }
+
+            int channelCount() const ;
+
+            int sampleRate() const;
+
+            void* getBuffer(uint32_t offset, uint32_t frames) const;
+
+            int name() const {
+                return mName;
+            }
+
+            bool isStopped() const {
+                return mState == STOPPED;
+            }
+
+            bool isTerminated() const {
+                return mState == TERMINATED;
+            }
+
+            bool step();
+            void reset();
+
+            sp<MixerThread>     mMixerThread;
+            sp<Client>          mClient;
+            sp<IMemory>         mCblkMemory;
+            audio_track_cblk_t* mCblk;
+            int                 mStreamType;
+            void*               mBuffer;
+            void*               mBufferEnd;
+            uint32_t            mFrameCount;
+            int                 mName;
+            // we don't really need a lock for these
+            int                 mState;
+            int                 mClientTid;
+            uint8_t             mFormat;
+            uint32_t            mFlags;
+        };
+
+        // playback track
+        class Track : public TrackBase {
+        public:
+                                Track(  const sp<MixerThread>& mixerThread,
+                                        const sp<Client>& client,
+                                        int streamType,
+                                        uint32_t sampleRate,
+                                        int format,
+                                        int channelCount,
+                                        int frameCount,
+                                        const sp<IMemory>& sharedBuffer);
+                                ~Track();
+
+                    void        dump(char* buffer, size_t size);
+            virtual status_t    start();
+            virtual void        stop();
+                    void        pause();
+
+                    void        flush();
+                    void        destroy();
+                    void        mute(bool);
+                    void        setVolume(float left, float right);
+
+        protected:
+            friend class MixerThread;
+            friend class AudioFlinger;
+            friend class AudioFlinger::TrackHandle;
+
+                                Track(const Track&);
+                                Track& operator = (const Track&);
+
+            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+            bool isMuted() const {
+                return (mMute || mMixerThread->mStreamTypes[mStreamType].mute);
+            }
+
+            bool isPausing() const {
+                return mState == PAUSING;
+            }
+
+            bool isPaused() const {
+                return mState == PAUSED;
+            }
+
+            bool isReady() const;
+
+            void setPaused() { mState = PAUSED; }
+            void reset();
+
+            // we don't really need a lock for these
+            float               mVolume[2];
+            volatile bool       mMute;
+            // FILLED state is used for suppressing volume ramp at begin of playing
+            enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
+            mutable uint8_t     mFillingUpStatus;
+            int8_t              mRetryCount;
+            sp<IMemory>         mSharedBuffer;
+            bool                mResetDone;
+        };  // end of Track
+
+        // record track
+        class RecordTrack : public TrackBase {
+        public:
+                                RecordTrack(const sp<MixerThread>& mixerThread,
+                                        const sp<Client>& client,
+                                        int streamType,
+                                        uint32_t sampleRate,
+                                        int format,
+                                        int channelCount,
+                                        int frameCount,
+                                        uint32_t flags);
+                                ~RecordTrack();
+
+            virtual status_t    start();
+            virtual void        stop();
+
+                    bool        overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+                    bool        setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+
+        private:
+            friend class AudioFlinger;
+            friend class AudioFlinger::RecordHandle;
+            friend class AudioFlinger::AudioRecordThread;
+            friend class MixerThread;
+
+                                RecordTrack(const Track&);
+                                RecordTrack& operator = (const Track&);
+
+            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+            bool                mOverflow;
+        };
+
+        // playback track
+        class OutputTrack : public Track {
+        public:
+            
+            class Buffer: public AudioBufferProvider::Buffer {
+            public:
+                int16_t *mBuffer;
+            };
+            
+                                OutputTrack(  const sp<MixerThread>& mixerThread,
+                                        uint32_t sampleRate,
+                                        int format,
+                                        int channelCount,
+                                        int frameCount);
+                                ~OutputTrack();
+
+            virtual status_t    start();
+            virtual void        stop();
+                    void        write(int16_t* data, uint32_t frames);
+                    bool        bufferQueueEmpty() { return (mBufferQueue.size() == 0) ? true : false; }
+
+        private:
+
+            status_t            obtainBuffer(AudioBufferProvider::Buffer* buffer);
+            void                clearBufferQueue();
+            
+            sp<MixerThread>             mOutputMixerThread;
+            Vector < Buffer* >          mBufferQueue;
+            AudioBufferProvider::Buffer mOutBuffer;
+            uint32_t                    mFramesWritten;
+            
+         };  // end of OutputTrack
+
+        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType);
+        virtual             ~MixerThread();
+
+        virtual     status_t    dump(int fd, const Vector<String16>& args);
+
+        // Thread virtuals
+        virtual     bool        threadLoop();
+        virtual     status_t    readyToRun();
+        virtual     void        onFirstRef();
+
+        virtual     uint32_t    sampleRate() const;
+        virtual     int         channelCount() const;
+        virtual     int         format() const;
+        virtual     size_t      frameCount() const;
+        virtual     uint32_t    latency() const;
+
+        virtual     status_t    setMasterVolume(float value);
+        virtual     status_t    setMasterMute(bool muted);
+
+        virtual     float       masterVolume() const;
+        virtual     bool        masterMute() const;
+
+        virtual     status_t    setStreamVolume(int stream, float value);
+        virtual     status_t    setStreamMute(int stream, bool muted);
+
+        virtual     float       streamVolume(int stream) const;
+        virtual     bool        streamMute(int stream) const;
+
+                    bool        isMusicActive() const;
+        
+                    
+        sp<Track> createTrack(
+                                    const sp<AudioFlinger::Client>& client,
+                                    int streamType,
+                                    uint32_t sampleRate,
+                                    int format,
+                                    int channelCount,
+                                    int frameCount,
+                                    const sp<IMemory>& sharedBuffer,
+                                    status_t *status);
+
+                    void        wakeUp() { mWaitWorkCV.broadcast(); }
+                    
+                    void        getTracks(SortedVector < sp<Track> >& tracks,
+                                          SortedVector < wp<Track> >& activeTracks);
+                    void        putTracks(SortedVector < sp<Track> >& tracks,
+                                          SortedVector < wp<Track> >& activeTracks);
+                    void        setOuputTrack(OutputTrack *track) { mOutputTrack = track; }
+                    
+        struct  stream_type_t {
+            stream_type_t()
+                :   volume(1.0f),
+                    mute(false)
+            {
+            }
+            float       volume;
+            bool        mute;
+        };
+
+    private:
+
+
+        friend class AudioFlinger;
+        friend class Track;
+        friend class TrackBase;
+        friend class RecordTrack;
+        
+        MixerThread(const Client&);
+        MixerThread& operator = (const MixerThread&);
+  
+        status_t    addTrack(const sp<Track>& track);
+        void        removeTrack(wp<Track> track, int name);
+        void        remove_track_l(wp<Track> track, int name);
+        void        destroyTrack(const sp<Track>& track);
+        int         getTrackName();
+        void        deleteTrackName(int name);
+        void        addActiveTrack(const wp<Track>& t);
+        void        removeActiveTrack(const wp<Track>& t);
+        size_t      getOutputFrameCount();
+
+        status_t    dumpInternals(int fd, const Vector<String16>& args);
+        status_t    dumpTracks(int fd, const Vector<String16>& args);
+        
+        sp<AudioFlinger>                mAudioFlinger;       
+        mutable     Mutex               mLock;
+        mutable     Condition           mWaitWorkCV;
+        SortedVector< wp<Track> >       mActiveTracks;
+        SortedVector< sp<Track> >       mTracks;
+        stream_type_t                   mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
+        AudioMixer*                     mAudioMixer;
+        AudioStreamOut*                 mOutput;
+        int                             mOutputType;
+        uint32_t                        mSampleRate;
+        size_t                          mFrameCount;
+        int                             mChannelCount;
+        int                             mFormat;
+        int16_t*                        mMixBuffer;
+        float                           mMasterVolume;
+        bool                            mMasterMute;
+        nsecs_t                         mLastWriteTime;
+        int                             mNumWrites;
+        int                             mNumDelayedWrites;
+        bool                            mStandby;
+        bool                            mInWrite;
+        sp <OutputTrack>                mOutputTrack;
+    };
+
+    
+    friend class AudioBuffer;
+
+    class TrackHandle : public android::BnAudioTrack {
+    public:
+                            TrackHandle(const sp<MixerThread::Track>& track);
+        virtual             ~TrackHandle();
+        virtual status_t    start();
+        virtual void        stop();
+        virtual void        flush();
+        virtual void        mute(bool);
+        virtual void        pause();
+        virtual void        setVolume(float left, float right);
+        virtual sp<IMemory> getCblk() const;
+        virtual status_t onTransact(
+            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+    private:
+        sp<MixerThread::Track> mTrack;
+    };
+
+    friend class Client;
+    friend class MixerThread::Track;
+
+
+                void        removeClient(pid_t pid);
+
+
+
+    class RecordHandle : public android::BnAudioRecord {
+    public:
+        RecordHandle(const sp<MixerThread::RecordTrack>& recordTrack);
+        virtual             ~RecordHandle();
+        virtual status_t    start();
+        virtual void        stop();
+        virtual sp<IMemory> getCblk() const;
+        virtual status_t onTransact(
+            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+    private:
+        sp<MixerThread::RecordTrack> mRecordTrack;
+    };
+
+    // record thread
+    class AudioRecordThread : public Thread
+    {
+    public:
+        AudioRecordThread(AudioHardwareInterface* audioHardware);
+        virtual             ~AudioRecordThread();
+        virtual bool        threadLoop();
+        virtual status_t    readyToRun() { return NO_ERROR; }
+        virtual void        onFirstRef() {}
+
+                status_t    start(MixerThread::RecordTrack* recordTrack);
+                void        stop(MixerThread::RecordTrack* recordTrack);
+                void        exit();
+                status_t    dump(int fd, const Vector<String16>& args);
+
+    private:
+                AudioRecordThread();
+                AudioHardwareInterface              *mAudioHardware;
+                sp<MixerThread::RecordTrack>        mRecordTrack;
+                Mutex                               mLock;
+                Condition                           mWaitWorkCV;
+                Condition                           mStopped;
+                volatile bool                       mActive;
+                status_t                            mStartStatus;
+    };
+
+    friend class AudioRecordThread;
+    friend class MixerThread;
+
+                status_t    startRecord(MixerThread::RecordTrack* recordTrack);
+                void        stopRecord(MixerThread::RecordTrack* recordTrack);
+                
+                void        handleOutputSwitch();
+
+    mutable     Mutex                                       mHardwareLock;
+    mutable     Mutex                                       mLock;
+                DefaultKeyedVector< pid_t, wp<Client> >     mClients;
+
+                sp<MixerThread>                     mA2dpMixerThread;
+                sp<MixerThread>                     mHardwareMixerThread;
+                AudioHardwareInterface*             mAudioHardware;
+                AudioHardwareInterface*             mA2dpAudioInterface;
+                sp<AudioRecordThread>               mAudioRecordThread;
+                bool                                mA2dpEnabled;
+                bool                                mA2dpEnabledReq;
+    mutable     int                                 mHardwareStatus;
+                SortedVector< wp<IBinder> >         mNotificationClients;
+                int                                 mForcedSpeakerCount;
+                uint32_t                            mSavedRoute;
+                uint32_t                            mForcedRoute;
+                nsecs_t                             mRouteRestoreTime;
+                bool                                mMusicMuteSaved;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_FLINGER_H
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
new file mode 100644
index 0000000..62beada
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -0,0 +1,313 @@
+/*
+**
+** Copyright 2007, 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 <stdint.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#define LOG_TAG "AudioHardware"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareGeneric.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static char const * const kAudioDeviceName = "/dev/eac";
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareGeneric::AudioHardwareGeneric()
+    : mOutput(0), mInput(0),  mFd(-1), mMicMute(false)
+{
+    mFd = ::open(kAudioDeviceName, O_RDWR);
+}
+
+AudioHardwareGeneric::~AudioHardwareGeneric()
+{
+    if (mFd >= 0) ::close(mFd);
+    delete mOutput;
+    delete mInput;
+}
+
+status_t AudioHardwareGeneric::initCheck()
+{
+    if (mFd >= 0) {
+        if (::access(kAudioDeviceName, O_RDWR) == NO_ERROR)
+            return NO_ERROR;
+    }
+    return NO_INIT;
+}
+
+AudioStreamOut* AudioHardwareGeneric::openOutputStream(
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
+{
+    AutoMutex lock(mLock);
+
+    // only one output stream allowed
+    if (mOutput) {
+        if (status) {
+            *status = INVALID_OPERATION;
+        }
+        return 0;
+    }
+
+    // create new output stream
+    AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
+    status_t lStatus = out->set(this, mFd, format, channelCount, sampleRate);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR) {
+        mOutput = out;
+    } else {
+        delete out;
+    }
+    return mOutput;
+}
+
+void AudioHardwareGeneric::closeOutputStream(AudioStreamOutGeneric* out) {
+    if (out == mOutput) mOutput = 0;
+}
+
+AudioStreamIn* AudioHardwareGeneric::openInputStream(
+        int format, int channelCount, uint32_t sampleRate, status_t *status,
+        AudioSystem::audio_in_acoustics acoustics)
+{
+    AutoMutex lock(mLock);
+
+    // only one input stream allowed
+    if (mInput) {
+        if (status) {
+            *status = INVALID_OPERATION;
+        }
+        return 0;
+    }
+
+    // create new output stream
+    AudioStreamInGeneric* in = new AudioStreamInGeneric();
+    status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate, acoustics);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR) {
+        mInput = in;
+    } else {
+        delete in;
+    }
+    return mInput;
+}
+
+void AudioHardwareGeneric::closeInputStream(AudioStreamInGeneric* in) {
+    if (in == mInput) mInput = 0;
+}
+
+status_t AudioHardwareGeneric::setVoiceVolume(float v)
+{
+    // Implement: set voice volume
+    return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::setMasterVolume(float v)
+{
+    // Implement: set master volume
+    // return error - software mixer will handle it
+    return INVALID_OPERATION;
+}
+
+status_t AudioHardwareGeneric::setMicMute(bool state)
+{
+    mMicMute = state;
+    return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::getMicMute(bool* state)
+{
+    *state = mMicMute;
+    return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioHardwareGeneric::dumpInternals\n");
+    snprintf(buffer, SIZE, "\tmFd: %d mMicMute: %s\n",  mFd, mMicMute? "true": "false");
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    if (mInput) {
+        mInput->dump(fd, args);
+    }
+    if (mOutput) {
+        mOutput->dump(fd, args);
+    }
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamOutGeneric::set(
+        AudioHardwareGeneric *hw,
+        int fd,
+        int format,
+        int channels,
+        uint32_t rate)
+{
+    // fix up defaults
+    if (format == 0) format = AudioSystem::PCM_16_BIT;
+    if (channels == 0) channels = channelCount();
+    if (rate == 0) rate = sampleRate();
+
+    // check values
+    if ((format != AudioSystem::PCM_16_BIT) ||
+            (channels != channelCount()) ||
+            (rate != sampleRate()))
+        return BAD_VALUE;
+
+    mAudioHardware = hw;
+    mFd = fd;
+    return NO_ERROR;
+}
+
+AudioStreamOutGeneric::~AudioStreamOutGeneric()
+{
+    if (mAudioHardware)
+        mAudioHardware->closeOutputStream(this);
+}
+
+ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes)
+{
+    Mutex::Autolock _l(mLock);
+    return ssize_t(::write(mFd, buffer, bytes));
+}
+
+status_t AudioStreamOutGeneric::standby()
+{
+    // Implement: audio hardware to standby mode
+    return NO_ERROR;
+}
+
+status_t AudioStreamOutGeneric::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioStreamOutGeneric::dump\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+// record functions
+status_t AudioStreamInGeneric::set(
+        AudioHardwareGeneric *hw,
+        int fd,
+        int format,
+        int channels,
+        uint32_t rate,
+        AudioSystem::audio_in_acoustics acoustics)
+{
+    // FIXME: remove logging
+    LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, format, channels, rate);
+    // check values
+    if ((format != AudioSystem::PCM_16_BIT) ||
+            (channels != channelCount()) ||
+            (rate != sampleRate())) {
+        LOGE("Error opening input channel");
+        return BAD_VALUE;
+    }
+
+    mAudioHardware = hw;
+    mFd = fd;
+    return NO_ERROR;
+}
+
+AudioStreamInGeneric::~AudioStreamInGeneric()
+{
+    // FIXME: remove logging
+    LOGD("AudioStreamInGeneric destructor");
+    if (mAudioHardware)
+        mAudioHardware->closeInputStream(this);
+}
+
+ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)
+{
+    // FIXME: remove logging
+    LOGD("AudioStreamInGeneric::read(%p, %d) from fd %d", buffer, bytes, mFd);
+    AutoMutex lock(mLock);
+    if (mFd < 0) {
+        LOGE("Attempt to read from unopened device");
+        return NO_INIT;
+    }
+    return ::read(mFd, buffer, bytes);
+}
+
+status_t AudioStreamInGeneric::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioStreamInGeneric::dump\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
new file mode 100644
index 0000000..c949aa1
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -0,0 +1,141 @@
+/*
+**
+** Copyright 2007, 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.
+*/
+
+#ifndef ANDROID_AUDIO_HARDWARE_GENERIC_H
+#define ANDROID_AUDIO_HARDWARE_GENERIC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class AudioHardwareGeneric;
+
+class AudioStreamOutGeneric : public AudioStreamOut {
+public:
+                        AudioStreamOutGeneric() : mAudioHardware(0), mFd(-1) {}
+    virtual             ~AudioStreamOutGeneric();
+
+    virtual status_t    set(
+            AudioHardwareGeneric *hw,
+            int mFd,
+            int format,
+            int channelCount,
+            uint32_t sampleRate);
+
+    virtual uint32_t    sampleRate() const { return 44100; }
+    virtual size_t      bufferSize() const { return 4096; }
+    virtual int         channelCount() const { return 2; }
+    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    virtual uint32_t    latency() const { return 20; }
+    virtual status_t    setVolume(float volume) { return INVALID_OPERATION; }
+    virtual ssize_t     write(const void* buffer, size_t bytes);
+    virtual status_t    standby();
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+private:
+    AudioHardwareGeneric *mAudioHardware;
+    Mutex   mLock;
+    int     mFd;
+};
+
+class AudioStreamInGeneric : public AudioStreamIn {
+public:
+                        AudioStreamInGeneric() : mAudioHardware(0), mFd(-1) {}
+    virtual             ~AudioStreamInGeneric();
+
+    virtual status_t    set(
+            AudioHardwareGeneric *hw,
+            int mFd,
+            int format,
+            int channelCount,
+            uint32_t sampleRate,
+            AudioSystem::audio_in_acoustics acoustics);
+
+    uint32_t    sampleRate() const { return 8000; }
+    virtual size_t      bufferSize() const { return 320; }
+    virtual int         channelCount() const { return 1; }
+    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    virtual status_t    setGain(float gain) { return INVALID_OPERATION; }
+    virtual ssize_t     read(void* buffer, ssize_t bytes);
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+    virtual status_t    standby() { return NO_ERROR; }
+
+private:
+    AudioHardwareGeneric *mAudioHardware;
+    Mutex   mLock;
+    int     mFd;
+};
+
+
+class AudioHardwareGeneric : public AudioHardwareBase
+{
+public:
+                        AudioHardwareGeneric();
+    virtual             ~AudioHardwareGeneric();
+    virtual status_t    initCheck();
+    virtual status_t    setVoiceVolume(float volume);
+    virtual status_t    setMasterVolume(float volume);
+
+    // mic mute
+    virtual status_t    setMicMute(bool state);
+    virtual status_t    getMicMute(bool* state);
+
+    virtual status_t    setParameter(const char* key, const char* value)
+            { return NO_ERROR; }
+
+    // create I/O streams
+    virtual AudioStreamOut* openOutputStream(
+            int format=0,
+            int channelCount=0,
+            uint32_t sampleRate=0,
+            status_t *status=0);
+
+    virtual AudioStreamIn* openInputStream(
+            int format,
+            int channelCount,
+            uint32_t sampleRate,
+            status_t *status,
+            AudioSystem::audio_in_acoustics acoustics);
+
+            void            closeOutputStream(AudioStreamOutGeneric* out);
+            void            closeInputStream(AudioStreamInGeneric* in);
+protected:
+    virtual status_t        doRouting() { return NO_ERROR; }
+    virtual status_t        dump(int fd, const Vector<String16>& args);
+
+private:
+    status_t                dumpInternals(int fd, const Vector<String16>& args);
+
+    Mutex                   mLock;
+    AudioStreamOutGeneric   *mOutput;
+    AudioStreamInGeneric    *mInput;
+    int                     mFd;
+    bool                    mMicMute;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_GENERIC_H
diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp
new file mode 100644
index 0000000..ac76a19
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareInterface.cpp
@@ -0,0 +1,247 @@
+/*
+**
+** Copyright 2007, 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 <cutils/properties.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LOG_TAG "AudioHardwareInterface"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareStub.h"
+#include "AudioHardwareGeneric.h"
+
+//#define DUMP_FLINGER_OUT        // if defined allows recording samples in a file
+#ifdef DUMP_FLINGER_OUT
+#include "AudioDumpInterface.h"
+#endif
+
+
+// change to 1 to log routing calls
+#define LOG_ROUTING_CALLS 0
+
+namespace android {
+
+#if LOG_ROUTING_CALLS
+static const char* routingModeStrings[] =
+{
+    "OUT OF RANGE",
+    "INVALID",
+    "CURRENT",
+    "NORMAL",
+    "RINGTONE",
+    "IN_CALL"
+};
+
+static const char* routeStrings[] =
+{
+    "EARPIECE ",
+    "SPEAKER ",
+    "BLUETOOTH ",
+    "HEADSET "
+    "BLUETOOTH_A2DP "
+};
+static const char* routeNone = "NONE";
+
+static const char* displayMode(int mode)
+{
+    if ((mode < -2) || (mode > 2))
+        return routingModeStrings[0];
+    return routingModeStrings[mode+3];
+}
+
+static const char* displayRoutes(uint32_t routes)
+{
+    static char routeStr[80];
+    if (routes == 0)
+        return routeNone;
+    routeStr[0] = 0;
+    int bitMask = 1;
+    for (int i = 0; i < 4; ++i, bitMask <<= 1) {
+        if (routes & bitMask) {
+            strcat(routeStr, routeStrings[i]);
+        }
+    }
+    routeStr[strlen(routeStr)-1] = 0;
+    return routeStr;
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareInterface* AudioHardwareInterface::create()
+{
+    /*
+     * FIXME: This code needs to instantiate the correct audio device
+     * interface. For now - we use compile-time switches.
+     */
+    AudioHardwareInterface* hw = 0;
+    char value[PROPERTY_VALUE_MAX];
+
+#ifdef GENERIC_AUDIO
+    hw = new AudioHardwareGeneric();
+#else
+    // if running in emulation - use the emulator driver
+    if (property_get("ro.kernel.qemu", value, 0)) {
+        LOGD("Running in emulation - using generic audio driver");
+        hw = new AudioHardwareGeneric();
+    }
+    else {
+        LOGV("Creating Vendor Specific AudioHardware");
+        hw = createAudioHardware();
+    }
+#endif
+    if (hw->initCheck() != NO_ERROR) {
+        LOGW("Using stubbed audio hardware. No sound will be produced.");
+        delete hw;
+        hw = new AudioHardwareStub();
+    }
+    
+#ifdef DUMP_FLINGER_OUT
+    // This code adds a record of buffers in a file to write calls made by AudioFlinger.
+    // It replaces the current AudioHardwareInterface object by an intermediate one which
+    // will record buffers in a file (after sending them to hardware) for testing purpose.
+    // This feature is enabled by defining symbol DUMP_FLINGER_OUT.
+    // The output file is FLINGER_DUMP_NAME. Pause are not recorded in the file.
+    
+    hw = new AudioDumpInterface(hw);    // replace interface
+#endif
+    return hw;
+}
+
+AudioStreamOut::~AudioStreamOut()
+{
+}
+
+AudioStreamIn::~AudioStreamIn() {}
+
+AudioHardwareBase::AudioHardwareBase()
+{
+    // force a routing update on initialization
+    memset(&mRoutes, 0, sizeof(mRoutes));
+    mMode = 0;
+}
+
+// generics for audio routing - the real work is done in doRouting
+status_t AudioHardwareBase::setRouting(int mode, uint32_t routes)
+{
+#if LOG_ROUTING_CALLS
+    LOGD("setRouting: mode=%s, routes=[%s]", displayMode(mode), displayRoutes(routes));
+#endif
+    if (mode == AudioSystem::MODE_CURRENT)
+        mode = mMode;
+    if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+        return BAD_VALUE;
+    uint32_t old = mRoutes[mode];
+    mRoutes[mode] = routes;
+    if ((mode != mMode) || (old == routes))
+        return NO_ERROR;
+#if LOG_ROUTING_CALLS
+    const char* oldRouteStr = strdup(displayRoutes(old));
+    LOGD("doRouting: mode=%s, old route=[%s], new route=[%s]",
+           displayMode(mode), oldRouteStr, displayRoutes(routes));
+    delete oldRouteStr;
+#endif
+    return doRouting();
+}
+
+status_t AudioHardwareBase::getRouting(int mode, uint32_t* routes)
+{
+    if (mode == AudioSystem::MODE_CURRENT)
+        mode = mMode;
+    if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+        return BAD_VALUE;
+    *routes = mRoutes[mode];
+#if LOG_ROUTING_CALLS
+    LOGD("getRouting: mode=%s, routes=[%s]",
+           displayMode(mode), displayRoutes(*routes));
+#endif
+    return NO_ERROR;
+}
+
+status_t AudioHardwareBase::setMode(int mode)
+{
+#if LOG_ROUTING_CALLS
+    LOGD("setMode(%s)", displayMode(mode));
+#endif
+    if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+        return BAD_VALUE;
+    if (mMode == mode)
+        return NO_ERROR;
+#if LOG_ROUTING_CALLS
+    LOGD("doRouting: old mode=%s, new mode=%s route=[%s]",
+            displayMode(mMode), displayMode(mode), displayRoutes(mRoutes[mode]));
+#endif
+    mMode = mode;
+    return doRouting();
+}
+
+status_t AudioHardwareBase::getMode(int* mode)
+{
+    // Implement: set audio routing
+    *mode = mMode;
+    return NO_ERROR;
+}
+
+status_t AudioHardwareBase::setParameter(const char* key, const char* value)
+{
+    // default implementation is to ignore
+    return NO_ERROR;
+}
+
+
+// default implementation
+size_t AudioHardwareBase::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    if (sampleRate != 8000) {
+        LOGW("getInputBufferSize bad sampling rate: %d", sampleRate);
+        return 0;
+    }
+    if (format != AudioSystem::PCM_16_BIT) {
+        LOGW("getInputBufferSize bad format: %d", format);
+        return 0;
+    }
+    if (channelCount != 1) {
+        LOGW("getInputBufferSize bad channel count: %d", channelCount);
+        return 0;
+    }
+
+    return 320;
+}
+
+status_t AudioHardwareBase::dumpState(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioHardwareBase::dumpState\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
+    result.append(buffer);
+    for (int i = 0, n = AudioSystem::NUM_MODES; i < n; ++i) {
+        snprintf(buffer, SIZE, "\tmRoutes[%d]: %d\n", i, mRoutes[i]);
+        result.append(buffer);
+    }
+    ::write(fd, result.string(), result.size());
+    dump(fd, args);  // Dump the state of the concrete child.
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
new file mode 100644
index 0000000..b13cb1c
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -0,0 +1,185 @@
+/* //device/servers/AudioFlinger/AudioHardwareStub.cpp
+**
+** Copyright 2007, 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 <stdint.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareStub.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareStub::AudioHardwareStub() : mMicMute(false)
+{
+}
+
+AudioHardwareStub::~AudioHardwareStub()
+{
+}
+
+status_t AudioHardwareStub::initCheck()
+{
+    return NO_ERROR;
+}
+
+AudioStreamOut* AudioHardwareStub::openOutputStream(
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
+{
+    AudioStreamOutStub* out = new AudioStreamOutStub();
+    status_t lStatus = out->set(format, channelCount, sampleRate);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR)
+        return out;
+    delete out;
+    return 0;
+}
+
+AudioStreamIn* AudioHardwareStub::openInputStream(
+        int format, int channelCount, uint32_t sampleRate,
+        status_t *status, AudioSystem::audio_in_acoustics acoustics)
+{
+    AudioStreamInStub* in = new AudioStreamInStub();
+    status_t lStatus = in->set(format, channelCount, sampleRate, acoustics);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR)
+        return in;
+    delete in;
+    return 0;
+}
+
+status_t AudioHardwareStub::setVoiceVolume(float volume)
+{
+    return NO_ERROR;
+}
+
+status_t AudioHardwareStub::setMasterVolume(float volume)
+{
+    return NO_ERROR;
+}
+
+status_t AudioHardwareStub::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioHardwareStub::dumpInternals\n");
+    snprintf(buffer, SIZE, "\tmMicMute: %s\n", mMicMute? "true": "false");
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioHardwareStub::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamOutStub::set(int format, int channels, uint32_t rate)
+{
+    // fix up defaults
+    if (format == 0) format = AudioSystem::PCM_16_BIT;
+    if (channels == 0) channels = channelCount();
+    if (rate == 0) rate = sampleRate();
+
+    if ((format == AudioSystem::PCM_16_BIT) &&
+            (channels == channelCount()) &&
+            (rate == sampleRate()))
+        return NO_ERROR;
+    return BAD_VALUE;
+}
+
+ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes)
+{
+    // fake timing for audio output
+    usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+    return bytes;
+}
+
+status_t AudioStreamOutStub::standby()
+{
+    return NO_ERROR;
+}
+
+status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioStreamOutStub::dump\n");
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamInStub::set(int format, int channels, uint32_t rate,
+				AudioSystem::audio_in_acoustics acoustics)
+{
+    if ((format == AudioSystem::PCM_16_BIT) &&
+            (channels == channelCount()) &&
+            (rate == sampleRate()))
+        return NO_ERROR;
+    return BAD_VALUE;
+}
+
+ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes)
+{
+    // fake timing for audio input
+    usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+    memset(buffer, 0, bytes);
+    return bytes;
+}
+
+status_t AudioStreamInStub::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioStreamInStub::dump\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
new file mode 100644
index 0000000..d406424
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -0,0 +1,100 @@
+/* //device/servers/AudioFlinger/AudioHardwareStub.h
+**
+** Copyright 2007, 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.
+*/
+
+#ifndef ANDROID_AUDIO_HARDWARE_STUB_H
+#define ANDROID_AUDIO_HARDWARE_STUB_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class AudioStreamOutStub : public AudioStreamOut {
+public:
+    virtual status_t    set(int format, int channelCount, uint32_t sampleRate);
+    virtual uint32_t    sampleRate() const { return 44100; }
+    virtual size_t      bufferSize() const { return 4096; }
+    virtual int         channelCount() const { return 2; }
+    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    virtual uint32_t    latency() const { return 0; }
+    virtual status_t    setVolume(float volume) { return NO_ERROR; }
+    virtual ssize_t     write(const void* buffer, size_t bytes);
+    virtual status_t    standby();
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+};
+
+class AudioStreamInStub : public AudioStreamIn {
+public:
+    virtual status_t    set(int format, int channelCount, uint32_t sampleRate, AudioSystem::audio_in_acoustics acoustics);
+    virtual uint32_t    sampleRate() const { return 8000; }
+    virtual size_t      bufferSize() const { return 320; }
+    virtual int         channelCount() const { return 1; }
+    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    virtual status_t    setGain(float gain) { return NO_ERROR; }
+    virtual ssize_t     read(void* buffer, ssize_t bytes);
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+    virtual status_t    standby() { return NO_ERROR; }
+};
+
+class AudioHardwareStub : public  AudioHardwareBase
+{
+public:
+                        AudioHardwareStub();
+    virtual             ~AudioHardwareStub();
+    virtual status_t    initCheck();
+    virtual status_t    setVoiceVolume(float volume);
+    virtual status_t    setMasterVolume(float volume);
+
+    // mic mute
+    virtual status_t    setMicMute(bool state) { mMicMute = state;  return  NO_ERROR; }
+    virtual status_t    getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; }
+
+    virtual status_t    setParameter(const char* key, const char* value)
+            { return NO_ERROR; }
+
+    // create I/O streams
+    virtual AudioStreamOut* openOutputStream(
+                                int format=0,
+                                int channelCount=0,
+                                uint32_t sampleRate=0,
+                                status_t *status=0);
+
+    virtual AudioStreamIn* openInputStream(
+                                int format,
+                                int channelCount,
+                                uint32_t sampleRate,
+                                status_t *status,
+				AudioSystem::audio_in_acoustics acoustics);
+
+protected:
+    virtual status_t    doRouting() { return NO_ERROR; }
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+            bool        mMicMute;
+private:
+    status_t            dumpInternals(int fd, const Vector<String16>& args);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_STUB_H
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
new file mode 100644
index 0000000..b03467f
--- /dev/null
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -0,0 +1,913 @@
+/* //device/include/server/AudioFlinger/AudioMixer.cpp
+**
+** Copyright 2007, 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.
+*/
+
+#define LOG_TAG "AudioMixer"
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "AudioMixer.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+static inline int16_t clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)
+    :   mActiveTrack(0), mTrackNames(0), mSampleRate(sampleRate)
+{
+    mState.enabledTracks= 0;
+    mState.needsChanged = 0;
+    mState.frameCount   = frameCount;
+    mState.outputTemp   = 0;
+    mState.resampleTemp = 0;
+    mState.hook         = process__nop;
+    track_t* t = mState.tracks;
+    for (int i=0 ; i<32 ; i++) {
+        t->needs = 0;
+        t->volume[0] = UNITY_GAIN;
+        t->volume[1] = UNITY_GAIN;
+        t->volumeInc[0] = 0;
+        t->volumeInc[1] = 0;
+        t->channelCount = 2;
+        t->enabled = 0;
+        t->format = 16;
+        t->buffer.raw = 0;
+        t->bufferProvider = 0;
+        t->hook = 0;
+        t->resampler = 0;
+        t->sampleRate = mSampleRate;
+        t->in = 0;
+        t++;
+    }
+}
+
+ AudioMixer::~AudioMixer()
+ {
+     track_t* t = mState.tracks;
+     for (int i=0 ; i<32 ; i++) {
+         delete t->resampler;
+         t++;
+     }
+     delete [] mState.outputTemp;
+     delete [] mState.resampleTemp;
+ }
+
+ int AudioMixer::getTrackName()
+ {
+    uint32_t names = mTrackNames;
+    uint32_t mask = 1;
+    int n = 0;
+    while (names & mask) {
+        mask <<= 1;
+        n++;
+    }
+    if (mask) {
+        LOGV("add track (%d)", n);
+        mTrackNames |= mask;
+        return TRACK0 + n;
+    }
+    return -1;
+ }
+
+ void AudioMixer::invalidateState(uint32_t mask)
+ {
+    if (mask) {
+        mState.needsChanged |= mask;
+        mState.hook = process__validate;
+    }
+ }
+
+ void AudioMixer::deleteTrackName(int name)
+ {
+    name -= TRACK0;
+    if (uint32_t(name) < MAX_NUM_TRACKS) {
+        LOGV("deleteTrackName(%d)", name);
+        track_t& track(mState.tracks[ name ]);
+        if (track.enabled != 0) {
+            track.enabled = 0;
+            invalidateState(1<<name);
+        }
+        if (track.resampler) {
+            // delete  the resampler
+            delete track.resampler;
+            track.resampler = 0;
+            track.sampleRate = mSampleRate;
+            invalidateState(1<<name);
+        }
+        track.volumeInc[0] = 0;
+        track.volumeInc[1] = 0;
+        mTrackNames &= ~(1<<name);
+    }
+ }
+
+status_t AudioMixer::enable(int name)
+{
+    switch (name) {
+        case MIXING: {
+            if (mState.tracks[ mActiveTrack ].enabled != 1) {
+                mState.tracks[ mActiveTrack ].enabled = 1;
+                LOGV("enable(%d)", mActiveTrack);
+                invalidateState(1<<mActiveTrack);
+            }
+        } break;
+        default:
+            return NAME_NOT_FOUND;
+    }
+    return NO_ERROR;
+}
+
+status_t AudioMixer::disable(int name)
+{
+    switch (name) {
+        case MIXING: {
+            if (mState.tracks[ mActiveTrack ].enabled != 0) {
+                mState.tracks[ mActiveTrack ].enabled = 0;
+                LOGV("disable(%d)", mActiveTrack);
+                invalidateState(1<<mActiveTrack);
+            }
+        } break;
+        default:
+            return NAME_NOT_FOUND;
+    }
+    return NO_ERROR;
+}
+
+status_t AudioMixer::setActiveTrack(int track)
+{
+    if (uint32_t(track-TRACK0) >= MAX_NUM_TRACKS) {
+        return BAD_VALUE;
+    }
+    mActiveTrack = track - TRACK0;
+    return NO_ERROR;
+}
+
+status_t AudioMixer::setParameter(int target, int name, int value)
+{
+    switch (target) {
+    case TRACK:
+        if (name == CHANNEL_COUNT) {
+            if ((uint32_t(value) <= MAX_NUM_CHANNELS) && (value)) {
+                if (mState.tracks[ mActiveTrack ].channelCount != value) {
+                    mState.tracks[ mActiveTrack ].channelCount = value;
+                    LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", value);
+                    invalidateState(1<<mActiveTrack);
+                }
+                return NO_ERROR;
+            }
+        }
+        break;
+    case RESAMPLE:
+        if (name == SAMPLE_RATE) {
+            if (value > 0) {
+                track_t& track = mState.tracks[ mActiveTrack ];
+                if (track.setResampler(uint32_t(value), mSampleRate)) {
+                    LOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)",
+                            uint32_t(value));
+                    invalidateState(1<<mActiveTrack);
+                }
+                return NO_ERROR;
+            }
+        }
+        break;
+    case RAMP_VOLUME:
+    case VOLUME:
+        if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {
+            track_t& track = mState.tracks[ mActiveTrack ];
+            if (track.volume[name-VOLUME0] != value) {
+                track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16;
+                track.volume[name-VOLUME0] = value;
+                if (target == VOLUME) {
+                    track.prevVolume[name-VOLUME0] = value << 16;
+                    track.volumeInc[name-VOLUME0] = 0;
+                } else {
+                    int32_t d = (value<<16) - track.prevVolume[name-VOLUME0];
+                    int32_t volInc = d / int32_t(mState.frameCount);
+                    track.volumeInc[name-VOLUME0] = volInc;
+                    if (volInc == 0) {
+                        track.prevVolume[name-VOLUME0] = value << 16;
+                    }
+                }
+                invalidateState(1<<mActiveTrack);
+            }
+            return NO_ERROR;
+        }
+        break;
+    }
+    return BAD_VALUE;
+}
+
+bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
+{
+    if (value!=devSampleRate || resampler) {
+        if (sampleRate != value) {
+            sampleRate = value;
+            if (resampler == 0) {
+                resampler = AudioResampler::create(
+                        format, channelCount, devSampleRate);
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioMixer::track_t::doesResample() const
+{
+    return resampler != 0;
+}
+
+inline
+void AudioMixer::track_t::adjustVolumeRamp()
+{
+    for (int i=0 ; i<2 ; i++) {
+        if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
+            ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) {
+            volumeInc[i] = 0;
+            prevVolume[i] = volume[i]<<16;
+        }
+    }
+}
+
+
+status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer)
+{
+    mState.tracks[ mActiveTrack ].bufferProvider = buffer;
+    return NO_ERROR;
+}
+
+
+
+void AudioMixer::process(void* output)
+{
+    mState.hook(&mState, output);
+}
+
+
+void AudioMixer::process__validate(state_t* state, void* output)
+{
+    LOGW_IF(!state->needsChanged,
+        "in process__validate() but nothing's invalid");
+
+    uint32_t changed = state->needsChanged;
+    state->needsChanged = 0; // clear the validation flag
+
+    // recompute which tracks are enabled / disabled
+    uint32_t enabled = 0;
+    uint32_t disabled = 0;
+    while (changed) {
+        const int i = 31 - __builtin_clz(changed);
+        const uint32_t mask = 1<<i;
+        changed &= ~mask;
+        track_t& t = state->tracks[i];
+        (t.enabled ? enabled : disabled) |= mask;
+    }
+    state->enabledTracks &= ~disabled;
+    state->enabledTracks |=  enabled;
+
+    // compute everything we need...
+    int countActiveTracks = 0;
+    int all16BitsStereoNoResample = 1;
+    int resampling = 0;
+    int volumeRamp = 0;
+    uint32_t en = state->enabledTracks;
+    while (en) {
+        const int i = 31 - __builtin_clz(en);
+        en &= ~(1<<i);
+
+        countActiveTracks++;
+        track_t& t = state->tracks[i];
+        uint32_t n = 0;
+        n |= NEEDS_CHANNEL_1 + t.channelCount - 1;
+        n |= NEEDS_FORMAT_16;
+        n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED;
+       
+        if (t.volumeInc[0]|t.volumeInc[1]) {
+            volumeRamp = 1;
+        } else if (!t.doesResample() && t.volumeRL == 0) {
+            n |= NEEDS_MUTE_ENABLED;
+        }
+        t.needs = n;
+
+        if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) {
+            t.hook = track__nop;
+        } else {
+            if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
+                all16BitsStereoNoResample = 0;
+                resampling = 1;
+                t.hook = track__genericResample;
+            } else {
+                if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
+                    t.hook = track__16BitsMono;
+                    all16BitsStereoNoResample = 0;
+                }
+                if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_2){
+                    t.hook = track__16BitsStereo;
+                }
+            }
+        }
+    }
+
+    // select the processing hooks
+    state->hook = process__nop;
+    if (countActiveTracks) {
+        if (resampling) {
+            if (!state->outputTemp) {
+                state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
+            }
+            if (!state->resampleTemp) {
+                state->resampleTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
+            }
+            state->hook = process__genericResampling;
+        } else {
+            if (state->outputTemp) {
+                delete [] state->outputTemp;
+                state->outputTemp = 0;
+            }
+            if (state->resampleTemp) {
+                delete [] state->resampleTemp;
+                state->resampleTemp = 0;
+            }
+            state->hook = process__genericNoResampling;
+            if (all16BitsStereoNoResample && !volumeRamp) {
+                if (countActiveTracks == 1) {
+                    state->hook = process__OneTrack16BitsStereoNoResampling;
+                }
+            }
+        }
+    }
+
+    LOGV("mixer configuration change: %d activeTracks (%08x) "
+        "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d",
+        countActiveTracks, state->enabledTracks,
+        all16BitsStereoNoResample, resampling, volumeRamp);
+
+   state->hook(state, output);
+
+   // Now that the volume ramp has been done, set optimal state and
+   // track hooks for subsequent mixer process
+   if (countActiveTracks) {
+       int allMuted = 1;
+       uint32_t en = state->enabledTracks;
+       while (en) {
+           const int i = 31 - __builtin_clz(en);
+           en &= ~(1<<i);
+           track_t& t = state->tracks[i];
+           if (!t.doesResample() && t.volumeRL == 0)
+           {
+               t.needs |= NEEDS_MUTE_ENABLED;
+               t.hook = track__nop;
+           } else {
+               allMuted = 0;
+           }
+       }
+       if (allMuted) {
+           state->hook = process__nop;
+       } else if (!resampling && all16BitsStereoNoResample) {
+           if (countActiveTracks == 1) {
+              state->hook = process__OneTrack16BitsStereoNoResampling;
+           }
+       }
+   }
+}
+
+static inline
+int32_t mulAdd(int16_t in, int16_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    asm( "smlabb %[out], %[in], %[v], %[a] \n"
+         : [out]"=r"(out)
+         : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
+         : );
+    return out;
+#else
+    return a + in * int32_t(v);
+#endif
+}
+
+static inline
+int32_t mul(int16_t in, int16_t v)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    asm( "smulbb %[out], %[in], %[v] \n"
+         : [out]"=r"(out)
+         : [in]"%r"(in), [v]"r"(v)
+         : );
+    return out;
+#else
+    return in * int32_t(v);
+#endif
+}
+
+static inline
+int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    if (left) {
+        asm( "smlabb %[out], %[inRL], %[vRL], %[a] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
+             : );
+    } else {
+        asm( "smlatt %[out], %[inRL], %[vRL], %[a] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
+             : );
+    }
+    return out;
+#else
+    if (left) {
+        return a + int16_t(inRL&0xFFFF) * int16_t(vRL&0xFFFF);
+    } else {
+        return a + int16_t(inRL>>16) * int16_t(vRL>>16);
+    }
+#endif
+}
+
+static inline
+int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    if (left) {
+        asm( "smulbb %[out], %[inRL], %[vRL] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [vRL]"r"(vRL)
+             : );
+    } else {
+        asm( "smultt %[out], %[inRL], %[vRL] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [vRL]"r"(vRL)
+             : );
+    }
+    return out;
+#else
+    if (left) {
+        return int16_t(inRL&0xFFFF) * int16_t(vRL&0xFFFF);
+    } else {
+        return int16_t(inRL>>16) * int16_t(vRL>>16);
+    }
+#endif
+}
+
+
+void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+{
+    t->resampler->setSampleRate(t->sampleRate);
+
+    // ramp gain - resample to temp buffer and scale/mix in 2nd step
+    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+        t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
+        memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
+        t->resampler->resample(temp, outFrameCount, t->bufferProvider);
+        volumeRampStereo(t, out, outFrameCount, temp);
+    }
+
+    // constant gain
+    else {
+        t->resampler->setVolume(t->volume[0], t->volume[1]);
+        t->resampler->resample(out, outFrameCount, t->bufferProvider);
+    }
+}
+
+void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+{
+}
+
+void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+{
+    int32_t vl = t->prevVolume[0];
+    int32_t vr = t->prevVolume[1];
+    const int32_t vlInc = t->volumeInc[0];
+    const int32_t vrInc = t->volumeInc[1];
+
+    //LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+    //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+    //       (vl + vlInc*frameCount)/65536.0f, frameCount);
+   
+    // ramp volume
+    do {
+        *out++ += (vl >> 16) * (*temp++ >> 12);
+        *out++ += (vr >> 16) * (*temp++ >> 12);
+        vl += vlInc;
+        vr += vrInc;
+    } while (--frameCount);
+
+    t->prevVolume[0] = vl;
+    t->prevVolume[1] = vr;
+    t->adjustVolumeRamp();
+}
+
+void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+{
+    int16_t const *in = static_cast<int16_t const *>(t->in);
+
+    // ramp gain
+    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+        int32_t vl = t->prevVolume[0];
+        int32_t vr = t->prevVolume[1];
+        const int32_t vlInc = t->volumeInc[0];
+        const int32_t vrInc = t->volumeInc[1];
+
+        // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+        //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+        //        (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+        do {
+            *out++ += (vl >> 16) * (int32_t) *in++;
+            *out++ += (vr >> 16) * (int32_t) *in++;
+            vl += vlInc;
+            vr += vrInc;
+        } while (--frameCount);
+       
+        t->prevVolume[0] = vl;
+        t->prevVolume[1] = vr;
+        t->adjustVolumeRamp();
+    }
+
+    // constant gain
+    else {
+        const uint32_t vrl = t->volumeRL;
+        do {
+            uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+            in += 2;
+            out[0] = mulAddRL(1, rl, vrl, out[0]);
+            out[1] = mulAddRL(0, rl, vrl, out[1]);
+            out += 2;
+        } while (--frameCount);
+    }
+    t->in = in;
+}
+
+void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+{
+    int16_t const *in = static_cast<int16_t const *>(t->in);
+
+    // ramp gain
+    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+        int32_t vl = t->prevVolume[0];
+        int32_t vr = t->prevVolume[1];
+        const int32_t vlInc = t->volumeInc[0];
+        const int32_t vrInc = t->volumeInc[1];
+
+        // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+        //         t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+        //         (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+        do {
+            int32_t l = *in++;
+            *out++ += (vl >> 16) * l;
+            *out++ += (vr >> 16) * l;
+            vl += vlInc;
+            vr += vrInc;
+        } while (--frameCount);
+       
+        t->prevVolume[0] = vl;
+        t->prevVolume[1] = vr;
+        t->adjustVolumeRamp();
+    }
+    // constant gain
+    else {
+        const int16_t vl = t->volume[0];
+        const int16_t vr = t->volume[1];
+        do {
+            int16_t l = *in++;
+            out[0] = mulAdd(l, vl, out[0]);
+            out[1] = mulAdd(l, vr, out[1]);
+            out += 2;
+        } while (--frameCount);
+    }
+    t->in = in;
+}
+
+inline
+void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
+{
+    for (size_t i=0 ; i<c ; i++) {
+        int32_t l = *sums++;
+        int32_t r = *sums++;
+        int32_t nl = l >> 12;
+        int32_t nr = r >> 12;
+        l = clamp16(nl);
+        r = clamp16(nr);
+        *out++ = (r<<16) | (l & 0xFFFF);
+    }
+}
+
+// no-op case
+void AudioMixer::process__nop(state_t* state, void* output)
+{
+    // this assumes output 16 bits stereo, no resampling
+    memset(output, 0, state->frameCount*4);
+    uint32_t en = state->enabledTracks;
+    while (en) {
+        const int i = 31 - __builtin_clz(en);
+        en &= ~(1<<i);
+        track_t& t = state->tracks[i];
+        size_t outFrames = state->frameCount;
+        while (outFrames) {
+            t.buffer.frameCount = outFrames;
+            t.bufferProvider->getNextBuffer(&t.buffer);
+            if (!t.buffer.raw) break;
+            outFrames -= t.buffer.frameCount;
+            t.bufferProvider->releaseBuffer(&t.buffer);
+        }
+    }
+}
+
+// generic code without resampling
+void AudioMixer::process__genericNoResampling(state_t* state, void* output)
+{
+    int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
+
+    // acquire each track's buffer
+    uint32_t enabledTracks = state->enabledTracks;
+    uint32_t en = enabledTracks;
+    while (en) {
+        const int i = 31 - __builtin_clz(en);
+        en &= ~(1<<i);
+        track_t& t = state->tracks[i];
+        t.buffer.frameCount = state->frameCount;
+        t.bufferProvider->getNextBuffer(&t.buffer);
+        t.frameCount = t.buffer.frameCount;
+        t.in = t.buffer.raw;
+        // t.in == NULL can happen if the track was flushed just after having
+        // been enabled for mixing.
+        if (t.in == NULL)
+            enabledTracks &= ~(1<<i);
+    }
+
+    // this assumes output 16 bits stereo, no resampling
+    int32_t* out = static_cast<int32_t*>(output);
+    size_t numFrames = state->frameCount;
+    do {
+        memset(outTemp, 0, sizeof(outTemp));
+
+        en = enabledTracks;
+        while (en) {
+            const int i = 31 - __builtin_clz(en);
+            en &= ~(1<<i);
+            track_t& t = state->tracks[i];
+            size_t outFrames = BLOCKSIZE;
+           
+            while (outFrames) {
+                size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
+                if (inFrames) {
+                    (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp);
+                    t.frameCount -= inFrames;
+                    outFrames -= inFrames;
+                }
+                if (t.frameCount == 0 && outFrames) {
+                    t.bufferProvider->releaseBuffer(&t.buffer);
+                    t.buffer.frameCount = numFrames - (BLOCKSIZE - outFrames);
+                    t.bufferProvider->getNextBuffer(&t.buffer);
+                    t.in = t.buffer.raw;
+                    if (t.in == NULL) {
+                        enabledTracks &= ~(1<<i);
+                        break;
+                    }
+                    t.frameCount = t.buffer.frameCount;
+                 }
+            }
+        }
+
+        ditherAndClamp(out, outTemp, BLOCKSIZE);
+        out += BLOCKSIZE;
+        numFrames -= BLOCKSIZE;
+    } while (numFrames);
+
+
+    // release each track's buffer
+    en = enabledTracks;
+    while (en) {
+        const int i = 31 - __builtin_clz(en);
+        en &= ~(1<<i);
+        track_t& t = state->tracks[i];
+        t.bufferProvider->releaseBuffer(&t.buffer);
+    }
+}
+
+// generic code with resampling
+void AudioMixer::process__genericResampling(state_t* state, void* output)
+{
+    int32_t* const outTemp = state->outputTemp;
+    const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
+    memset(outTemp, 0, size);
+
+    int32_t* out = static_cast<int32_t*>(output);
+    size_t numFrames = state->frameCount;
+
+    uint32_t en = state->enabledTracks;
+    while (en) {
+        const int i = 31 - __builtin_clz(en);
+        en &= ~(1<<i);
+        track_t& t = state->tracks[i];
+
+        // this is a little goofy, on the resampling case we don't
+        // acquire/release the buffers because it's done by
+        // the resampler.
+        if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
+            (t.hook)(&t, outTemp, numFrames, state->resampleTemp);
+        } else {
+
+            size_t outFrames = numFrames;
+           
+            while (outFrames) {
+                t.buffer.frameCount = outFrames;
+                t.bufferProvider->getNextBuffer(&t.buffer);
+                t.in = t.buffer.raw;
+                // t.in == NULL can happen if the track was flushed just after having
+                // been enabled for mixing.
+                if (t.in == NULL) break;
+
+                (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp);
+                outFrames -= t.buffer.frameCount;
+                t.bufferProvider->releaseBuffer(&t.buffer);
+            }
+        }
+    }
+
+    ditherAndClamp(out, outTemp, numFrames);
+}
+
+// one track, 16 bits stereo without resampling is the most common case
+void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* output)
+{
+    const int i = 31 - __builtin_clz(state->enabledTracks);
+    const track_t& t = state->tracks[i];
+
+    AudioBufferProvider::Buffer& b(t.buffer);
+   
+    int32_t* out = static_cast<int32_t*>(output);
+    size_t numFrames = state->frameCount;
+  
+    const int16_t vl = t.volume[0];
+    const int16_t vr = t.volume[1];
+    const uint32_t vrl = t.volumeRL;
+    while (numFrames) {
+        b.frameCount = numFrames;
+        t.bufferProvider->getNextBuffer(&b);
+        int16_t const *in = b.i16;
+
+        // in == NULL can happen if the track was flushed just after having
+        // been enabled for mixing.
+        if (in == NULL) {
+            memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t));
+            return;
+        }
+        size_t outFrames = b.frameCount;
+       
+        if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
+            // volume is boosted, so we might need to clamp even though
+            // we process only one track.
+            do {
+                uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+                in += 2;
+                int32_t l = mulRL(1, rl, vrl) >> 12;
+                int32_t r = mulRL(0, rl, vrl) >> 12;
+                // clamping...
+                l = clamp16(l);
+                r = clamp16(r);
+                *out++ = (r<<16) | (l & 0xFFFF);
+            } while (--outFrames);
+        } else {
+            do {
+                uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+                in += 2;
+                int32_t l = mulRL(1, rl, vrl) >> 12;
+                int32_t r = mulRL(0, rl, vrl) >> 12;
+                *out++ = (r<<16) | (l & 0xFFFF);
+            } while (--outFrames);
+        }
+        numFrames -= b.frameCount;
+        t.bufferProvider->releaseBuffer(&b);
+    }
+}
+
+// 2 tracks is also a common case
+void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output)
+{
+    int i;
+    uint32_t en = state->enabledTracks;
+
+    i = 31 - __builtin_clz(en);
+    const track_t& t0 = state->tracks[i];
+    AudioBufferProvider::Buffer& b0(t0.buffer);
+
+    en &= ~(1<<i);
+    i = 31 - __builtin_clz(en);
+    const track_t& t1 = state->tracks[i];
+    AudioBufferProvider::Buffer& b1(t1.buffer);
+   
+    int16_t const *in0;
+    const int16_t vl0 = t0.volume[0];
+    const int16_t vr0 = t0.volume[1];
+    size_t frameCount0 = 0;
+  
+    int16_t const *in1;
+    const int16_t vl1 = t1.volume[0];
+    const int16_t vr1 = t1.volume[1];
+    size_t frameCount1 = 0;
+   
+    int32_t* out = static_cast<int32_t*>(output);
+    size_t numFrames = state->frameCount;
+    int16_t const *buff = NULL;
+
+  
+    while (numFrames) {
+   
+        if (frameCount0 == 0) {
+            b0.frameCount = numFrames;
+            t0.bufferProvider->getNextBuffer(&b0);
+            if (b0.i16 == NULL) {
+                if (buff == NULL) {
+                    buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
+                }
+                in0 = buff;
+                b0.frameCount = numFrames;
+            } else {
+                in0 = b0.i16;
+            }
+            frameCount0 = b0.frameCount;
+        }
+        if (frameCount1 == 0) {
+            b1.frameCount = numFrames;
+            t1.bufferProvider->getNextBuffer(&b1);
+            if (b1.i16 == NULL) {
+                if (buff == NULL) {
+                    buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
+                }
+                in1 = buff;
+                b1.frameCount = numFrames;
+               } else {
+                in1 = b1.i16;
+            }
+            frameCount1 = b1.frameCount;
+        }
+       
+        size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;
+
+        numFrames -= outFrames;
+        frameCount0 -= outFrames;
+        frameCount1 -= outFrames;
+       
+        do {
+            int32_t l0 = *in0++;
+            int32_t r0 = *in0++;
+            l0 = mul(l0, vl0);
+            r0 = mul(r0, vr0);
+            int32_t l = *in1++;
+            int32_t r = *in1++;
+            l = mulAdd(l, vl1, l0) >> 12;
+            r = mulAdd(r, vr1, r0) >> 12;
+            // clamping...
+            l = clamp16(l);
+            r = clamp16(r);
+            *out++ = (r<<16) | (l & 0xFFFF);
+        } while (--outFrames);
+       
+        if (frameCount0 == 0) {
+            t0.bufferProvider->releaseBuffer(&b0);
+        }
+        if (frameCount1 == 0) {
+            t1.bufferProvider->releaseBuffer(&b1);
+        }
+    }   
+       
+    if (buff != NULL) {
+        delete [] buff;       
+    }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
new file mode 100644
index 0000000..72ca28a
--- /dev/null
+++ b/libs/audioflinger/AudioMixer.h
@@ -0,0 +1,192 @@
+/* //device/include/server/AudioFlinger/AudioMixer.h
+**
+** Copyright 2007, 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.
+*/
+
+#ifndef ANDROID_AUDIO_MIXER_H
+#define ANDROID_AUDIO_MIXER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "AudioBufferProvider.h"
+#include "AudioResampler.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+// ----------------------------------------------------------------------------
+
+class AudioMixer
+{
+public:
+                            AudioMixer(size_t frameCount, uint32_t sampleRate);
+
+                            ~AudioMixer();
+
+    static const uint32_t MAX_NUM_TRACKS = 32;
+    static const uint32_t MAX_NUM_CHANNELS = 2;
+
+    static const uint16_t UNITY_GAIN = 0x1000;
+
+    enum { // names
+
+        // track units (32 units)
+        TRACK0          = 0x1000,
+
+        // enable/disable
+        MIXING          = 0x2000,
+
+        // setParameter targets
+        TRACK           = 0x3000,
+        RESAMPLE        = 0x3001,
+        RAMP_VOLUME     = 0x3002, // ramp to new volume
+        VOLUME          = 0x3003, // don't ramp
+
+        // set Parameter names
+        // for target TRACK
+        CHANNEL_COUNT   = 0x4000,
+        FORMAT          = 0x4001,
+        // for TARGET RESAMPLE
+        SAMPLE_RATE     = 0x4100,
+        // for TARGET VOLUME (8 channels max)
+        VOLUME0         = 0x4200,
+        VOLUME1         = 0x4201,
+    };
+
+
+    int         getTrackName();
+    void        deleteTrackName(int name);
+
+    status_t    enable(int name);
+    status_t    disable(int name);
+
+    status_t    setActiveTrack(int track);
+    status_t    setParameter(int target, int name, int value);
+
+    status_t    setBufferProvider(AudioBufferProvider* bufferProvider);
+    void        process(void* output);
+
+    uint32_t    trackNames() const { return mTrackNames; }
+
+private:
+
+    enum {
+        NEEDS_CHANNEL_COUNT__MASK   = 0x00000003,
+        NEEDS_FORMAT__MASK          = 0x000000F0,
+        NEEDS_MUTE__MASK            = 0x00000100,
+        NEEDS_RESAMPLE__MASK        = 0x00001000,
+    };
+
+    enum {
+        NEEDS_CHANNEL_1             = 0x00000000,
+        NEEDS_CHANNEL_2             = 0x00000001,
+
+        NEEDS_FORMAT_16             = 0x00000010,
+
+        NEEDS_MUTE_DISABLED         = 0x00000000,
+        NEEDS_MUTE_ENABLED          = 0x00000100,
+
+        NEEDS_RESAMPLE_DISABLED     = 0x00000000,
+        NEEDS_RESAMPLE_ENABLED      = 0x00001000,
+    };
+
+    static inline int32_t applyVolume(int32_t in, int32_t v) {
+        return in * v;
+    }
+
+
+    struct state_t;
+
+    typedef void (*mix_t)(state_t* state, void* output);
+
+    static const int BLOCKSIZE = 16; // 4 cache lines
+
+    struct track_t {
+        uint32_t    needs;
+
+        union {
+        int16_t     volume[2];      // [0]3.12 fixed point
+        int32_t     volumeRL;
+        };
+
+        int32_t     prevVolume[2];
+
+        int32_t     volumeInc[2];
+
+        uint16_t    frameCount;
+
+        uint8_t     channelCount : 4;
+        uint8_t     enabled      : 1;
+        uint8_t     reserved0    : 3;
+        uint8_t     format;
+
+        AudioBufferProvider*                bufferProvider;
+        mutable AudioBufferProvider::Buffer buffer;
+
+        void (*hook)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp);
+        void const* in;             // current location in buffer
+
+        AudioResampler*     resampler;
+        uint32_t            sampleRate;
+
+        bool        setResampler(uint32_t sampleRate, uint32_t devSampleRate);
+        bool        doesResample() const;
+        void        adjustVolumeRamp();
+    };
+
+    // pad to 32-bytes to fill cache line
+    struct state_t {
+        uint32_t        enabledTracks;
+        uint32_t        needsChanged;
+        size_t          frameCount;
+        mix_t           hook;
+        int32_t         *outputTemp;
+        int32_t         *resampleTemp;
+        int32_t         reserved[2];
+        track_t         tracks[32]; __attribute__((aligned(32)));
+    };
+
+    int             mActiveTrack;
+    uint32_t        mTrackNames;
+    const uint32_t  mSampleRate;
+
+    state_t         mState __attribute__((aligned(32)));
+
+    void invalidateState(uint32_t mask);
+
+    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+    static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+    static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp);
+    static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+    static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+    static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c);
+
+    static void process__validate(state_t* state, void* output);
+    static void process__nop(state_t* state, void* output);
+    static void process__genericNoResampling(state_t* state, void* output);
+    static void process__genericResampling(state_t* state, void* output);
+    static void process__OneTrack16BitsStereoNoResampling(state_t* state, void* output);
+    static void process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_AUDIO_MIXER_H
diff --git a/libs/audioflinger/AudioResampler.cpp b/libs/audioflinger/AudioResampler.cpp
new file mode 100644
index 0000000..5dabacb
--- /dev/null
+++ b/libs/audioflinger/AudioResampler.cpp
@@ -0,0 +1,595 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "AudioResampler"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include "AudioResampler.h"
+#include "AudioResamplerSinc.h"
+#include "AudioResamplerCubic.h"
+
+namespace android {
+
+#ifdef __ARM_ARCH_5E__  // optimized asm option
+    #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
+#endif // __ARM_ARCH_5E__
+// ----------------------------------------------------------------------------
+
+class AudioResamplerOrder1 : public AudioResampler {
+public:
+    AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) :
+        AudioResampler(bitDepth, inChannelCount, sampleRate), mX0L(0), mX0R(0) {
+    }
+    virtual void resample(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+private:
+    // number of bits used in interpolation multiply - 15 bits avoids overflow
+    static const int kNumInterpBits = 15;
+
+    // bits to shift the phase fraction down to avoid overflow
+    static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;
+
+    void init() {}
+    void resampleMono16(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+    void resampleStereo16(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
+    void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+            uint32_t &phaseFraction, uint32_t phaseIncrement);
+    void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+            uint32_t &phaseFraction, uint32_t phaseIncrement);
+#endif  // ASM_ARM_RESAMP1
+
+    static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) {
+        return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits);
+    }
+    static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) {
+        *frac += inc;
+        *index += (size_t)(*frac >> kNumPhaseBits);
+        *frac &= kPhaseMask;
+    }
+    int mX0L;
+    int mX0R;
+};
+
+// ----------------------------------------------------------------------------
+AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
+        int32_t sampleRate, int quality) {
+
+    // can only create low quality resample now
+    AudioResampler* resampler;
+
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("af.resampler.quality", value, 0)) {
+        quality = atoi(value);
+        LOGD("forcing AudioResampler quality to %d", quality);
+    }
+
+    if (quality == DEFAULT)
+        quality = LOW_QUALITY;
+
+    switch (quality) {
+    default:
+    case LOW_QUALITY:
+        LOGV("Create linear Resampler");
+        resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
+        break;
+    case MED_QUALITY:
+        LOGV("Create cubic Resampler");
+        resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
+        break;
+    case HIGH_QUALITY:
+        LOGV("Create sinc Resampler");
+        resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
+        break;
+    }
+
+    // initialize resampler
+    resampler->init();
+    return resampler;
+}
+
+AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
+        int32_t sampleRate) :
+    mBitDepth(bitDepth), mChannelCount(inChannelCount),
+            mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
+            mPhaseFraction(0) {
+    // sanity check on format
+    if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
+        LOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
+                inChannelCount);
+        // LOG_ASSERT(0);
+    }
+
+    // initialize common members
+    mVolume[0] = mVolume[1] = 0;
+    mBuffer.frameCount = 0;
+
+    // save format for quick lookup
+    if (inChannelCount == 1) {
+        mFormat = MONO_16_BIT;
+    } else {
+        mFormat = STEREO_16_BIT;
+    }
+}
+
+AudioResampler::~AudioResampler() {
+}
+
+void AudioResampler::setSampleRate(int32_t inSampleRate) {
+    mInSampleRate = inSampleRate;
+    mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate);
+}
+
+void AudioResampler::setVolume(int16_t left, int16_t right) {
+    // TODO: Implement anti-zipper filter
+    mVolume[0] = left;
+    mVolume[1] = right;
+}
+
+// ----------------------------------------------------------------------------
+
+void AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider) {
+
+    // should never happen, but we overflow if it does
+    // LOG_ASSERT(outFrameCount < 32767);
+
+    // select the appropriate resampler
+    switch (mChannelCount) {
+    case 1:
+        resampleMono16(out, outFrameCount, provider);
+        break;
+    case 2:
+        resampleStereo16(out, outFrameCount, provider);
+        break;
+    }
+}
+
+void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider) {
+
+    int32_t vl = mVolume[0];
+    int32_t vr = mVolume[1];
+
+    size_t inputIndex = mInputIndex;
+    uint32_t phaseFraction = mPhaseFraction;
+    uint32_t phaseIncrement = mPhaseIncrement;
+    size_t outputIndex = 0;
+    size_t outputSampleCount = outFrameCount * 2;
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+
+    // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
+    //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
+
+    while (outputIndex < outputSampleCount) {
+
+        // buffer is empty, fetch a new one
+        while (mBuffer.frameCount == 0) {
+            mBuffer.frameCount = inFrameCount;
+            provider->getNextBuffer(&mBuffer);
+            if (mBuffer.raw == NULL) {
+                goto resampleStereo16_exit;
+            }
+
+            // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+            if (mBuffer.frameCount > inputIndex) break;
+
+            inputIndex -= mBuffer.frameCount;
+            mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
+            mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
+            provider->releaseBuffer(&mBuffer);
+             // mBuffer.frameCount == 0 now so we reload a new buffer
+        }
+
+        int16_t *in = mBuffer.i16;
+
+        // handle boundary case
+        while (inputIndex == 0) {
+            // LOGE("boundary case\n");
+            out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
+            out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
+            Advance(&inputIndex, &phaseFraction, phaseIncrement);
+            if (outputIndex == outputSampleCount)
+                break;
+        }
+
+        // process input samples
+        // LOGE("general case\n");
+
+#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
+        if (inputIndex + 2 < mBuffer.frameCount) {
+            int32_t* maxOutPt;
+            int32_t maxInIdx;
+
+            maxOutPt = out + (outputSampleCount - 2);   // 2 because 2 frames per loop
+            maxInIdx = mBuffer.frameCount - 2;
+            AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
+                    phaseFraction, phaseIncrement);
+        }
+#endif  // ASM_ARM_RESAMP1
+
+        while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
+            out[outputIndex++] += vl * Interp(in[inputIndex*2-2],
+                    in[inputIndex*2], phaseFraction);
+            out[outputIndex++] += vr * Interp(in[inputIndex*2-1],
+                    in[inputIndex*2+1], phaseFraction);
+            Advance(&inputIndex, &phaseFraction, phaseIncrement);
+        }
+
+        // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+
+        // if done with buffer, save samples
+        if (inputIndex >= mBuffer.frameCount) {
+            inputIndex -= mBuffer.frameCount;
+
+            // LOGE("buffer done, new input index %d", inputIndex);
+
+            mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
+            mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
+            provider->releaseBuffer(&mBuffer);
+
+            // verify that the releaseBuffer resets the buffer frameCount
+            // LOG_ASSERT(mBuffer.frameCount == 0);
+        }
+    }
+
+    // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+
+resampleStereo16_exit:
+    // save state
+    mInputIndex = inputIndex;
+    mPhaseFraction = phaseFraction;
+}
+
+void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider) {
+
+    int32_t vl = mVolume[0];
+    int32_t vr = mVolume[1];
+
+    size_t inputIndex = mInputIndex;
+    uint32_t phaseFraction = mPhaseFraction;
+    uint32_t phaseIncrement = mPhaseIncrement;
+    size_t outputIndex = 0;
+    size_t outputSampleCount = outFrameCount * 2;
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+
+    // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
+    //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
+    while (outputIndex < outputSampleCount) {
+        // buffer is empty, fetch a new one
+        while (mBuffer.frameCount == 0) {
+            mBuffer.frameCount = inFrameCount;
+            provider->getNextBuffer(&mBuffer);
+            if (mBuffer.raw == NULL) {
+                mInputIndex = inputIndex;
+                mPhaseFraction = phaseFraction;
+                goto resampleMono16_exit;
+            }
+            // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+            if (mBuffer.frameCount >  inputIndex) break;
+
+            inputIndex -= mBuffer.frameCount;
+            mX0L = mBuffer.i16[mBuffer.frameCount-1];
+            provider->releaseBuffer(&mBuffer);
+            // mBuffer.frameCount == 0 now so we reload a new buffer
+        }
+        int16_t *in = mBuffer.i16;
+
+        // handle boundary case
+        while (inputIndex == 0) {
+            // LOGE("boundary case\n");
+            int32_t sample = Interp(mX0L, in[0], phaseFraction);
+            out[outputIndex++] += vl * sample;
+            out[outputIndex++] += vr * sample;
+            Advance(&inputIndex, &phaseFraction, phaseIncrement);
+            if (outputIndex == outputSampleCount)
+                break;
+        }
+
+        // process input samples
+        // LOGE("general case\n");
+
+#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
+        if (inputIndex + 2 < mBuffer.frameCount) {
+            int32_t* maxOutPt;
+            int32_t maxInIdx;
+
+            maxOutPt = out + (outputSampleCount - 2);
+            maxInIdx = (int32_t)mBuffer.frameCount - 2;
+                AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
+                        phaseFraction, phaseIncrement);
+        }
+#endif  // ASM_ARM_RESAMP1
+
+        while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
+            int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
+                    phaseFraction);
+            out[outputIndex++] += vl * sample;
+            out[outputIndex++] += vr * sample;
+            Advance(&inputIndex, &phaseFraction, phaseIncrement);
+        }
+
+
+        // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+
+        // if done with buffer, save samples
+        if (inputIndex >= mBuffer.frameCount) {
+            inputIndex -= mBuffer.frameCount;
+
+            // LOGE("buffer done, new input index %d", inputIndex);
+
+            mX0L = mBuffer.i16[mBuffer.frameCount-1];
+            provider->releaseBuffer(&mBuffer);
+
+            // verify that the releaseBuffer resets the buffer frameCount
+            // LOG_ASSERT(mBuffer.frameCount == 0);
+        }
+    }
+
+    // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+
+resampleMono16_exit:
+    // save state
+    mInputIndex = inputIndex;
+    mPhaseFraction = phaseFraction;
+}
+
+#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
+
+/*******************************************************************
+*
+*   AsmMono16Loop
+*   asm optimized monotonic loop version; one loop is 2 frames
+*   Input:
+*       in : pointer on input samples
+*       maxOutPt : pointer on first not filled
+*       maxInIdx : index on first not used
+*       outputIndex : pointer on current output index
+*       out : pointer on output buffer
+*       inputIndex : pointer on current input index
+*       vl, vr : left and right gain
+*       phaseFraction : pointer on current phase fraction
+*       phaseIncrement
+*   Ouput:
+*       outputIndex :
+*       out : updated buffer
+*       inputIndex : index of next to use
+*       phaseFraction : phase fraction for next interpolation
+*
+*******************************************************************/
+void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+            uint32_t &phaseFraction, uint32_t phaseIncrement)
+{
+#define MO_PARAM5   "36"        // offset of parameter 5 (outputIndex)
+
+    asm(
+        "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
+        // get parameters
+        "   ldr r6, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
+        "   ldr r6, [r6]\n"                         // phaseFraction
+        "   ldr r7, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
+        "   ldr r7, [r7]\n"                         // inputIndex
+        "   ldr r8, [sp, #" MO_PARAM5 " + 4]\n"     // out
+        "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
+        "   ldr r0, [r0]\n"                         // outputIndex
+        "   add r8, r0, asl #2\n"                   // curOut
+        "   ldr r9, [sp, #" MO_PARAM5 " + 24]\n"    // phaseIncrement
+        "   ldr r10, [sp, #" MO_PARAM5 " + 12]\n"   // vl
+        "   ldr r11, [sp, #" MO_PARAM5 " + 16]\n"   // vr
+
+        // r0 pin, x0, Samp
+
+        // r1 in
+        // r2 maxOutPt
+        // r3 maxInIdx
+
+        // r4 x1, i1, i3, Out1
+        // r5 out0
+
+        // r6 frac
+        // r7 inputIndex
+        // r8 curOut
+
+        // r9 inc
+        // r10 vl
+        // r11 vr
+
+        // r12
+        // r13 sp
+        // r14
+
+        // the following loop works on 2 frames
+
+        ".Y4L01:\n"
+        "   cmp r8, r2\n"                   // curOut - maxCurOut
+        "   bcs .Y4L02\n"
+
+#define MO_ONE_FRAME \
+    "   add r0, r1, r7, asl #1\n"       /* in + inputIndex */\
+    "   ldrsh r4, [r0]\n"               /* in[inputIndex] */\
+    "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
+    "   ldrsh r0, [r0, #-2]\n"          /* in[inputIndex-1] */\
+    "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
+    "   sub r4, r4, r0\n"               /* in[inputIndex] - in[inputIndex-1] */\
+    "   mov r4, r4, lsl #2\n"           /* <<2 */\
+    "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
+    "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
+    "   add r0, r0, r4\n"               /* x0 - (..) */\
+    "   mla r5, r0, r10, r5\n"          /* vl*interp + out[] */\
+    "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
+    "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
+    "   mla r4, r0, r11, r4\n"          /* vr*interp + out[] */\
+    "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */\
+    "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */
+
+        MO_ONE_FRAME    // frame 1
+        MO_ONE_FRAME    // frame 2
+
+        "   cmp r7, r3\n"                   // inputIndex - maxInIdx
+        "   bcc .Y4L01\n"
+        ".Y4L02:\n"
+
+        "   bic r6, r6, #0xC0000000\n"             // phaseFraction & ...
+        // save modified values
+        "   ldr r0, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
+        "   str r6, [r0]\n"                         // phaseFraction
+        "   ldr r0, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
+        "   str r7, [r0]\n"                         // inputIndex
+        "   ldr r0, [sp, #" MO_PARAM5 " + 4]\n"     // out
+        "   sub r8, r0\n"                           // curOut - out
+        "   asr r8, #2\n"                           // new outputIndex
+        "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
+        "   str r8, [r0]\n"                         // save outputIndex
+
+        "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
+    );
+}
+
+/*******************************************************************
+*
+*   AsmStereo16Loop
+*   asm optimized stereo loop version; one loop is 2 frames
+*   Input:
+*       in : pointer on input samples
+*       maxOutPt : pointer on first not filled
+*       maxInIdx : index on first not used
+*       outputIndex : pointer on current output index
+*       out : pointer on output buffer
+*       inputIndex : pointer on current input index
+*       vl, vr : left and right gain
+*       phaseFraction : pointer on current phase fraction
+*       phaseIncrement
+*   Ouput:
+*       outputIndex :
+*       out : updated buffer
+*       inputIndex : index of next to use
+*       phaseFraction : phase fraction for next interpolation
+*
+*******************************************************************/
+void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+            uint32_t &phaseFraction, uint32_t phaseIncrement)
+{
+#define ST_PARAM5    "40"     // offset of parameter 5 (outputIndex)
+    asm(
+        "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
+        // get parameters
+        "   ldr r6, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
+        "   ldr r6, [r6]\n"                         // phaseFraction
+        "   ldr r7, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
+        "   ldr r7, [r7]\n"                         // inputIndex
+        "   ldr r8, [sp, #" ST_PARAM5 " + 4]\n"     // out
+        "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
+        "   ldr r0, [r0]\n"                         // outputIndex
+        "   add r8, r0, asl #2\n"                   // curOut
+        "   ldr r9, [sp, #" ST_PARAM5 " + 24]\n"    // phaseIncrement
+        "   ldr r10, [sp, #" ST_PARAM5 " + 12]\n"   // vl
+        "   ldr r11, [sp, #" ST_PARAM5 " + 16]\n"   // vr
+
+        // r0 pin, x0, Samp
+
+        // r1 in
+        // r2 maxOutPt
+        // r3 maxInIdx
+
+        // r4 x1, i1, i3, out1
+        // r5 out0
+
+        // r6 frac
+        // r7 inputIndex
+        // r8 curOut
+
+        // r9 inc
+        // r10 vl
+        // r11 vr
+
+        // r12 temporary
+        // r13 sp
+        // r14
+
+        ".Y5L01:\n"
+        "   cmp r8, r2\n"                   // curOut - maxCurOut
+        "   bcs .Y5L02\n"
+
+#define ST_ONE_FRAME \
+    "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
+\
+    "   add r0, r1, r7, asl #2\n"       /* in + 2*inputIndex */\
+\
+    "   ldrsh r4, [r0]\n"               /* in[2*inputIndex] */\
+    "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
+    "   ldrsh r12, [r0, #-4]\n"         /* in[2*inputIndex-2] */\
+    "   sub r4, r4, r12\n"              /* in[2*InputIndex] - in[2*InputIndex-2] */\
+    "   mov r4, r4, lsl #2\n"           /* <<2 */\
+    "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
+    "   add r12, r12, r4\n"             /* x0 - (..) */\
+    "   mla r5, r12, r10, r5\n"         /* vl*interp + out[] */\
+    "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
+    "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
+\
+    "   ldrsh r12, [r0, #+2]\n"         /* in[2*inputIndex+1] */\
+    "   ldrsh r0, [r0, #-2]\n"          /* in[2*inputIndex-1] */\
+    "   sub r12, r12, r0\n"             /* in[2*InputIndex] - in[2*InputIndex-2] */\
+    "   mov r12, r12, lsl #2\n"         /* <<2 */\
+    "   smulwt r12, r12, r6\n"          /* (x1-x0)*.. */\
+    "   add r12, r0, r12\n"             /* x0 - (..) */\
+    "   mla r4, r12, r11, r4\n"         /* vr*interp + out[] */\
+    "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */\
+\
+    "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
+    "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */
+
+    ST_ONE_FRAME    // frame 1
+    ST_ONE_FRAME    // frame 1
+
+        "   cmp r7, r3\n"                       // inputIndex - maxInIdx
+        "   bcc .Y5L01\n"
+        ".Y5L02:\n"
+
+        "   bic r6, r6, #0xC0000000\n"              // phaseFraction & ...
+        // save modified values
+        "   ldr r0, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
+        "   str r6, [r0]\n"                         // phaseFraction
+        "   ldr r0, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
+        "   str r7, [r0]\n"                         // inputIndex
+        "   ldr r0, [sp, #" ST_PARAM5 " + 4]\n"     // out
+        "   sub r8, r0\n"                           // curOut - out
+        "   asr r8, #2\n"                           // new outputIndex
+        "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
+        "   str r8, [r0]\n"                         // save outputIndex
+
+        "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n"
+    );
+}
+
+#endif  // ASM_ARM_RESAMP1
+
+
+// ----------------------------------------------------------------------------
+}
+; // namespace android
+
diff --git a/libs/audioflinger/AudioResampler.h b/libs/audioflinger/AudioResampler.h
new file mode 100644
index 0000000..39656c0
--- /dev/null
+++ b/libs/audioflinger/AudioResampler.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_AUDIO_RESAMPLER_H
+#define ANDROID_AUDIO_RESAMPLER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "AudioBufferProvider.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResampler {
+public:
+    // Determines quality of SRC.
+    //  LOW_QUALITY: linear interpolator (1st order)
+    //  MED_QUALITY: cubic interpolator (3rd order)
+    //  HIGH_QUALITY: fixed multi-tap FIR (e.g. 48KHz->44.1KHz)
+    // NOTE: high quality SRC will only be supported for
+    // certain fixed rate conversions. Sample rate cannot be
+    // changed dynamically. 
+    enum src_quality {
+        DEFAULT=0,
+        LOW_QUALITY=1,
+        MED_QUALITY=2,
+        HIGH_QUALITY=3
+    };
+
+    static AudioResampler* create(int bitDepth, int inChannelCount,
+            int32_t sampleRate, int quality=DEFAULT);
+
+    virtual ~AudioResampler();
+
+    virtual void init() = 0;
+    virtual void setSampleRate(int32_t inSampleRate);
+    virtual void setVolume(int16_t left, int16_t right);
+
+    virtual void resample(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider) = 0;
+
+protected:
+    // number of bits for phase fraction - 30 bits allows nearly 2x downsampling
+    static const int kNumPhaseBits = 30;
+
+    // phase mask for fraction
+    static const uint32_t kPhaseMask = (1LU<<kNumPhaseBits)-1;
+
+    // multiplier to calculate fixed point phase increment
+    static const double kPhaseMultiplier = 1L << kNumPhaseBits;
+
+    enum format {MONO_16_BIT, STEREO_16_BIT};
+    AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate);
+
+    // prevent copying
+    AudioResampler(const AudioResampler&);
+    AudioResampler& operator=(const AudioResampler&);
+
+    int32_t mBitDepth;
+    int32_t mChannelCount;
+    int32_t mSampleRate;
+    int32_t mInSampleRate;
+    AudioBufferProvider::Buffer mBuffer;
+    union {
+    	int16_t mVolume[2];
+    	uint32_t mVolumeRL;
+    };
+    int16_t mTargetVolume[2];
+    format mFormat;
+    size_t mInputIndex;
+    int32_t mPhaseIncrement;
+    uint32_t mPhaseFraction;
+};
+
+// ----------------------------------------------------------------------------
+}
+; // namespace android
+
+#endif // ANDROID_AUDIO_RESAMPLER_H
diff --git a/libs/audioflinger/AudioResamplerCubic.cpp b/libs/audioflinger/AudioResamplerCubic.cpp
new file mode 100644
index 0000000..1d247bd
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerCubic.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2007 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 <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+#include "AudioResamplerCubic.h"
+
+#define LOG_TAG "AudioSRC"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+void AudioResamplerCubic::init() {
+    memset(&left, 0, sizeof(state));
+    memset(&right, 0, sizeof(state));
+}
+
+void AudioResamplerCubic::resample(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider) {
+
+    // should never happen, but we overflow if it does
+    // LOG_ASSERT(outFrameCount < 32767);
+
+    // select the appropriate resampler
+    switch (mChannelCount) {
+    case 1:
+        resampleMono16(out, outFrameCount, provider);
+        break;
+    case 2:
+        resampleStereo16(out, outFrameCount, provider);
+        break;
+    }
+}
+
+void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider) {
+
+    int32_t vl = mVolume[0];
+    int32_t vr = mVolume[1];
+
+    size_t inputIndex = mInputIndex;
+    uint32_t phaseFraction = mPhaseFraction;
+    uint32_t phaseIncrement = mPhaseIncrement;
+    size_t outputIndex = 0;
+    size_t outputSampleCount = outFrameCount * 2;
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+
+    // fetch first buffer
+    if (mBuffer.frameCount == 0) {
+        mBuffer.frameCount = inFrameCount;
+        provider->getNextBuffer(&mBuffer);
+        if (mBuffer.raw == NULL)
+            return;
+        // LOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
+    }
+    int16_t *in = mBuffer.i16;
+
+    while (outputIndex < outputSampleCount) {
+        int32_t sample;
+        int32_t x;
+
+        // calculate output sample
+        x = phaseFraction >> kPreInterpShift;
+        out[outputIndex++] += vl * interp(&left, x);
+        out[outputIndex++] += vr * interp(&right, x);
+        // out[outputIndex++] += vr * in[inputIndex*2];
+
+        // increment phase
+        phaseFraction += phaseIncrement;
+        uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits);
+        phaseFraction &= kPhaseMask;
+
+        // time to fetch another sample
+        while (indexIncrement--) {
+
+            inputIndex++;
+            if (inputIndex == mBuffer.frameCount) {
+                inputIndex = 0;
+                provider->releaseBuffer(&mBuffer);
+                mBuffer.frameCount = inFrameCount;
+                provider->getNextBuffer(&mBuffer);
+                if (mBuffer.raw == NULL)
+                    goto save_state;  // ugly, but efficient
+                in = mBuffer.i16;
+                // LOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+            }
+
+            // advance sample state
+            advance(&left, in[inputIndex*2]);
+            advance(&right, in[inputIndex*2+1]);
+        }
+    }
+
+save_state:
+    // LOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction);
+    mInputIndex = inputIndex;
+    mPhaseFraction = phaseFraction;
+}
+
+void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider) {
+
+    int32_t vl = mVolume[0];
+    int32_t vr = mVolume[1];
+
+    size_t inputIndex = mInputIndex;
+    uint32_t phaseFraction = mPhaseFraction;
+    uint32_t phaseIncrement = mPhaseIncrement;
+    size_t outputIndex = 0;
+    size_t outputSampleCount = outFrameCount * 2;
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+
+    // fetch first buffer
+    if (mBuffer.frameCount == 0) {
+        mBuffer.frameCount = inFrameCount;
+        provider->getNextBuffer(&mBuffer);
+        if (mBuffer.raw == NULL)
+            return;
+        // LOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+    }
+    int16_t *in = mBuffer.i16;
+
+    while (outputIndex < outputSampleCount) {
+        int32_t sample;
+        int32_t x;
+
+        // calculate output sample
+        x = phaseFraction >> kPreInterpShift;
+        sample = interp(&left, x);
+        out[outputIndex++] += vl * sample;
+        out[outputIndex++] += vr * sample;
+
+        // increment phase
+        phaseFraction += phaseIncrement;
+        uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits);
+        phaseFraction &= kPhaseMask;
+
+        // time to fetch another sample
+        while (indexIncrement--) {
+
+            inputIndex++;
+            if (inputIndex == mBuffer.frameCount) {
+                inputIndex = 0;
+                provider->releaseBuffer(&mBuffer);
+                mBuffer.frameCount = inFrameCount;
+                provider->getNextBuffer(&mBuffer);
+                if (mBuffer.raw == NULL)
+                    goto save_state;  // ugly, but efficient
+                // LOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
+                in = mBuffer.i16;
+            }
+
+            // advance sample state
+            advance(&left, in[inputIndex]);
+        }
+    }
+
+save_state:
+    // LOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction);
+    mInputIndex = inputIndex;
+    mPhaseFraction = phaseFraction;
+}
+
+// ----------------------------------------------------------------------------
+}
+; // namespace android
+
diff --git a/libs/audioflinger/AudioResamplerCubic.h b/libs/audioflinger/AudioResamplerCubic.h
new file mode 100644
index 0000000..b72b62a
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerCubic.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_AUDIO_RESAMPLER_CUBIC_H
+#define ANDROID_AUDIO_RESAMPLER_CUBIC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResamplerCubic : public AudioResampler {
+public:
+    AudioResamplerCubic(int bitDepth, int inChannelCount, int32_t sampleRate) :
+        AudioResampler(bitDepth, inChannelCount, sampleRate) {
+    }
+    virtual void resample(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+private:
+    // number of bits used in interpolation multiply - 14 bits avoids overflow
+    static const int kNumInterpBits = 14;
+
+    // bits to shift the phase fraction down to avoid overflow
+    static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;
+    typedef struct {
+        int32_t a, b, c, y0, y1, y2, y3;
+    } state;
+    void init();
+    void resampleMono16(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+    void resampleStereo16(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+    static inline int32_t interp(state* p, int32_t x) {
+        return (((((p->a * x >> 14) + p->b) * x >> 14) + p->c) * x >> 14) + p->y1;
+    }
+    static inline void advance(state* p, int16_t in) {
+        p->y0 = p->y1;
+        p->y1 = p->y2;
+        p->y2 = p->y3;
+        p->y3 = in;
+        p->a = (3 * (p->y1 - p->y2) - p->y0 + p->y3) >> 1;            
+        p->b = (p->y2 << 1) + p->y0 - (((5 * p->y1 + p->y3)) >> 1);
+        p->c = (p->y2 - p->y0) >> 1;
+    }
+    state left, right;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_CUBIC_H*/
diff --git a/libs/audioflinger/AudioResamplerSinc.cpp b/libs/audioflinger/AudioResamplerSinc.cpp
new file mode 100644
index 0000000..9e5e254
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerSinc.cpp
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2007 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 <string.h>
+#include "AudioResamplerSinc.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+
+/*
+ * These coeficients are computed with the "fir" utility found in
+ * tools/resampler_tools
+ * TODO: A good optimization would be to transpose this matrix, to take
+ * better advantage of the data-cache.
+ */
+const int32_t AudioResamplerSinc::mFirCoefsUp[] = {
+        0x7fffffff, 0x7f15d078, 0x7c5e0da6, 0x77ecd867, 0x71e2e251, 0x6a6c304a, 0x61be7269, 0x58170412, 0x4db8ab05, 0x42e92ea6, 0x37eee214, 0x2d0e3bb1, 0x22879366, 0x18951e95, 0x0f693d0d, 0x072d2621,
+        0x00000000, 0xf9f66655, 0xf51a5fd7, 0xf16bbd84, 0xeee0d9ac, 0xed67a922, 0xece70de6, 0xed405897, 0xee50e505, 0xeff3be30, 0xf203370f, 0xf45a6741, 0xf6d67d53, 0xf957db66, 0xfbc2f647, 0xfe00f2b9,
+        0x00000000, 0x01b37218, 0x0313a0c6, 0x041d930d, 0x04d28057, 0x053731b0, 0x05534dff, 0x05309bfd, 0x04da440d, 0x045c1aee, 0x03c1fcdd, 0x03173ef5, 0x02663ae8, 0x01b7f736, 0x0113ec79, 0x007fe6a9,
+        0x00000000, 0xff96b229, 0xff44f99f, 0xff0a86be, 0xfee5f803, 0xfed518fd, 0xfed521fd, 0xfee2f4fd, 0xfefb54f8, 0xff1b159b, 0xff3f4203, 0xff6539e0, 0xff8ac502, 0xffae1ddd, 0xffcdf3f9, 0xffe96798,
+        0x00000000, 0x00119de6, 0x001e6b7e, 0x0026cb7a, 0x002b4830, 0x002c83d6, 0x002b2a82, 0x0027e67a, 0x002356f9, 0x001e098e, 0x001875e4, 0x0012fbbe, 0x000de2d1, 0x00095c10, 0x00058414, 0x00026636,
+        0x00000000, 0xfffe44a9, 0xfffd206d, 0xfffc7b7f, 0xfffc3c8f, 0xfffc4ac2, 0xfffc8f2b, 0xfffcf5c4, 0xfffd6df3, 0xfffdeab2, 0xfffe6275, 0xfffececf, 0xffff2c07, 0xffff788c, 0xffffb471, 0xffffe0f2,
+        0x00000000, 0x000013e6, 0x00001f03, 0x00002396, 0x00002399, 0x000020b6, 0x00001c3c, 0x00001722, 0x00001216, 0x00000d81, 0x0000099c, 0x0000067c, 0x00000419, 0x0000025f, 0x00000131, 0x00000070,
+        0x00000000, 0xffffffc7, 0xffffffb3, 0xffffffb3, 0xffffffbe, 0xffffffcd, 0xffffffdb, 0xffffffe7, 0xfffffff0, 0xfffffff7, 0xfffffffb, 0xfffffffe, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+        0x00000000 // this one is needed for lerping the last coefficient
+};
+
+/*
+ * These coefficients are optimized for 48KHz -> 44.1KHz (stop-band at 22.050KHz)
+ * It's possible to use the above coefficient for any down-sampling
+ * at the expense of a slower processing loop (we can interpolate
+ * these coefficient from the above by "Stretching" them in time).
+ */
+const int32_t AudioResamplerSinc::mFirCoefsDown[] = {
+        0x7fffffff, 0x7f55e46d, 0x7d5b4c60, 0x7a1b4b98, 0x75a7fb14, 0x7019f0bd, 0x698f875a, 0x622bfd59, 0x5a167256, 0x5178cc54, 0x487e8e6c, 0x3f53aae8, 0x36235ad4, 0x2d17047b, 0x245539ab, 0x1c00d540,
+        0x14383e57, 0x0d14d5ca, 0x06aa910b, 0x0107c38b, 0xfc351654, 0xf835abae, 0xf5076b45, 0xf2a37202, 0xf0fe9faa, 0xf00a3bbd, 0xefb4aa81, 0xefea2b05, 0xf0959716, 0xf1a11e83, 0xf2f6f7a0, 0xf481fff4,
+        0xf62e48ce, 0xf7e98ca5, 0xf9a38b4c, 0xfb4e4bfa, 0xfcde456f, 0xfe4a6d30, 0xff8c2fdf, 0x009f5555, 0x0181d393, 0x0233940f, 0x02b62f06, 0x030ca07d, 0x033afa62, 0x03461725, 0x03334f83, 0x030835fa,
+        0x02ca59cc, 0x027f12d1, 0x022b570d, 0x01d39a49, 0x017bb78f, 0x0126e414, 0x00d7aaaf, 0x008feec7, 0x0050f584, 0x001b73e3, 0xffefa063, 0xffcd46ed, 0xffb3ddcd, 0xffa29aaa, 0xff988691, 0xff949066,
+        0xff959d24, 0xff9a959e, 0xffa27195, 0xffac4011, 0xffb72d2b, 0xffc28569, 0xffcdb706, 0xffd85171, 0xffe20364, 0xffea97e9, 0xfff1f2b2, 0xfff80c06, 0xfffcec92, 0x0000a955, 0x00035fd8, 0x000532cf,
+        0x00064735, 0x0006c1f9, 0x0006c62d, 0x000673ba, 0x0005e68f, 0x00053630, 0x000475a3, 0x0003b397, 0x0002fac1, 0x00025257, 0x0001be9e, 0x0001417a, 0x0000dafd, 0x000089eb, 0x00004c28, 0x00001f1d,
+        0x00000000, 0xffffec10, 0xffffe0be, 0xffffdbc5, 0xffffdb39, 0xffffdd8b, 0xffffe182, 0xffffe638, 0xffffeb0a, 0xffffef8f, 0xfffff38b, 0xfffff6e3, 0xfffff993, 0xfffffba6, 0xfffffd30, 0xfffffe4a,
+        0xffffff09, 0xffffff85, 0xffffffd1, 0xfffffffb, 0x0000000f, 0x00000016, 0x00000015, 0x00000012, 0x0000000d, 0x00000009, 0x00000006, 0x00000003, 0x00000002, 0x00000001, 0x00000000, 0x00000000,
+        0x00000000 // this one is needed for lerping the last coefficient
+};
+
+// ----------------------------------------------------------------------------
+
+static inline
+int32_t mulRL(int left, int32_t in, uint32_t vRL)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    if (left) {
+        asm( "smultb %[out], %[in], %[vRL] \n"
+             : [out]"=r"(out)
+             : [in]"%r"(in), [vRL]"r"(vRL)
+             : );
+    } else {
+        asm( "smultt %[out], %[in], %[vRL] \n"
+             : [out]"=r"(out)
+             : [in]"%r"(in), [vRL]"r"(vRL)
+             : );
+    }
+    return out;
+#else
+    if (left) {
+        return int16_t(in>>16) * int16_t(vRL&0xFFFF);
+    } else {
+        return int16_t(in>>16) * int16_t(vRL>>16);
+    }
+#endif
+}
+
+static inline
+int32_t mulAdd(int16_t in, int32_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    asm( "smlawb %[out], %[v], %[in], %[a] \n"
+         : [out]"=r"(out)
+         : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
+         : );
+    return out;
+#else
+    return a + in * (v>>16);
+    // improved precision
+    // return a + in * (v>>16) + ((in * (v & 0xffff)) >> 16);
+#endif
+}
+
+static inline
+int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    if (left) {
+        asm( "smlawb %[out], %[v], %[inRL], %[a] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
+             : );
+    } else {
+        asm( "smlawt %[out], %[v], %[inRL], %[a] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
+             : );
+    }
+    return out;
+#else
+    if (left) {
+        return a + (int16_t(inRL&0xFFFF) * (v>>16));
+        //improved precision
+        // return a + (int16_t(inRL&0xFFFF) * (v>>16)) + ((int16_t(inRL&0xFFFF) * (v & 0xffff)) >> 16);
+    } else {
+        return a + (int16_t(inRL>>16) * (v>>16));
+    }
+#endif
+}
+
+// ----------------------------------------------------------------------------
+
+AudioResamplerSinc::AudioResamplerSinc(int bitDepth,
+        int inChannelCount, int32_t sampleRate)
+    : AudioResampler(bitDepth, inChannelCount, sampleRate),
+    mState(0)
+{
+    /*
+     * Layout of the state buffer for 32 tap:
+     *
+     * "present" sample            beginning of 2nd buffer
+     *                 v                v
+     *  0              01               2              23              3
+     *  0              F0               0              F0              F
+     * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn]
+     *                 ^               ^ head
+     *
+     * p = past samples, convoluted with the (p)ositive side of sinc()
+     * n = future samples, convoluted with the (n)egative side of sinc()
+     * r = extra space for implementing the ring buffer
+     *
+     */
+
+    const size_t numCoefs = 2*halfNumCoefs;
+    const size_t stateSize = numCoefs * inChannelCount * 2;
+    mState = new int16_t[stateSize];
+    memset(mState, 0, sizeof(int16_t)*stateSize);
+    mImpulse = mState + (halfNumCoefs-1)*inChannelCount;
+    mRingFull = mImpulse + (numCoefs+1)*inChannelCount;
+}
+
+AudioResamplerSinc::~AudioResamplerSinc()
+{
+    delete [] mState;
+}
+
+void AudioResamplerSinc::init() {
+}
+
+void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider)
+{
+    mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
+
+    // select the appropriate resampler
+    switch (mChannelCount) {
+    case 1:
+        resample<1>(out, outFrameCount, provider);
+        break;
+    case 2:
+        resample<2>(out, outFrameCount, provider);
+        break;
+    }
+}
+
+
+template<int CHANNELS>
+void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider)
+{
+    int16_t* impulse = mImpulse;
+    uint32_t vRL = mVolumeRL;
+    size_t inputIndex = mInputIndex;
+    uint32_t phaseFraction = mPhaseFraction;
+    uint32_t phaseIncrement = mPhaseIncrement;
+    size_t outputIndex = 0;
+    size_t outputSampleCount = outFrameCount * 2;
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+
+    AudioBufferProvider::Buffer& buffer(mBuffer);
+    while (outputIndex < outputSampleCount) {
+        // buffer is empty, fetch a new one
+        while (buffer.frameCount == 0) {
+            buffer.frameCount = inFrameCount;
+            provider->getNextBuffer(&buffer);
+            if (buffer.raw == NULL) {
+                goto resample_exit;
+            }
+            const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+            if (phaseIndex == 1) {
+                // read one frame
+                read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+            } else if (phaseIndex == 2) {
+                // read 2 frames
+                read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+                inputIndex++;
+                if (inputIndex >= mBuffer.frameCount) {
+                    inputIndex -= mBuffer.frameCount;
+                    provider->releaseBuffer(&buffer);
+                } else {
+                    read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+                }
+           }
+        }
+        int16_t *in = buffer.i16;
+        const size_t frameCount = buffer.frameCount;
+
+        // Always read-in the first samples from the input buffer
+        int16_t* head = impulse + halfNumCoefs*CHANNELS;
+        head[0] = in[inputIndex*CHANNELS + 0];
+        if (CHANNELS == 2)
+            head[1] = in[inputIndex*CHANNELS + 1];
+
+        // handle boundary case
+        int32_t l, r;
+        while (outputIndex < outputSampleCount) {
+            filterCoefficient<CHANNELS>(l, r, phaseFraction, impulse);
+            out[outputIndex++] += 2 * mulRL(1, l, vRL);
+            out[outputIndex++] += 2 * mulRL(0, r, vRL);
+
+            phaseFraction += phaseIncrement;
+            const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+            if (phaseIndex == 1) {
+                inputIndex++;
+                if (inputIndex >= frameCount)
+                    break;  // need a new buffer
+                read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+            } else if(phaseIndex == 2) {    // maximum value
+                inputIndex++;
+                if (inputIndex >= frameCount)
+                    break;  // 0 frame available, 2 frames needed
+                // read first frame
+                read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+                inputIndex++;
+                if (inputIndex >= frameCount)
+                    break;  // 0 frame available, 1 frame needed
+                // read second frame
+                read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+            }
+        }
+
+        // if done with buffer, save samples
+        if (inputIndex >= frameCount) {
+            inputIndex -= frameCount;
+            provider->releaseBuffer(&buffer);
+        }
+    }
+
+resample_exit:
+    mImpulse = impulse;
+    mInputIndex = inputIndex;
+    mPhaseFraction = phaseFraction;
+}
+
+template<int CHANNELS>
+/***
+* read()
+*
+* This function reads only one frame from input buffer and writes it in
+* state buffer
+*
+**/
+void AudioResamplerSinc::read(
+        int16_t*& impulse, uint32_t& phaseFraction,
+        int16_t const* in, size_t inputIndex)
+{
+    const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+    impulse += CHANNELS;
+    phaseFraction -= 1LU<<kNumPhaseBits;
+    if (impulse >= mRingFull) {
+        const size_t stateSize = (halfNumCoefs*2)*CHANNELS;
+        memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize);
+        impulse -= stateSize;
+    }
+    int16_t* head = impulse + halfNumCoefs*CHANNELS;
+    head[0] = in[inputIndex*CHANNELS + 0];
+    if (CHANNELS == 2)
+        head[1] = in[inputIndex*CHANNELS + 1];
+}
+
+template<int CHANNELS>
+void AudioResamplerSinc::filterCoefficient(
+        int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples)
+{
+    // compute the index of the coefficient on the positive side and
+    // negative side
+    uint32_t indexP = (phase & cMask) >> cShift;
+    uint16_t lerpP  = (phase & pMask) >> pShift;
+    uint32_t indexN = (-phase & cMask) >> cShift;
+    uint16_t lerpN  = (-phase & pMask) >> pShift;
+    if ((indexP == 0) && (lerpP == 0)) {
+        indexN = cMask >> cShift;
+        lerpN = pMask >> pShift;
+    }
+
+    l = 0;
+    r = 0;
+    int32_t const* coefs = mFirCoefs;
+    int16_t const *sP = samples;
+    int16_t const *sN = samples+CHANNELS;
+    for (unsigned int i=0 ; i<halfNumCoefs/4 ; i++) {
+        interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+        interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+        sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+        interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+        interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+        sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+        interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+        interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+        sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+        interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+        interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+        sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+    }
+}
+
+template<int CHANNELS>
+void AudioResamplerSinc::interpolate(
+        int32_t& l, int32_t& r,
+        int32_t const* coefs, int16_t lerp, int16_t const* samples)
+{
+    int32_t c0 = coefs[0];
+    int32_t c1 = coefs[1];
+    int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0);
+    if (CHANNELS == 2) {
+        uint32_t rl = *reinterpret_cast<uint32_t const*>(samples);
+        l = mulAddRL(1, rl, sinc, l);
+        r = mulAddRL(0, rl, sinc, r);
+    } else {
+        r = l = mulAdd(samples[0], sinc, l);
+    }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/audioflinger/AudioResamplerSinc.h b/libs/audioflinger/AudioResamplerSinc.h
new file mode 100644
index 0000000..e6cb90b
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerSinc.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_AUDIO_RESAMPLER_SINC_H
+#define ANDROID_AUDIO_RESAMPLER_SINC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class AudioResamplerSinc : public AudioResampler {
+public:
+    AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate);
+
+    ~AudioResamplerSinc();
+
+    virtual void resample(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+private:
+    void init();
+
+    template<int CHANNELS>
+    void resample(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+
+    template<int CHANNELS>
+    inline void filterCoefficient(
+            int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples);
+
+    template<int CHANNELS>
+    inline void interpolate(
+            int32_t& l, int32_t& r,
+            int32_t const* coefs, int16_t lerp, int16_t const* samples);
+
+    template<int CHANNELS>
+    inline void read(int16_t*& impulse, uint32_t& phaseFraction,
+            int16_t const* in, size_t inputIndex);
+
+    int16_t *mState;
+    int16_t *mImpulse;
+    int16_t *mRingFull;
+
+    int32_t const * mFirCoefs;
+    static const int32_t mFirCoefsDown[];
+    static const int32_t mFirCoefsUp[];
+
+    // ----------------------------------------------------------------------------
+    static const int32_t RESAMPLE_FIR_NUM_COEF       = 8;
+    static const int32_t RESAMPLE_FIR_LERP_INT_BITS  = 4;
+
+    // we have 16 coefs samples per zero-crossing
+    static const int coefsBits = RESAMPLE_FIR_LERP_INT_BITS;        // 4
+    static const int cShift = kNumPhaseBits - coefsBits;            // 26
+    static const uint32_t cMask  = ((1<<coefsBits)-1) << cShift;    // 0xf<<26 = 3c00 0000
+
+    // and we use 15 bits to interpolate between these samples
+    // this cannot change because the mul below rely on it.
+    static const int pLerpBits = 15;
+    static const int pShift = kNumPhaseBits - coefsBits - pLerpBits;    // 11
+    static const uint32_t pMask  = ((1<<pLerpBits)-1) << pShift;    // 0x7fff << 11
+
+    // number of zero-crossing on each side
+    static const unsigned int halfNumCoefs = RESAMPLE_FIR_NUM_COEF;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_SINC_H*/
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
new file mode 100644
index 0000000..496e271
--- /dev/null
+++ b/libs/surfaceflinger/Android.mk
@@ -0,0 +1,49 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    clz.cpp.arm \
+    DisplayHardware/DisplayHardware.cpp \
+    DisplayHardware/DisplayHardwareBase.cpp \
+    GPUHardware/GPUHardware.cpp \
+    BootAnimation.cpp \
+    BlurFilter.cpp.arm \
+    CPUGauge.cpp \
+    Layer.cpp \
+    LayerBase.cpp \
+    LayerBuffer.cpp \
+    LayerBlur.cpp \
+    LayerBitmap.cpp \
+    LayerDim.cpp \
+    LayerOrientationAnim.cpp \
+    OrientationAnimation.cpp \
+    SurfaceFlinger.cpp \
+    Tokenizer.cpp \
+    Transform.cpp \
+    VRamHeap.cpp
+
+
+# need "-lrt" on Linux simulator to pick up clock_gettime
+ifeq ($(TARGET_SIMULATOR),true)
+	ifeq ($(HOST_OS),linux)
+		LOCAL_LDLIBS += -lrt
+	endif
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+	libhardware \
+	libutils \
+	libcutils \
+	libui \
+	libcorecg \
+	libsgl \
+	libpixelflinger \
+	libEGL \
+	libGLESv1_CM
+
+LOCAL_C_INCLUDES := \
+	$(call include-path-for, corecg graphics)
+
+LOCAL_MODULE:= libsurfaceflinger
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/surfaceflinger/Barrier.h b/libs/surfaceflinger/Barrier.h
new file mode 100644
index 0000000..e2bcf6a
--- /dev/null
+++ b/libs/surfaceflinger/Barrier.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_BARRIER_H
+#define ANDROID_BARRIER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class Barrier
+{
+public:
+    inline Barrier() : state(CLOSED) { }
+    inline ~Barrier() { }
+    void open() {
+        // gcc memory barrier, this makes sure all memory writes
+        // have been issued by gcc. On an SMP system we'd need a real
+        // h/w barrier.
+        asm volatile ("":::"memory");
+        Mutex::Autolock _l(lock);
+        state = OPENED;
+        cv.broadcast();
+    }
+    void close() {
+        Mutex::Autolock _l(lock);
+        state = CLOSED;
+    }
+    void wait() const {
+        Mutex::Autolock _l(lock);
+        while (state == CLOSED) {
+            cv.wait(lock);
+        }
+    }
+private:
+    enum { OPENED, CLOSED };
+    mutable     Mutex       lock;
+    mutable     Condition   cv;
+    volatile    int         state;
+};
+
+}; // namespace android
+
+#endif // ANDROID_BARRIER_H
diff --git a/libs/surfaceflinger/BlurFilter.cpp b/libs/surfaceflinger/BlurFilter.cpp
new file mode 100644
index 0000000..5dc0ba0
--- /dev/null
+++ b/libs/surfaceflinger/BlurFilter.cpp
@@ -0,0 +1,326 @@
+/* 
+**
+** Copyright 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <utils/Errors.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "clz.h"
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+inline uint32_t BLUR_RGBA_TO_HOST(uint32_t v) {
+    return v;
+}
+inline uint32_t BLUR_HOST_TO_RGBA(uint32_t v) {
+    return v;
+}
+#else
+inline uint32_t BLUR_RGBA_TO_HOST(uint32_t v) {
+    return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
+}
+inline uint32_t BLUR_HOST_TO_RGBA(uint32_t v) {
+    return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
+}
+#endif
+
+const int BLUR_DITHER_BITS = 6;  // dither weights stored on 6 bits
+const int BLUR_DITHER_ORDER_SHIFT= 3;
+const int BLUR_DITHER_ORDER      = (1<<BLUR_DITHER_ORDER_SHIFT);
+const int BLUR_DITHER_SIZE       = BLUR_DITHER_ORDER * BLUR_DITHER_ORDER;
+const int BLUR_DITHER_MASK       = BLUR_DITHER_ORDER-1;
+
+static const uint8_t gDitherMatrix[BLUR_DITHER_SIZE] = {
+     0, 32,  8, 40,  2, 34, 10, 42,
+    48, 16, 56, 24, 50, 18, 58, 26,
+    12, 44,  4, 36, 14, 46,  6, 38,
+    60, 28, 52, 20, 62, 30, 54, 22,
+     3, 35, 11, 43,  1, 33,  9, 41,
+    51, 19, 59, 27, 49, 17, 57, 25,
+    15, 47,  7, 39, 13, 45,  5, 37,
+    63, 31, 55, 23, 61, 29, 53, 21
+};
+
+
+template <int FACTOR = 0>
+struct BlurColor565
+{
+    typedef uint16_t type;
+    int r, g, b;    
+    inline BlurColor565() { }
+    inline BlurColor565(uint16_t v) {
+        r = v >> 11;
+        g = (v >> 5) & 0x3E;
+        b = v & 0x1F;
+    }
+    inline void clear() { r=g=b=0; }
+    inline uint16_t to(int shift, int last, int dither) const {
+        int R = r;
+        int G = g;
+        int B = b;
+        if  (UNLIKELY(last)) {
+            if (FACTOR>0) {
+                int L = (R+G+B)>>1;
+                R += (((L>>1) - R) * FACTOR) >> 8;
+                G += (((L   ) - G) * FACTOR) >> 8;
+                B += (((L>>1) - B) * FACTOR) >> 8;
+            }
+            R += (dither << shift) >> BLUR_DITHER_BITS;
+            G += (dither << shift) >> BLUR_DITHER_BITS;
+            B += (dither << shift) >> BLUR_DITHER_BITS;
+        }
+        R >>= shift;
+        G >>= shift;
+        B >>= shift;
+        return (R<<11) | (G<<5) | B;
+    }    
+    inline BlurColor565& operator += (const BlurColor565& rhs) {
+        r += rhs.r;
+        g += rhs.g;
+        b += rhs.b;
+        return *this;
+    }
+    inline BlurColor565& operator -= (const BlurColor565& rhs) {
+        r -= rhs.r;
+        g -= rhs.g;
+        b -= rhs.b;
+        return *this;
+    }
+};
+
+struct BlurGray565
+{
+    typedef uint16_t type;
+    int l;    
+    inline BlurGray565() { }
+    inline BlurGray565(uint16_t v) {
+        int r = v >> 11;
+        int g = (v >> 5) & 0x3F;
+        int b = v & 0x1F;
+        l = (r + g + b + 1)>>1;
+    }
+    inline void clear() { l=0; }
+    inline uint16_t to(int shift, int last, int dither) const {
+        int L = l;
+        if  (UNLIKELY(last)) {
+            L += (dither << shift) >> BLUR_DITHER_BITS;
+        }
+        L >>= shift;
+        return ((L>>1)<<11) | (L<<5) | (L>>1);
+    }
+    inline BlurGray565& operator += (const BlurGray565& rhs) {
+        l += rhs.l;
+        return *this;
+    }
+    inline BlurGray565& operator -= (const BlurGray565& rhs) {
+        l -= rhs.l;
+        return *this;
+    }
+};
+
+struct BlurGray8888
+{
+    typedef uint32_t type;
+    int l, a;    
+    inline BlurGray8888() { }
+    inline BlurGray8888(uint32_t v) {
+        v = BLUR_RGBA_TO_HOST(v);
+        int r = v & 0xFF;
+        int g = (v >>  8) & 0xFF;
+        int b = (v >> 16) & 0xFF;
+        a = v >> 24;
+        l = r + g + g + b;
+    }    
+    inline void clear() { l=a=0; }
+    inline uint32_t to(int shift, int last, int dither) const {
+        int L = l;
+        int A = a;
+        if  (UNLIKELY(last)) {
+            L += (dither << (shift+2)) >> BLUR_DITHER_BITS;
+            A += (dither << shift) >> BLUR_DITHER_BITS;
+        }
+        L >>= (shift+2);
+        A >>= shift;
+        return BLUR_HOST_TO_RGBA((A<<24) | (L<<16) | (L<<8) | L);
+    }
+    inline BlurGray8888& operator += (const BlurGray8888& rhs) {
+        l += rhs.l;
+        a += rhs.a;
+        return *this;
+    }
+    inline BlurGray8888& operator -= (const BlurGray8888& rhs) {
+        l -= rhs.l;
+        a -= rhs.a;
+        return *this;
+    }
+};
+
+
+template<typename PIXEL>
+static status_t blurFilter(
+        GGLSurface const* dst,
+        GGLSurface const* src,
+        int kernelSizeUser,
+        int repeat)
+{
+    typedef typename PIXEL::type TYPE;
+
+    const int shift             = 31 - clz(kernelSizeUser);
+    const int areaShift         = shift*2;
+    const int kernelSize        = 1<<shift;
+    const int kernelHalfSize    = kernelSize/2;
+    const int mask              = kernelSize-1;
+    const int w                 = src->width;
+    const int h                 = src->height;
+    const uint8_t* ditherMatrix = gDitherMatrix;
+
+    // we need a temporary buffer to store one line of blurred columns
+    // as well as kernelSize lines of source pixels organized as a ring buffer.
+    void* const temporary_buffer = malloc(
+            (w + kernelSize) * sizeof(PIXEL) +
+            (src->stride * kernelSize) * sizeof(TYPE));
+    if (!temporary_buffer)
+        return NO_MEMORY;
+
+    PIXEL* const sums = (PIXEL*)temporary_buffer;
+    TYPE* const scratch = (TYPE*)(sums + w + kernelSize);
+
+    // Apply the blur 'repeat' times, this is used to approximate
+    // gaussian blurs. 3 times gives good results.
+    for (int k=0 ; k<repeat ; k++) {
+
+        // Clear the columns sums for this round
+        memset(sums, 0, (w + kernelSize) * sizeof(PIXEL));
+        TYPE* head;
+        TYPE pixel;
+        PIXEL current;
+
+        // Since we're going to override the source data we need
+        // to copy it in a temporary buffer. Only kernelSize lines are
+        // required. But since we start in the center of the kernel,
+        // we only copy half of the data, and fill the rest with zeros
+        // (assuming black/transparent pixels).
+        memcpy( scratch + src->stride*kernelHalfSize,
+                src->data,
+                src->stride*kernelHalfSize*sizeof(TYPE));
+
+        // sum half of each column, because we assume the first half is
+        // zeros (black/transparent).
+        for (int y=0 ; y<kernelHalfSize ; y++) {
+            head = (TYPE*)src->data + y*src->stride;
+            for (int x=0 ; x<w ; x++)
+                sums[x] += PIXEL( *head++ );
+        }
+
+        for (int y=0 ; y<h ; y++) {
+            TYPE* fb = (TYPE*)dst->data + y*dst->stride;
+
+            // compute the dither matrix line
+            uint8_t const * ditherY = ditherMatrix
+                    + (y & BLUR_DITHER_MASK)*BLUR_DITHER_ORDER;
+
+            // Horizontal blur pass on the columns sums
+            int count, dither, x=0;
+            PIXEL const * out= sums;
+            PIXEL const * in = sums;
+            current.clear();
+
+            count = kernelHalfSize;
+            do {
+                current += *in;
+                in++;
+            } while (--count);
+            
+            count = kernelHalfSize;
+            do {
+                current += *in;
+                dither = *(ditherY + ((x++)&BLUR_DITHER_MASK));
+                *fb++ = current.to(areaShift, k==repeat-1, dither);
+                in++;
+            } while (--count);
+
+            count = w-kernelSize;
+            do {
+                current += *in;
+                current -= *out;
+                dither = *(ditherY + ((x++)&BLUR_DITHER_MASK));
+                *fb++ = current.to(areaShift, k==repeat-1, dither);
+                in++, out++;
+            } while (--count);
+
+            count = kernelHalfSize;
+            do {
+                current -= *out;
+                dither = *(ditherY + ((x++)&BLUR_DITHER_MASK));
+                *fb++ = current.to(areaShift, k==repeat-1, dither);
+                out++;
+            } while (--count);
+
+            // vertical blur pass, subtract the oldest line from each columns
+            // and add a new line. Subtract or add zeros at the top
+            // and bottom edges.
+            TYPE* const tail = scratch + (y & mask) * src->stride;
+            if (y >= kernelHalfSize) {
+                for (int x=0 ; x<w ; x++)
+                    sums[x] -= PIXEL( tail[x] );
+            }
+            if (y < h-kernelSize) {
+                memcpy( tail,
+                        (TYPE*)src->data + (y+kernelHalfSize)*src->stride,
+                        src->stride*sizeof(TYPE));
+                for (int x=0 ; x<w ; x++)
+                    sums[x] += PIXEL( tail[x] );
+            }
+        }
+
+        // The subsequent passes are always done in-place.
+        src = dst;
+    }
+    
+    free(temporary_buffer);
+
+    return NO_ERROR;
+}
+
+template status_t blurFilter< BlurColor565<0x80> >(
+        GGLSurface const* dst,
+        GGLSurface const* src,
+        int kernelSizeUser,
+        int repeat);
+
+status_t blurFilter(
+        GGLSurface const* image,
+        int kernelSizeUser,
+        int repeat)
+{
+    return blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+}
+
+} // namespace android
+
+//err = blur< BlurColor565<0x80> >(dst, src, kernelSizeUser, repeat);
+//err = blur<BlurGray565>(dst, src, kernelSizeUser, repeat);
+//err = blur<BlurGray8888>(dst, src, kernelSizeUser, repeat);
diff --git a/libs/surfaceflinger/BlurFilter.h b/libs/surfaceflinger/BlurFilter.h
new file mode 100644
index 0000000..294db43
--- /dev/null
+++ b/libs/surfaceflinger/BlurFilter.h
@@ -0,0 +1,35 @@
+/* 
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_BLUR_FILTER_H
+#define ANDROID_BLUR_FILTER_H
+
+#include <stdint.h>
+#include <utils/Errors.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+namespace android {
+
+status_t blurFilter(
+        GGLSurface const* image,
+        int kernelSizeUser,
+        int repeat);
+
+} // namespace android
+
+#endif // ANDROID_BLUR_FILTER_H
diff --git a/libs/surfaceflinger/BootAnimation.cpp b/libs/surfaceflinger/BootAnimation.cpp
new file mode 100644
index 0000000..2b30336
--- /dev/null
+++ b/libs/surfaceflinger/BootAnimation.cpp
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "BootAnimation"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <math.h>
+#include <fcntl.h>
+#include <utils/misc.h>
+
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/AssetManager.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/DisplayInfo.h>
+#include <ui/ISurfaceComposer.h>
+#include <ui/ISurfaceFlingerClient.h>
+#include <ui/EGLNativeWindowSurface.h>
+
+#include <core/SkBitmap.h>
+#include <images/SkImageDecoder.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <EGL/eglext.h>
+
+#include "BootAnimation.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer) :
+    Thread(false) {
+    mSession = SurfaceComposerClient::clientForConnection(
+            composer->createConnection()->asBinder());
+}
+
+BootAnimation::~BootAnimation() {
+}
+
+void BootAnimation::onFirstRef() {
+    run("BootAnimation", PRIORITY_DISPLAY);
+}
+
+const sp<SurfaceComposerClient>& BootAnimation::session() const {
+    return mSession;
+}
+
+status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
+        const char* name) {
+    Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
+    if (!asset)
+        return NO_INIT;
+    SkBitmap bitmap;
+    SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
+            &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode);
+    asset->close();
+    delete asset;
+
+    // ensure we can call getPixels(). No need to call unlock, since the
+    // bitmap will go out of scope when we return from this method.
+    bitmap.lockPixels();
+
+    const int w = bitmap.width();
+    const int h = bitmap.height();
+    const void* p = bitmap.getPixels();
+
+    GLint crop[4] = { 0, h, w, -h };
+    texture->w = w;
+    texture->h = h;
+
+    glGenTextures(1, &texture->name);
+    glBindTexture(GL_TEXTURE_2D, texture->name);
+
+    switch (bitmap.getConfig()) {
+        case SkBitmap::kA8_Config:
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
+                    GL_UNSIGNED_BYTE, p);
+            break;
+        case SkBitmap::kARGB_4444_Config:
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
+                    GL_UNSIGNED_SHORT_4_4_4_4, p);
+            break;
+        case SkBitmap::kARGB_8888_Config:
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
+                    GL_UNSIGNED_BYTE, p);
+            break;
+        case SkBitmap::kRGB_565_Config:
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
+                    GL_UNSIGNED_SHORT_5_6_5, p);
+            break;
+        default:
+            break;
+    }
+
+    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    return NO_ERROR;
+}
+
+status_t BootAnimation::readyToRun() {
+    mAssets.addDefaultAssets();
+
+    DisplayInfo dinfo;
+    status_t status = session()->getDisplayInfo(0, &dinfo);
+    if (status)
+        return -1;
+
+    // create the native surface
+    sp<Surface> s = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h,
+            PIXEL_FORMAT_RGB_565);
+    session()->openTransaction();
+    s->setLayer(0x40000000);
+    session()->closeTransaction();
+
+    // initialize opengl and egl
+    const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6,
+            EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE };
+    EGLint w, h, dummy;
+    EGLint numConfigs;
+    EGLConfig config;
+    EGLSurface surface;
+    EGLContext context;
+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
+
+    mNativeWindowSurface = new EGLNativeWindowSurface(s);
+    surface = eglCreateWindowSurface(display, config, 
+            mNativeWindowSurface.get(), NULL);
+
+    context = eglCreateContext(display, config, NULL, NULL);
+    eglQuerySurface(display, surface, EGL_WIDTH, &w);
+    eglQuerySurface(display, surface, EGL_HEIGHT, &h);
+    eglMakeCurrent(display, surface, surface, context);
+    mDisplay = display;
+    mContext = context;
+    mSurface = surface;
+    mWidth = w;
+    mHeight = h;
+    mFlingerSurface = s;
+
+    // initialize GL
+    glShadeModel(GL_FLAT);
+    glEnable(GL_DITHER);
+    glEnable(GL_TEXTURE_2D);
+    glEnable(GL_SCISSOR_TEST);
+    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+    return NO_ERROR;
+}
+
+void BootAnimation::requestExit() {
+    mBarrier.open();
+    Thread::requestExit();
+}
+
+bool BootAnimation::threadLoop() {
+    bool r = android();
+    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglDestroyContext(mDisplay, mContext);
+    eglDestroySurface(mDisplay, mSurface);
+    mNativeWindowSurface.clear();
+    return r;
+}
+
+bool BootAnimation::android() {
+    initTexture(&mAndroid[0], mAssets, "images/android_320x480.png");
+    initTexture(&mAndroid[1], mAssets, "images/boot_robot.png");
+    initTexture(&mAndroid[2], mAssets, "images/boot_robot_glow.png");
+
+    // erase screen
+    glDisable(GL_SCISSOR_TEST);
+    glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
+
+    // clear screen
+    glClear(GL_COLOR_BUFFER_BIT);
+    eglSwapBuffers(mDisplay, mSurface);
+
+    // wait ~1s
+    usleep(800000);
+
+    // fade in
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+    const int steps = 8;
+    for (int i = 1; i < steps; i++) {
+        float fade = i / float(steps);
+        glColor4f(1, 1, 1, fade * fade);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h);
+        eglSwapBuffers(mDisplay, mSurface);
+    }
+
+    // draw last frame
+    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    glDisable(GL_BLEND);
+    glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h);
+    eglSwapBuffers(mDisplay, mSurface);
+
+    // update rect for the robot
+    const int x = mWidth - mAndroid[1].w - 33;
+    const int y = (mHeight - mAndroid[1].h) / 2 - 1;
+    const Rect updateRect(x, y, x + mAndroid[1].w, y + mAndroid[1].h);
+
+    // draw and update only what we need
+    mNativeWindowSurface->setSwapRectangle(updateRect.left,
+            updateRect.top, updateRect.width(), updateRect.height());
+
+    glEnable(GL_SCISSOR_TEST);
+    glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
+            updateRect.height());
+
+    const nsecs_t startTime = systemTime();
+    do {
+        // glow speed and shape
+        nsecs_t time = systemTime() - startTime;
+        float t = ((4.0f / (360.0f * us2ns(16667))) * time);
+        t = t - floorf(t);
+        const float fade = 0.5f + 0.5f * sinf(t * 2 * M_PI);
+
+        // fade the glow in and out
+        glDisable(GL_BLEND);
+        glBindTexture(GL_TEXTURE_2D, mAndroid[2].name);
+        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+        glColor4f(fade, fade, fade, fade);
+        glDrawTexiOES(updateRect.left, mHeight - updateRect.bottom, 0,
+                updateRect.width(), updateRect.height());
+
+        // draw the robot
+        glEnable(GL_BLEND);
+        glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
+        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+        glDrawTexiOES(updateRect.left, mHeight - updateRect.bottom, 0,
+                updateRect.width(), updateRect.height());
+
+        // make sure sleep a lot to not take too much CPU away from 
+        // the boot process. With this "glow" animation there is no
+        // visible difference. 
+        usleep(16667 * 4);
+
+        eglSwapBuffers(mDisplay, mSurface);
+    } while (!exitPending());
+
+    glDeleteTextures(1, &mAndroid[0].name);
+    glDeleteTextures(1, &mAndroid[1].name);
+    glDeleteTextures(1, &mAndroid[2].name);
+    return false;
+}
+
+bool BootAnimation::cylon() {
+    // initialize the textures...
+    initTexture(&mLeftTrail, mAssets, "images/cylon_left.png");
+    initTexture(&mRightTrail, mAssets, "images/cylon_right.png");
+    initTexture(&mBrightSpot, mAssets, "images/cylon_dot.png");
+
+    int w = mWidth;
+    int h = mHeight;
+
+    const Point c(w / 2, h / 2);
+    const GLint amplitude = 60;
+    const int scx = c.x - amplitude - mBrightSpot.w / 2;
+    const int scy = c.y - mBrightSpot.h / 2;
+    const int scw = amplitude * 2 + mBrightSpot.w;
+    const int sch = mBrightSpot.h;
+    const Rect updateRect(scx, h - scy - sch, scx + scw, h - scy);
+
+    // erase screen
+    glDisable(GL_SCISSOR_TEST);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    eglSwapBuffers(mDisplay, mSurface);
+
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    mNativeWindowSurface->setSwapRectangle(updateRect.left,
+            updateRect.top, updateRect.width(), updateRect.height());
+
+    glEnable(GL_SCISSOR_TEST);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+    // clear the screen to white
+    Point p;
+    float t = 0;
+    float alpha = 1.0f;
+    const nsecs_t startTime = systemTime();
+    nsecs_t fadeTime = 0;
+
+    do {
+        // Set scissor in interesting area
+        glScissor(scx, scy, scw, sch);
+
+        // erase screen
+        glClear(GL_COLOR_BUFFER_BIT);
+
+        // compute wave
+        const float a = (t * 2 * M_PI) - M_PI / 2;
+        const float sn = sinf(a);
+        const float cs = cosf(a);
+        GLint x = GLint(amplitude * sn);
+        float derivative = cs;
+
+        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+        if (derivative > 0) {
+            // vanishing trail...
+            p.x = (-amplitude + c.x) - mBrightSpot.w / 2;
+            p.y = c.y - mLeftTrail.h / 2;
+            float fade = 2.0f * (0.5f - t);
+            //fade *= fade;
+            glColor4f(fade, fade, fade, fade);
+            glBindTexture(GL_TEXTURE_2D, mLeftTrail.name);
+            glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h);
+
+            // trail...
+            p.x = (x + c.x) - (mRightTrail.w + mBrightSpot.w / 2) + 16;
+            p.y = c.y - mRightTrail.h / 2;
+            fade = t < 0.25f ? t * 4.0f : 1.0f;
+            fade *= fade;
+            glColor4f(fade, fade, fade, fade);
+            glBindTexture(GL_TEXTURE_2D, mRightTrail.name);
+            glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h);
+        } else {
+            // vanishing trail..
+            p.x = (amplitude + c.x) - (mRightTrail.w + mBrightSpot.w / 2) + 16;
+            p.y = c.y - mRightTrail.h / 2;
+            float fade = 2.0f * (0.5f - (t - 0.5f));
+            //fade *= fade;
+            glColor4f(fade, fade, fade, fade);
+            glBindTexture(GL_TEXTURE_2D, mRightTrail.name);
+            glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h);
+
+            // trail...
+            p.x = (x + c.x) - mBrightSpot.w / 2;
+            p.y = c.y - mLeftTrail.h / 2;
+            fade = t < 0.5f + 0.25f ? (t - 0.5f) * 4.0f : 1.0f;
+            fade *= fade;
+            glColor4f(fade, fade, fade, fade);
+            glBindTexture(GL_TEXTURE_2D, mLeftTrail.name);
+            glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h);
+        }
+
+        const Point p(x + c.x - mBrightSpot.w / 2, c.y - mBrightSpot.h / 2);
+        glBindTexture(GL_TEXTURE_2D, mBrightSpot.name);
+        glColor4f(1, 0.5, 0.5, 1);
+        glDrawTexiOES(p.x, p.y, 0, mBrightSpot.w, mBrightSpot.h);
+
+        // update animation
+        nsecs_t time = systemTime() - startTime;
+        t = ((4.0f / (360.0f * us2ns(16667))) * time);
+        t = t - floorf(t);
+
+        eglSwapBuffers(mDisplay, mSurface);
+
+        if (exitPending()) {
+            if (fadeTime == 0) {
+                fadeTime = time;
+            }
+            time -= fadeTime;
+            alpha = 1.0f - ((float(time) * 6.0f) / float(s2ns(1)));
+
+            session()->openTransaction();
+            mFlingerSurface->setAlpha(alpha * alpha);
+            session()->closeTransaction();
+        }
+    } while (alpha > 0);
+
+    // cleanup
+    glFinish();
+    glDeleteTextures(1, &mLeftTrail.name);
+    glDeleteTextures(1, &mRightTrail.name);
+    glDeleteTextures(1, &mBrightSpot.name);
+    return false;
+}
+
+// ---------------------------------------------------------------------------
+
+}
+; // namespace android
diff --git a/libs/surfaceflinger/BootAnimation.h b/libs/surfaceflinger/BootAnimation.h
new file mode 100644
index 0000000..b20cea0
--- /dev/null
+++ b/libs/surfaceflinger/BootAnimation.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_BOOTANIMATION_H
+#define ANDROID_BOOTANIMATION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/AssetManager.h>
+
+#include <ui/ISurfaceComposer.h>
+#include <ui/SurfaceComposerClient.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+
+#include "Barrier.h"
+
+class SkBitmap;
+
+namespace android {
+
+class AssetManager;
+class EGLNativeWindowSurface;
+
+// ---------------------------------------------------------------------------
+
+class BootAnimation : public Thread
+{
+public:
+                BootAnimation(const sp<ISurfaceComposer>& composer);
+    virtual     ~BootAnimation();
+
+    const sp<SurfaceComposerClient>& session() const;
+    virtual void        requestExit();
+
+private:
+    virtual bool        threadLoop();
+    virtual status_t    readyToRun();
+    virtual void        onFirstRef();
+
+    struct Texture {
+        GLint   w;
+        GLint   h;
+        GLuint  name;
+    };
+
+    status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
+    bool android();
+    bool cylon();
+
+    sp<SurfaceComposerClient>       mSession;
+    AssetManager mAssets;
+    Texture mLeftTrail;
+    Texture mRightTrail;
+    Texture mBrightSpot;
+    Texture mAndroid[3];
+    int     mWidth;
+    int     mHeight;
+    EGLDisplay  mDisplay;
+    EGLDisplay  mContext;
+    EGLDisplay  mSurface;
+    sp<Surface> mFlingerSurface;
+    sp<EGLNativeWindowSurface> mNativeWindowSurface;
+    Barrier mBarrier;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_BOOTANIMATION_H
diff --git a/libs/surfaceflinger/CPUGauge.cpp b/libs/surfaceflinger/CPUGauge.cpp
new file mode 100644
index 0000000..74a9270
--- /dev/null
+++ b/libs/surfaceflinger/CPUGauge.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "CPUGauge"
+
+#include <stdint.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <math.h>
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/DisplayInfo.h>
+#include <ui/ISurfaceComposer.h>
+#include <ui/ISurfaceFlingerClient.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "CPUGauge.h"
+
+namespace android {
+
+CPUGauge::CPUGauge( const sp<ISurfaceComposer>& composer,
+                    nsecs_t interval,
+                    int clock,
+                    int refclock)
+    :   Thread(false), 
+        mInterval(interval), mClock(clock), mRefClock(refclock),
+        mReferenceTime(0),
+        mReferenceWorkingTime(0), mCpuUsage(0),
+        mRefIdleTime(0), mIdleTime(0)
+{
+    mFd = fopen("/proc/stat", "r");
+    setvbuf(mFd, NULL, _IONBF, 0);
+
+    mSession = SurfaceComposerClient::clientForConnection(
+        composer->createConnection()->asBinder());
+}
+
+CPUGauge::~CPUGauge()
+{
+    fclose(mFd);
+}
+
+const sp<SurfaceComposerClient>& CPUGauge::session() const 
+{
+    return mSession;
+}
+
+void CPUGauge::onFirstRef()
+{
+    run("CPU Gauge");
+}
+
+status_t CPUGauge::readyToRun()
+{
+    LOGI("Starting CPU gauge...");
+    return NO_ERROR;
+}
+
+bool CPUGauge::threadLoop()
+{
+    DisplayInfo dinfo;
+    session()->getDisplayInfo(0, &dinfo);
+    sp<Surface> s(session()->createSurface(getpid(), 0, dinfo.w, 4, PIXEL_FORMAT_OPAQUE));
+    session()->openTransaction();
+    s->setLayer(INT_MAX);
+    session()->closeTransaction();
+    
+    static const GGLfixed colors[4][4] = {
+            { 0x00000, 0x10000, 0x00000, 0x10000 },
+            { 0x10000, 0x10000, 0x00000, 0x10000 },
+            { 0x10000, 0x00000, 0x00000, 0x10000 },
+            { 0x00000, 0x00000, 0x00000, 0x10000 },
+        };
+
+    GGLContext* gl;
+    gglInit(&gl);
+    gl->activeTexture(gl, 0);
+    gl->disable(gl, GGL_TEXTURE_2D);
+    gl->disable(gl, GGL_BLEND);
+
+    const int w = dinfo.w;
+
+    while(!exitPending())
+    {
+        mLock.lock();
+            const float cpuUsage = this->cpuUsage();
+            const float totalCpuUsage = 1.0f - idle();
+        mLock.unlock();
+
+        Surface::SurfaceInfo info;
+        s->lock(&info);
+            GGLSurface fb;
+                fb.version = sizeof(GGLSurface);
+                fb.width   = info.w;
+                fb.height  = info.h;
+                fb.stride  = info.w;
+                fb.format  = info.format;
+                fb.data = (GGLubyte*)info.bits;
+
+            gl->colorBuffer(gl, &fb);
+            gl->color4xv(gl, colors[3]);
+            gl->recti(gl, 0, 0, w, 4);
+            gl->color4xv(gl, colors[2]); // red
+            gl->recti(gl, 0, 0, int(totalCpuUsage*w), 2);
+            gl->color4xv(gl, colors[0]); // green
+            gl->recti(gl, 0, 2, int(cpuUsage*w), 4);
+        
+        s->unlockAndPost(); 
+
+        usleep(ns2us(mInterval));
+    }
+
+    gglUninit(gl);
+    return false;
+}
+
+void CPUGauge::sample()
+{
+    if (mLock.tryLock() == NO_ERROR) {
+        const nsecs_t now = systemTime(mRefClock);
+        const nsecs_t referenceTime = now-mReferenceTime;
+        if (referenceTime >= mInterval) {
+            const float reftime = 1.0f / referenceTime;
+            const nsecs_t nowWorkingTime = systemTime(mClock);
+            
+            char buf[256];
+            fgets(buf, 256, mFd);
+            rewind(mFd);
+            char *str = buf+5;
+            char const * const usermode = strsep(&str, " ");  (void)usermode;
+            char const * const usernice = strsep(&str, " ");  (void)usernice;
+            char const * const systemmode = strsep(&str, " ");(void)systemmode;
+            char const * const idle = strsep(&str, " ");
+            const nsecs_t nowIdleTime = atoi(idle) * 10000000LL;
+            mIdleTime = float(nowIdleTime - mRefIdleTime) * reftime;
+            mRefIdleTime = nowIdleTime;
+            
+            const nsecs_t workingTime = nowWorkingTime - mReferenceWorkingTime;
+            const float newCpuUsage = float(workingTime) * reftime;
+            if (mCpuUsage != newCpuUsage) {        
+                mCpuUsage = newCpuUsage;
+                mReferenceWorkingTime = nowWorkingTime;
+                mReferenceTime = now;
+            }
+        }
+        mLock.unlock();
+    }
+}
+
+
+}; // namespace android
diff --git a/libs/surfaceflinger/CPUGauge.h b/libs/surfaceflinger/CPUGauge.h
new file mode 100644
index 0000000..5bb53c0
--- /dev/null
+++ b/libs/surfaceflinger/CPUGauge.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_CPUGAUGE_H
+#define ANDROID_CPUGAUGE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Timers.h>
+
+#include <ui/SurfaceComposerClient.h>
+
+namespace android {
+
+class CPUGauge : public Thread
+{
+public:
+    CPUGauge(   const sp<ISurfaceComposer>& composer,
+                nsecs_t interval=s2ns(1),
+                int clock=SYSTEM_TIME_THREAD,
+                int refclock=SYSTEM_TIME_MONOTONIC);
+                
+    ~CPUGauge();
+
+    const sp<SurfaceComposerClient>& session() const;
+
+    void sample();
+ 
+    inline float cpuUsage() const { return mCpuUsage; }
+    inline float idle() const { return mIdleTime; }
+
+private:
+    virtual void        onFirstRef();
+    virtual status_t    readyToRun();
+    virtual bool        threadLoop();
+
+    Mutex mLock;
+
+    sp<SurfaceComposerClient> mSession;
+
+    const nsecs_t mInterval;
+    const int mClock;
+    const int mRefClock;
+
+    nsecs_t mReferenceTime;
+    nsecs_t mReferenceWorkingTime;
+    float mCpuUsage;
+    nsecs_t mRefIdleTime;
+    float mIdleTime;
+    FILE*   mFd;
+};
+
+
+}; // namespace android
+
+#endif // ANDROID_CPUGAUGE_H
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
new file mode 100644
index 0000000..f14d7e9
--- /dev/null
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include <cutils/properties.h>
+
+#include <utils/Log.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include <GLES/gl.h>
+#include <EGL/eglext.h>
+
+
+#include "DisplayHardware/DisplayHardware.h"
+
+#include <hardware/copybit.h>
+#include <hardware/overlay.h>
+
+using namespace android;
+
+static __attribute__((noinline))
+const char *egl_strerror(EGLint err)
+{
+    switch (err){
+        case EGL_SUCCESS:           return "EGL_SUCCESS";
+        case EGL_NOT_INITIALIZED:   return "EGL_NOT_INITIALIZED";
+        case EGL_BAD_ACCESS:        return "EGL_BAD_ACCESS";
+        case EGL_BAD_ALLOC:         return "EGL_BAD_ALLOC";
+        case EGL_BAD_ATTRIBUTE:     return "EGL_BAD_ATTRIBUTE";
+        case EGL_BAD_CONFIG:        return "EGL_BAD_CONFIG";
+        case EGL_BAD_CONTEXT:       return "EGL_BAD_CONTEXT";
+        case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
+        case EGL_BAD_DISPLAY:       return "EGL_BAD_DISPLAY";
+        case EGL_BAD_MATCH:         return "EGL_BAD_MATCH";
+        case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
+        case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
+        case EGL_BAD_PARAMETER:     return "EGL_BAD_PARAMETER";
+        case EGL_BAD_SURFACE:       return "EGL_BAD_SURFACE";
+        case EGL_CONTEXT_LOST:      return "EGL_CONTEXT_LOST";
+        default: return "UNKNOWN";
+    }
+}
+
+static __attribute__((noinline))
+void checkGLErrors()
+{
+    GLenum error = glGetError();
+    if (error != GL_NO_ERROR)
+        LOGE("GL error 0x%04x", int(error));
+}
+
+static __attribute__((noinline))
+void checkEGLErrors(const char* token)
+{
+    EGLint error = eglGetError();
+    // GLESonGL seems to be returning 0 when there is no errors?
+    if (error && error != EGL_SUCCESS)
+        LOGE("%s error 0x%04x (%s)",
+                token, int(error), egl_strerror(error));
+}
+
+
+/*
+ * Initialize the display to the specified values.
+ *
+ */
+
+DisplayHardware::DisplayHardware(
+        const sp<SurfaceFlinger>& flinger,
+        uint32_t dpy)
+    : DisplayHardwareBase(flinger, dpy)
+{
+    init(dpy);
+}
+
+DisplayHardware::~DisplayHardware()
+{
+    fini();
+}
+
+float DisplayHardware::getDpiX() const          { return mDpiX; }
+float DisplayHardware::getDpiY() const          { return mDpiY; }
+float DisplayHardware::getDensity() const       { return mDensity; }
+float DisplayHardware::getRefreshRate() const   { return mRefreshRate; }
+int DisplayHardware::getWidth() const           { return mWidth; }
+int DisplayHardware::getHeight() const          { return mHeight; }
+PixelFormat DisplayHardware::getFormat() const  { return mFormat; }
+
+void DisplayHardware::init(uint32_t dpy)
+{
+    // initialize EGL
+    const EGLint attribs[] = {
+            EGL_RED_SIZE,       5,
+            EGL_GREEN_SIZE,     6,
+            EGL_BLUE_SIZE,      5,
+            EGL_DEPTH_SIZE,     0,
+            EGL_NONE
+    };
+    EGLint w, h, dummy;
+    EGLint numConfigs, n;
+    EGLConfig config;
+    EGLSurface surface;
+    EGLContext context;
+    mFlags = 0;
+
+    // TODO: all the extensions below should be queried through
+    // eglGetProcAddress().
+
+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    eglInitialize(display, NULL, NULL);
+    eglGetConfigs(display, NULL, 0, &numConfigs);
+    eglChooseConfig(display, attribs, &config, 1, &n);
+
+    /*
+     * Gather EGL extensions
+     */
+
+    const char* const egl_extensions = eglQueryString(
+            display, EGL_EXTENSIONS);
+    
+    LOGI("EGL informations:");
+    LOGI("# of configs : %d", numConfigs);
+    LOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
+    LOGI("version   : %s", eglQueryString(display, EGL_VERSION));
+    LOGI("extensions: %s", egl_extensions);
+    LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
+
+    // TODO: get this from the devfb driver (probably should be HAL module)
+    mFlags |= SWAP_RECTANGLE_EXTENSION;
+    
+    // TODO: get the real "update_on_demand" behavior (probably should be HAL module)
+    mFlags |= UPDATE_ON_DEMAND;
+
+    if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
+        if (dummy == EGL_SLOW_CONFIG)
+            mFlags |= SLOW_CONFIG;
+    }
+
+    /*
+     * Create our main surface
+     */
+
+    mDisplaySurface = new EGLDisplaySurface();
+
+    surface = eglCreateWindowSurface(display, config, mDisplaySurface.get(), NULL);
+    //checkEGLErrors("eglCreateDisplaySurfaceANDROID");
+
+    if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
+        if (dummy == EGL_BUFFER_PRESERVED) {
+            mFlags |= BUFFER_PRESERVED;
+        }
+    }
+    
+    GLint value = EGL_UNKNOWN;
+    eglQuerySurface(display, surface, EGL_HORIZONTAL_RESOLUTION, &value);
+    if (value == EGL_UNKNOWN) {
+        mDpiX = 160.0f;
+    } else {
+        mDpiX = 25.4f * float(value)/EGL_DISPLAY_SCALING;
+    }
+    value = EGL_UNKNOWN;
+    eglQuerySurface(display, surface, EGL_VERTICAL_RESOLUTION, &value);
+    if (value == EGL_UNKNOWN) {
+        mDpiY = 160.0f;
+    } else {
+        mDpiY = 25.4f * float(value)/EGL_DISPLAY_SCALING;
+    }
+    mRefreshRate = 60.f;    // TODO: get the real refresh rate 
+    
+    
+    char property[PROPERTY_VALUE_MAX];
+    if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
+        LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
+        strcpy(property, "160");
+    }
+    mDensity = atoi(property) * (1.0f/160.0f);
+
+
+    /*
+     * Create our OpenGL ES context
+     */
+    
+    context = eglCreateContext(display, config, NULL, NULL);
+    //checkEGLErrors("eglCreateContext");
+    
+    eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
+    eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
+    
+    
+    /*
+     * Gather OpenGL ES extensions
+     */
+
+    eglMakeCurrent(display, surface, surface, context);
+    const char* const  gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
+    LOGI("OpenGL informations:");
+    LOGI("vendor    : %s", glGetString(GL_VENDOR));
+    LOGI("renderer  : %s", glGetString(GL_RENDERER));
+    LOGI("version   : %s", glGetString(GL_VERSION));
+    LOGI("extensions: %s", gl_extensions);
+
+    if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) {
+        mFlags |= NPOT_EXTENSION;
+    }
+    if (strstr(gl_extensions, "GL_OES_draw_texture")) {
+        mFlags |= DRAW_TEXTURE_EXTENSION;
+    }
+    if (strstr(gl_extensions, "GL_ANDROID_direct_texture")) {
+        mFlags |= DIRECT_TEXTURE;
+    }
+
+    // Unbind the context from this thread
+    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+    mDisplay = display;
+    mConfig  = config;
+    mSurface = surface;
+    mContext = context;
+    mFormat  = GGL_PIXEL_FORMAT_RGB_565;
+    
+    hw_module_t const* module;
+
+    mBlitEngine = NULL;
+    if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+        copybit_open(module, &mBlitEngine);
+    }
+
+    mOverlayEngine = NULL;
+    if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
+        overlay_control_open(module, &mOverlayEngine);
+    }
+}
+
+/*
+ * Clean up.  Throw out our local state.
+ *
+ * (It's entirely possible we'll never get here, since this is meant
+ * for real hardware, which doesn't restart.)
+ */
+
+void DisplayHardware::fini()
+{
+    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglTerminate(mDisplay);
+    copybit_close(mBlitEngine);
+    overlay_control_close(mOverlayEngine);
+}
+
+void DisplayHardware::releaseScreen() const
+{
+    DisplayHardwareBase::releaseScreen();
+}
+
+void DisplayHardware::acquireScreen() const
+{
+    DisplayHardwareBase::acquireScreen();
+}
+
+void DisplayHardware::getDisplaySurface(copybit_image_t* img) const
+{
+    img->w      = mDisplaySurface->stride;
+    img->h      = mDisplaySurface->height;
+    img->format = mDisplaySurface->format;
+    img->offset = mDisplaySurface->offset;
+    img->base   = (void*)mDisplaySurface->base;
+    img->fd     = mDisplaySurface->fd;
+}
+
+void DisplayHardware::getDisplaySurface(GGLSurface* fb) const
+{
+    fb->version= sizeof(GGLSurface);
+    fb->width  = mDisplaySurface->width;
+    fb->height = mDisplaySurface->height;
+    fb->stride = mDisplaySurface->stride;
+    fb->format = mDisplaySurface->format;
+    fb->data   = (GGLubyte*)mDisplaySurface->base + mDisplaySurface->offset;
+}
+
+uint32_t DisplayHardware::getPageFlipCount() const {
+    return mDisplaySurface->getPageFlipCount();
+}
+
+/*
+ * "Flip" the front and back buffers.
+ */
+
+void DisplayHardware::flip(const Region& dirty) const
+{
+    checkGLErrors();
+
+    EGLDisplay dpy = mDisplay;
+    EGLSurface surface = mSurface;
+
+    Region newDirty(dirty);
+    newDirty.andSelf(Rect(mWidth, mHeight));
+
+    if (mFlags & BUFFER_PRESERVED) {
+        const Region copyback(mDirty.subtract(newDirty));
+        mDirty = newDirty;
+        mDisplaySurface->copyFrontToBack(copyback);
+    } 
+
+    if (mFlags & SWAP_RECTANGLE_EXTENSION) {
+        const Rect& b(newDirty.bounds());
+        mDisplaySurface->setSwapRectangle(
+                b.left, b.top, b.width(), b.height());
+    }
+
+    eglSwapBuffers(dpy, surface);
+    checkEGLErrors("eglSwapBuffers");
+
+    // for debugging
+    //glClearColor(1,0,0,0);
+    //glClear(GL_COLOR_BUFFER_BIT);
+}
+
+uint32_t DisplayHardware::getFlags() const
+{
+    return mFlags;
+}
+
+void DisplayHardware::makeCurrent() const
+{
+    eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
+}
+
+void DisplayHardware::copyFrontToImage(const copybit_image_t& front) const {
+    mDisplaySurface->copyFrontToImage(front);
+}
+
+void DisplayHardware::copyBackToImage(const copybit_image_t& front) const {
+    mDisplaySurface->copyBackToImage(front);
+}
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
new file mode 100644
index 0000000..550a4d1
--- /dev/null
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_DISPLAY_HARDWARE_H
+#define ANDROID_DISPLAY_HARDWARE_H
+
+#include <stdlib.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+
+#include <EGL/egl.h>
+
+#include "DisplayHardware/DisplayHardwareBase.h"
+
+struct overlay_control_device_t;
+struct copybit_device_t;
+struct copybit_image_t;
+struct copybit_t;
+
+namespace android {
+
+class EGLDisplaySurface;
+
+class DisplayHardware : public DisplayHardwareBase
+{
+public:
+    enum {
+        DIRECT_TEXTURE          = 0x00000002,
+        SWAP_RECTANGLE_EXTENSION= 0x00000004,
+        COPY_BITS_EXTENSION     = 0x00000008,
+        NPOT_EXTENSION          = 0x00000100,
+        DRAW_TEXTURE_EXTENSION  = 0x00000200,
+        BUFFER_PRESERVED        = 0x00010000,
+        UPDATE_ON_DEMAND        = 0x00020000,   // video driver feature
+        SLOW_CONFIG             = 0x00040000,   // software
+    };
+
+    DisplayHardware(
+            const sp<SurfaceFlinger>& flinger,
+            uint32_t displayIndex);
+
+    ~DisplayHardware();
+
+    void releaseScreen() const;
+    void acquireScreen() const;
+
+    // Flip the front and back buffers if the back buffer is "dirty".  Might
+    // be instantaneous, might involve copying the frame buffer around.
+    void flip(const Region& dirty) const;
+
+    float       getDpiX() const;
+    float       getDpiY() const;
+    float       getRefreshRate() const;
+    float       getDensity() const;
+    int         getWidth() const;
+    int         getHeight() const;
+    PixelFormat getFormat() const;
+    uint32_t    getFlags() const;
+    void        makeCurrent() const;
+
+    uint32_t getPageFlipCount() const;
+    void getDisplaySurface(copybit_image_t* img) const;
+    void getDisplaySurface(GGLSurface* fb) const;
+    EGLDisplay getEGLDisplay() const { return mDisplay; }
+    copybit_device_t* getBlitEngine() const { return mBlitEngine; }
+    overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
+    
+    void copyFrontToImage(const copybit_image_t& front) const;
+    void copyBackToImage(const copybit_image_t& front) const;
+       
+    Rect bounds() const {
+        return Rect(mWidth, mHeight);
+    }
+
+private:
+    void init(uint32_t displayIndex) __attribute__((noinline));
+    void fini() __attribute__((noinline));
+
+    EGLDisplay      mDisplay;
+    EGLSurface      mSurface;
+    EGLContext      mContext;
+    EGLConfig       mConfig;
+    float           mDpiX;
+    float           mDpiY;
+    float           mRefreshRate;
+    float           mDensity;
+    int             mWidth;
+    int             mHeight;
+    PixelFormat     mFormat;
+    uint32_t        mFlags;
+    mutable Region  mDirty;
+    sp<EGLDisplaySurface> mDisplaySurface;
+    copybit_device_t*     mBlitEngine;
+    overlay_control_device_t* mOverlayEngine;
+};
+
+}; // namespace android
+
+#endif // ANDROID_DISPLAY_HARDWARE_H
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
new file mode 100644
index 0000000..f75e5c2
--- /dev/null
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+
+#include <linux/unistd.h>
+
+#include <utils/Log.h>
+
+#include "DisplayHardware/DisplayHardwareBase.h"
+#include "SurfaceFlinger.h"
+
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+namespace android {
+
+static char const * kSleepFileName = "/sys/power/wait_for_fb_sleep";
+static char const * kWakeFileName = "/sys/power/wait_for_fb_wake";
+static char const * const kOldSleepFileName = "/sys/android_power/wait_for_fb_sleep";
+static char const * const kOldWakeFileName = "/sys/android_power/wait_for_fb_wake";
+
+// This dir exists if the framebuffer console is present, either built into
+// the kernel or loaded as a module.
+static char const * const kFbconSysDir = "/sys/class/graphics/fbcon";
+
+// ----------------------------------------------------------------------------
+
+DisplayHardwareBase::DisplayEventThreadBase::DisplayEventThreadBase(
+        const sp<SurfaceFlinger>& flinger)
+    : Thread(false), mFlinger(flinger) {
+}
+
+DisplayHardwareBase::DisplayEventThreadBase::~DisplayEventThreadBase() {
+}
+
+// ----------------------------------------------------------------------------
+
+DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
+        const sp<SurfaceFlinger>& flinger)
+    : DisplayEventThreadBase(flinger)
+{
+}
+
+DisplayHardwareBase::DisplayEventThread::~DisplayEventThread()
+{
+}
+
+bool DisplayHardwareBase::DisplayEventThread::threadLoop()
+{
+    int err = 0;
+    char buf;
+    int fd;
+
+    fd = open(kSleepFileName, O_RDONLY, 0);
+    do {
+      err = read(fd, &buf, 1);
+    } while (err < 0 && errno == EINTR);
+    close(fd);
+    LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
+    if (err >= 0) {
+        sp<SurfaceFlinger> flinger = mFlinger.promote();
+        LOGD("About to give-up screen, flinger = %p", flinger.get());
+        if (flinger != 0) {
+            mBarrier.close();
+            flinger->screenReleased(0);
+            mBarrier.wait();
+        }
+    }
+    fd = open(kWakeFileName, O_RDONLY, 0);
+    do {
+      err = read(fd, &buf, 1);
+    } while (err < 0 && errno == EINTR);
+    close(fd);
+    LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
+    if (err >= 0) {
+        sp<SurfaceFlinger> flinger = mFlinger.promote();
+        LOGD("Screen about to return, flinger = %p", flinger.get());
+        if (flinger != 0)
+            flinger->screenAcquired(0);
+    }
+    return true;
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const
+{
+    mBarrier.open();
+    return NO_ERROR;
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::readyToRun()
+{
+    if (access(kSleepFileName, R_OK) || access(kWakeFileName, R_OK)) {
+        if (access(kOldSleepFileName, R_OK) || access(kOldWakeFileName, R_OK)) {
+            LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName);
+            return NO_INIT;
+        }
+        kSleepFileName = kOldSleepFileName;
+        kWakeFileName = kOldWakeFileName;
+    }
+    return NO_ERROR;
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::initCheck() const
+{
+    return (((access(kSleepFileName, R_OK) == 0 &&
+            access(kWakeFileName, R_OK) == 0) ||
+            (access(kOldSleepFileName, R_OK) == 0 &&
+            access(kOldWakeFileName, R_OK) == 0)) &&
+            access(kFbconSysDir, F_OK) != 0) ? NO_ERROR : NO_INIT;
+}
+
+// ----------------------------------------------------------------------------
+
+pid_t DisplayHardwareBase::ConsoleManagerThread::sSignalCatcherPid = 0;
+
+DisplayHardwareBase::ConsoleManagerThread::ConsoleManagerThread(
+        const sp<SurfaceFlinger>& flinger)
+    : DisplayEventThreadBase(flinger), consoleFd(-1)
+{   
+    sSignalCatcherPid = 0;
+
+    // create a new console
+    char const * const ttydev = "/dev/tty0";
+    int fd = open(ttydev, O_RDWR | O_SYNC);
+    if (fd<0) {
+        LOGE("Can't open %s", ttydev);
+        this->consoleFd = -errno;
+        return;
+    }
+
+    // to make sure that we are in text mode
+    int res = ioctl(fd, KDSETMODE, (void*) KD_TEXT);
+    if (res<0) {
+        LOGE("ioctl(%d, KDSETMODE, ...) failed, res %d (%s)",
+                fd, res, strerror(errno));
+    }
+    
+    // get the current console
+    struct vt_stat vs;
+    res = ioctl(fd, VT_GETSTATE, &vs);
+    if (res<0) {
+        LOGE("ioctl(%d, VT_GETSTATE, ...) failed, res %d (%s)",
+                fd, res, strerror(errno));
+        this->consoleFd = -errno;
+        return;
+    }
+
+    // switch to console 7 (which is what X normaly uses)
+    int vtnum = 7;
+    do {
+        res = ioctl(fd, VT_ACTIVATE, (void*)vtnum);
+    } while(res < 0 && errno == EINTR);
+    if (res<0) {
+        LOGE("ioctl(%d, VT_ACTIVATE, ...) failed, %d (%s) for %d",
+                fd, errno, strerror(errno), vtnum);
+        this->consoleFd = -errno;
+        return;
+    }
+
+    do {
+        res = ioctl(fd, VT_WAITACTIVE, (void*)vtnum);
+    } while(res < 0 && errno == EINTR);
+    if (res<0) {
+        LOGE("ioctl(%d, VT_WAITACTIVE, ...) failed, %d %d %s for %d",
+                fd, res, errno, strerror(errno), vtnum);
+        this->consoleFd = -errno;
+        return;
+    }
+
+    // open the new console
+    close(fd);
+    fd = open(ttydev, O_RDWR | O_SYNC);
+    if (fd<0) {
+        LOGE("Can't open new console %s", ttydev);
+        this->consoleFd = -errno;
+        return;
+    }
+
+    /* disable console line buffer, echo, ... */
+    struct termios ttyarg;
+    ioctl(fd, TCGETS , &ttyarg);
+    ttyarg.c_iflag = 0;
+    ttyarg.c_lflag = 0;
+    ioctl(fd, TCSETS , &ttyarg);
+
+    // set up signals so we're notified when the console changes
+    // we can't use SIGUSR1 because it's used by the java-vm
+    vm.mode = VT_PROCESS;
+    vm.waitv = 0;
+    vm.relsig = SIGUSR2;
+    vm.acqsig = SIGUNUSED;
+    vm.frsig = 0;
+
+    struct sigaction act;
+    sigemptyset(&act.sa_mask);
+    act.sa_handler = sigHandler;
+    act.sa_flags = 0;
+    sigaction(vm.relsig, &act, NULL);
+
+    sigemptyset(&act.sa_mask);
+    act.sa_handler = sigHandler;
+    act.sa_flags = 0;
+    sigaction(vm.acqsig, &act, NULL);
+
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, vm.relsig);
+    sigaddset(&mask, vm.acqsig);
+    sigprocmask(SIG_BLOCK, &mask, NULL);
+
+    // switch to graphic mode
+    res = ioctl(fd, KDSETMODE, (void*)KD_GRAPHICS);
+    LOGW_IF(res<0,
+            "ioctl(%d, KDSETMODE, KD_GRAPHICS) failed, res %d", fd, res);
+
+    this->prev_vt_num = vs.v_active;
+    this->vt_num = vtnum;
+    this->consoleFd = fd;
+}
+
+DisplayHardwareBase::ConsoleManagerThread::~ConsoleManagerThread()
+{   
+    if (this->consoleFd >= 0) {
+        int fd = this->consoleFd;
+        int prev_vt_num = this->prev_vt_num;
+        int res;
+        ioctl(fd, KDSETMODE, (void*)KD_TEXT);
+        do {
+            res = ioctl(fd, VT_ACTIVATE, (void*)prev_vt_num);
+        } while(res < 0 && errno == EINTR);
+        do {
+            res = ioctl(fd, VT_WAITACTIVE, (void*)prev_vt_num);
+        } while(res < 0 && errno == EINTR);
+        close(fd);    
+        char const * const ttydev = "/dev/tty0";
+        fd = open(ttydev, O_RDWR | O_SYNC);
+        ioctl(fd, VT_DISALLOCATE, 0);
+        close(fd);
+    }
+}
+
+status_t DisplayHardwareBase::ConsoleManagerThread::readyToRun()
+{
+    if (this->consoleFd >= 0) {
+        sSignalCatcherPid = gettid();
+        
+        sigset_t mask;
+        sigemptyset(&mask);
+        sigaddset(&mask, vm.relsig);
+        sigaddset(&mask, vm.acqsig);
+        sigprocmask(SIG_BLOCK, &mask, NULL);
+
+        int res = ioctl(this->consoleFd, VT_SETMODE, &vm);
+        if (res<0) {
+            LOGE("ioctl(%d, VT_SETMODE, ...) failed, %d (%s)",
+                    this->consoleFd, errno, strerror(errno));
+        }
+        return NO_ERROR;
+    }
+    return this->consoleFd;
+}
+
+void DisplayHardwareBase::ConsoleManagerThread::requestExit()
+{
+    Thread::requestExit();
+    if (sSignalCatcherPid != 0) {
+        // wake the thread up
+        kill(sSignalCatcherPid, SIGINT);
+        // wait for it...
+    }
+}
+
+void DisplayHardwareBase::ConsoleManagerThread::sigHandler(int sig)
+{
+    // resend the signal to our signal catcher thread
+    LOGW("received signal %d in thread %d, resending to %d",
+            sig, gettid(), sSignalCatcherPid);
+
+    // we absolutely need the delays below because without them
+    // our main thread never gets a chance to handle the signal.
+    usleep(10000);
+    kill(sSignalCatcherPid, sig);
+    usleep(10000);
+}
+
+status_t DisplayHardwareBase::ConsoleManagerThread::releaseScreen() const
+{
+    int fd = this->consoleFd;
+    int err = ioctl(fd, VT_RELDISP, (void*)1);
+    LOGE_IF(err<0, "ioctl(%d, VT_RELDISP, 1) failed %d (%s)",
+        fd, errno, strerror(errno));
+    return (err<0) ? (-errno) : status_t(NO_ERROR);
+}
+
+bool DisplayHardwareBase::ConsoleManagerThread::threadLoop()
+{
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, vm.relsig);
+    sigaddset(&mask, vm.acqsig);
+
+    int sig = 0;
+    sigwait(&mask, &sig);
+
+    if (sig == vm.relsig) {
+        sp<SurfaceFlinger> flinger = mFlinger.promote();
+        //LOGD("About to give-up screen, flinger = %p", flinger.get());
+        if (flinger != 0)
+            flinger->screenReleased(0);
+    } else if (sig == vm.acqsig) {
+        sp<SurfaceFlinger> flinger = mFlinger.promote();
+        //LOGD("Screen about to return, flinger = %p", flinger.get());
+        if (flinger != 0) 
+            flinger->screenAcquired(0);
+    }
+    
+    return true;
+}
+
+status_t DisplayHardwareBase::ConsoleManagerThread::initCheck() const
+{
+    return consoleFd >= 0 ? NO_ERROR : NO_INIT;
+}
+
+// ----------------------------------------------------------------------------
+
+DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,
+        uint32_t displayIndex) 
+    : mCanDraw(true)
+{
+    mDisplayEventThread = new DisplayEventThread(flinger);
+    if (mDisplayEventThread->initCheck() != NO_ERROR) {
+        // fall-back on the console
+        mDisplayEventThread = new ConsoleManagerThread(flinger);
+    }
+}
+
+DisplayHardwareBase::~DisplayHardwareBase()
+{
+    // request exit
+    mDisplayEventThread->requestExitAndWait();
+}
+
+
+bool DisplayHardwareBase::canDraw() const
+{
+    return mCanDraw;
+}
+
+void DisplayHardwareBase::releaseScreen() const
+{
+    status_t err = mDisplayEventThread->releaseScreen();
+    if (err >= 0) {
+        //LOGD("screen given-up");
+        mCanDraw = false;
+    }
+}
+
+void DisplayHardwareBase::acquireScreen() const
+{
+    status_t err = mDisplayEventThread->acquireScreen();
+    if (err >= 0) {
+        //LOGD("screen returned");
+        mCanDraw = true;
+    }
+}
+
+}; // namespace android
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
new file mode 100644
index 0000000..8369bb8
--- /dev/null
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_DISPLAY_HARDWARE_BASE_H
+#define ANDROID_DISPLAY_HARDWARE_BASE_H
+
+#include <stdint.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include "Barrier.h"
+
+namespace android {
+
+class SurfaceFlinger; 
+
+class DisplayHardwareBase
+{
+public:
+                DisplayHardwareBase(
+                        const sp<SurfaceFlinger>& flinger,
+                        uint32_t displayIndex);
+
+                ~DisplayHardwareBase();
+
+    // console managment
+    void releaseScreen() const;
+    void acquireScreen() const;
+    bool canDraw() const;
+
+private:
+    class DisplayEventThreadBase : public Thread {
+    protected:
+        wp<SurfaceFlinger> mFlinger;
+    public:
+        DisplayEventThreadBase(const sp<SurfaceFlinger>& flinger);
+        virtual ~DisplayEventThreadBase();
+        virtual void onFirstRef() {
+            run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
+        }
+        virtual status_t acquireScreen() const { return NO_ERROR; };
+        virtual status_t releaseScreen() const { return NO_ERROR; };
+        virtual status_t initCheck() const = 0;
+    };
+
+    class DisplayEventThread : public DisplayEventThreadBase 
+    {
+        mutable Barrier mBarrier;
+    public:
+                DisplayEventThread(const sp<SurfaceFlinger>& flinger);
+        virtual ~DisplayEventThread();
+        virtual bool threadLoop();
+        virtual status_t readyToRun();
+        virtual status_t releaseScreen() const;
+        virtual status_t initCheck() const;
+    };
+
+    class ConsoleManagerThread : public DisplayEventThreadBase 
+    {
+        int consoleFd;
+        int vt_num;
+        int prev_vt_num;
+        vt_mode vm;
+        static void sigHandler(int sig);
+        static pid_t sSignalCatcherPid;
+    public:
+                ConsoleManagerThread(const sp<SurfaceFlinger>& flinger);
+        virtual ~ConsoleManagerThread();
+        virtual bool threadLoop();
+        virtual status_t readyToRun();
+        virtual void requestExit();
+        virtual status_t releaseScreen() const;
+        virtual status_t initCheck() const;
+    };
+
+    sp<DisplayEventThreadBase>  mDisplayEventThread;
+    mutable int                 mCanDraw;
+};
+
+}; // namespace android
+
+#endif // ANDROID_DISPLAY_HARDWARE_BASE_H
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
new file mode 100644
index 0000000..eb75f99
--- /dev/null
+++ b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
@@ -0,0 +1,581 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/IBinder.h>
+#include <utils/MemoryDealer.h>
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapPmem.h>
+#include <utils/MemoryHeapBase.h>
+#include <utils/IPCThreadState.h>
+#include <utils/StopWatch.h>
+
+#include <ui/ISurfaceComposer.h>
+
+#include "VRamHeap.h"
+#include "GPUHardware.h"
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+#include "GPUHardware/GPUHardware.h"
+
+
+/* 
+ * Manage the GPU. This implementation is very specific to the G1.
+ * There are no abstraction here. 
+ * 
+ * All this code will soon go-away and be replaced by a new architecture
+ * for managing graphics accelerators.
+ * 
+ * In the meantime, it is conceptually possible to instantiate a
+ * GPUHardwareInterface for another GPU (see GPUFactory at the bottom
+ * of this file); practically... doubtful.
+ * 
+ */
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class GPUClientHeap;
+class GPUAreaHeap;
+
+class GPUHardware : public GPUHardwareInterface, public IBinder::DeathRecipient
+{
+public:
+    static const int GPU_RESERVED_SIZE;
+    static const int GPUR_SIZE;
+
+            GPUHardware();
+    virtual ~GPUHardware();
+    
+    virtual void revoke(int pid);
+    virtual sp<MemoryDealer> request(int pid);
+    virtual status_t request(int pid, 
+            const sp<IGPUCallback>& callback,
+            ISurfaceComposer::gpu_info_t* gpu);
+
+    virtual status_t friendlyRevoke();
+    virtual void unconditionalRevoke();
+    
+    virtual pid_t getOwner() const { return mOwner; }
+
+    // used for debugging only...
+    virtual sp<SimpleBestFitAllocator> getAllocator() const;
+
+private:
+    
+    
+    enum {
+        NO_OWNER = -1,
+    };
+        
+    struct GPUArea {
+        sp<GPUAreaHeap>     heap;
+        sp<MemoryHeapPmem>  clientHeap;
+        sp<IMemory> map();
+    };
+    
+    struct Client {
+        pid_t       pid;
+        GPUArea     smi;
+        GPUArea     ebi;
+        GPUArea     reg;
+        void createClientHeaps();
+        void revokeAllHeaps();
+    };
+    
+    Client& getClientLocked(pid_t pid);
+    status_t requestLocked(int pid);
+    void releaseLocked();
+    void takeBackGPULocked();
+    void registerCallbackLocked(const sp<IGPUCallback>& callback,
+            Client& client);
+
+    virtual void binderDied(const wp<IBinder>& who);
+
+    mutable Mutex           mLock;
+    sp<GPUAreaHeap>         mSMIHeap;
+    sp<GPUAreaHeap>         mEBIHeap;
+    sp<GPUAreaHeap>         mREGHeap;
+
+    KeyedVector<pid_t, Client> mClients;
+    DefaultKeyedVector< wp<IBinder>, pid_t > mRegisteredClients;
+    
+    pid_t                   mOwner;
+
+    sp<MemoryDealer>        mCurrentAllocator;
+    sp<IGPUCallback>        mCallback;
+    
+    sp<SimpleBestFitAllocator>  mAllocator;
+
+    Condition               mCondition;
+};
+
+// size reserved for GPU surfaces
+// 1200 KB fits exactly:
+//  - two 320*480 16-bits double-buffered surfaces
+//  - one 320*480 32-bits double-buffered surface
+//  - one 320*240 16-bits double-buffered, 4x anti-aliased surface
+const int GPUHardware::GPU_RESERVED_SIZE  = 1200 * 1024;
+const int GPUHardware::GPUR_SIZE          = 1 * 1024 * 1024;
+
+// ---------------------------------------------------------------------------
+
+/* 
+ * GPUHandle is a special IMemory given to the client. It represents their
+ * handle to the GPU. Once they give it up, they loose GPU access, or if
+ * they explicitly revoke their access through the binder code 1000.
+ * In both cases, this triggers a callback to revoke()
+ * first, and then actually powers down the chip.
+ * 
+ * In the case of a misbehaving app, GPUHardware can ask for an immediate
+ * release of the GPU to the target process which should answer by calling
+ * code 1000 on GPUHandle. If it doesn't in a timely manner, the GPU will
+ * be revoked from under their feet.
+ * 
+ * We should never hold a strong reference on GPUHandle. In practice this
+ * shouldn't be a big issue though because clients should use code 1000 and
+ * not rely on the dtor being called.
+ * 
+ */
+
+class GPUClientHeap : public MemoryHeapPmem
+{
+public:
+    GPUClientHeap(const wp<GPUHardware>& gpu, 
+            const sp<MemoryHeapBase>& heap)
+        :  MemoryHeapPmem(heap), mGPU(gpu) { }
+protected:
+    wp<GPUHardware> mGPU;
+};
+
+class GPUAreaHeap : public MemoryHeapBase
+{
+public:
+    GPUAreaHeap(const wp<GPUHardware>& gpu,
+            const char* const vram, size_t size=0, size_t reserved=0)
+    : MemoryHeapBase(vram, size), mGPU(gpu) { 
+        if (base() != MAP_FAILED) {
+            if (reserved == 0)
+                reserved = virtualSize();
+            mAllocator = new SimpleBestFitAllocator(reserved);
+        }
+    }
+    virtual sp<MemoryHeapPmem> createClientHeap() {
+        sp<MemoryHeapBase> parentHeap(this);
+        return new GPUClientHeap(mGPU, parentHeap);
+    }
+    virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
+        return mAllocator; 
+    }
+private:
+    sp<SimpleBestFitAllocator>  mAllocator;
+protected:
+    wp<GPUHardware> mGPU;
+};
+
+class GPURegisterHeap : public GPUAreaHeap
+{
+public:
+    GPURegisterHeap(const sp<GPUHardware>& gpu)
+        : GPUAreaHeap(gpu, "/dev/hw3d", GPUHardware::GPUR_SIZE) { }
+    virtual sp<MemoryHeapPmem> createClientHeap() {
+        sp<MemoryHeapBase> parentHeap(this);
+        return new MemoryHeapRegs(mGPU, parentHeap);
+    }
+private:
+    class MemoryHeapRegs : public GPUClientHeap  {
+    public:
+        MemoryHeapRegs(const wp<GPUHardware>& gpu, 
+             const sp<MemoryHeapBase>& heap)
+            : GPUClientHeap(gpu, heap) { }
+        sp<MemoryHeapPmem::MemoryPmem> createMemory(size_t offset, size_t size);
+        virtual void revoke();
+    private:
+        class GPUHandle : public MemoryHeapPmem::MemoryPmem {
+        public:
+            GPUHandle(const sp<GPUHardware>& gpu,
+                    const sp<MemoryHeapPmem>& heap)
+                : MemoryHeapPmem::MemoryPmem(heap), 
+                  mGPU(gpu), mOwner(gpu->getOwner()) { }
+            virtual ~GPUHandle();
+            virtual sp<IMemoryHeap> getMemory(
+                    ssize_t* offset, size_t* size) const;
+            virtual void revoke() { };
+            virtual status_t onTransact(
+                    uint32_t code, const Parcel& data, 
+                    Parcel* reply, uint32_t flags);
+        private:
+            void revokeNotification();
+            wp<GPUHardware> mGPU;
+            pid_t mOwner;
+        };
+    };
+};
+
+GPURegisterHeap::MemoryHeapRegs::GPUHandle::~GPUHandle() { 
+    //LOGD("GPUHandle %p released, revoking GPU", this);
+    revokeNotification(); 
+}
+void GPURegisterHeap::MemoryHeapRegs::GPUHandle::revokeNotification()  {
+    sp<GPUHardware> hw(mGPU.promote());
+    if (hw != 0) {
+        hw->revoke(mOwner);
+    }
+}
+sp<IMemoryHeap> GPURegisterHeap::MemoryHeapRegs::GPUHandle::getMemory(
+        ssize_t* offset, size_t* size) const
+{
+    sp<MemoryHeapPmem> heap = getHeap();
+    if (offset) *offset = 0;
+    if (size)   *size = heap !=0 ? heap->virtualSize() : 0;
+    return heap;
+}
+status_t GPURegisterHeap::MemoryHeapRegs::GPUHandle::onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    status_t err = BnMemory::onTransact(code, data, reply, flags);
+    if (err == UNKNOWN_TRANSACTION && code == 1000) {
+        int callingPid = IPCThreadState::self()->getCallingPid();
+        //LOGD("pid %d voluntarily revoking gpu", callingPid);
+        if (callingPid == mOwner) {
+            revokeNotification();
+            // we've revoked the GPU, don't do it again later when we
+            // are destroyed.
+            mGPU.clear();
+        } else {
+            LOGW("%d revoking someone else's gpu? (owner=%d)",
+                    callingPid, mOwner);            
+        }
+        err = NO_ERROR;
+    }
+    return err;
+}
+
+// ---------------------------------------------------------------------------
+
+
+sp<MemoryHeapPmem::MemoryPmem> GPURegisterHeap::MemoryHeapRegs::createMemory(
+        size_t offset, size_t size)
+{
+    sp<GPUHandle> memory;
+    sp<GPUHardware> gpu = mGPU.promote();
+    if (heapID()>0 && gpu!=0) {
+#if HAVE_ANDROID_OS
+        /* this is where the GPU is powered on and the registers are mapped
+         * in the client */
+        //LOGD("ioctl(HW3D_GRANT_GPU)");
+        int err = ioctl(heapID(), HW3D_GRANT_GPU, base());
+        if (err) {
+            // it can happen if the master heap has been closed already
+            // in which case the GPU already is revoked (app crash for
+            // instance).
+            LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
+                    strerror(errno), heapID(), base());
+        }
+        memory = new GPUHandle(gpu, this);
+#endif
+    }
+    return memory;
+}
+
+void GPURegisterHeap::MemoryHeapRegs::revoke() 
+{
+    MemoryHeapPmem::revoke();
+#if HAVE_ANDROID_OS
+    if (heapID() > 0) {
+        //LOGD("ioctl(HW3D_REVOKE_GPU)");
+        int err = ioctl(heapID(), HW3D_REVOKE_GPU, base());
+        LOGE_IF(err, "HW3D_REVOKE_GPU failed (%s), mFD=%d, base=%p",
+                strerror(errno), heapID(), base());
+    }
+#endif
+}
+
+/*****************************************************************************/
+
+GPUHardware::GPUHardware()
+    : mOwner(NO_OWNER)
+{
+}
+
+GPUHardware::~GPUHardware()
+{
+}
+
+status_t GPUHardware::requestLocked(int pid)
+{
+    const int self_pid = getpid();
+    if (pid == self_pid) {
+        // can't use GPU from surfaceflinger's process
+        return PERMISSION_DENIED;
+    }
+
+    if (mOwner != pid) {
+        if (mREGHeap != 0) {
+            if (mOwner != NO_OWNER) {
+                // someone already has the gpu.
+                takeBackGPULocked();
+                releaseLocked();
+            }
+        } else {
+            // first time, initialize the stuff.
+            if (mSMIHeap == 0)
+                mSMIHeap = new GPUAreaHeap(this, "/dev/pmem_gpu0");
+            if (mEBIHeap == 0)
+                mEBIHeap = new GPUAreaHeap(this, 
+                        "/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE);
+            mREGHeap = new GPURegisterHeap(this);
+            mAllocator = mEBIHeap->getAllocator();
+            if (mAllocator == NULL) {
+                // something went terribly wrong.
+                mSMIHeap.clear();
+                mEBIHeap.clear();
+                mREGHeap.clear();
+                return INVALID_OPERATION;
+            }
+        }
+        Client& client = getClientLocked(pid);
+        mCurrentAllocator = new MemoryDealer(client.ebi.clientHeap, mAllocator);
+        mOwner = pid;
+    }
+    return NO_ERROR;
+}
+
+sp<MemoryDealer> GPUHardware::request(int pid)
+{
+    sp<MemoryDealer> dealer;
+    Mutex::Autolock _l(mLock);
+    Client* client;
+    LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
+    if (requestLocked(pid) == NO_ERROR) {
+        dealer = mCurrentAllocator;
+        LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
+    }
+    return dealer;
+}
+
+status_t GPUHardware::request(int pid, const sp<IGPUCallback>& callback,
+        ISurfaceComposer::gpu_info_t* gpu)
+{
+    if (callback == 0)
+        return BAD_VALUE;
+
+    sp<IMemory> gpuHandle;
+    LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
+    Mutex::Autolock _l(mLock);
+    status_t err = requestLocked(pid);
+    if (err == NO_ERROR) {
+        // it's guaranteed to be there, be construction
+        Client& client = mClients.editValueFor(pid);
+        registerCallbackLocked(callback, client);
+        gpu->count = 2;
+        gpu->regions[0].region = client.smi.map();
+        gpu->regions[1].region = client.ebi.map();
+        gpu->regs              = client.reg.map();
+        gpu->regions[0].reserved = 0;
+        gpu->regions[1].reserved = GPU_RESERVED_SIZE;
+        if (gpu->regs != 0) {
+            //LOGD("gpu core granted to pid %d, handle base=%p",
+            //        mOwner, gpu->regs->pointer());
+        }
+        mCallback = callback;
+    } else {
+        LOGW("couldn't grant gpu core to pid %d", pid);
+    }
+    return err;
+}
+
+void GPUHardware::revoke(int pid)
+{
+    Mutex::Autolock _l(mLock);
+    if (mOwner > 0) {
+        if (pid != mOwner) {
+            LOGW("GPU owned by %d, revoke from %d", mOwner, pid);
+            return;
+        }
+        //LOGD("revoke pid=%d, owner=%d", pid, mOwner);
+        // mOwner could be <0 if the same process acquired the GPU
+        // several times without releasing it first.
+        mCondition.signal();
+        releaseLocked();
+    }
+}
+
+status_t GPUHardware::friendlyRevoke()
+{
+    Mutex::Autolock _l(mLock);
+    //LOGD("friendlyRevoke owner=%d", mOwner);
+    takeBackGPULocked();
+    releaseLocked();
+    return NO_ERROR;
+}
+
+void GPUHardware::takeBackGPULocked()
+{
+    sp<IGPUCallback> callback = mCallback;
+    mCallback.clear();
+    if (callback != 0) {
+        callback->gpuLost(); // one-way
+        mCondition.waitRelative(mLock, ms2ns(250));
+    }
+}
+
+void GPUHardware::releaseLocked()
+{
+    //LOGD("revoking gpu from pid %d", mOwner);
+    if (mOwner != NO_OWNER) {
+        // this may fail because the client might have died, and have
+        // been removed from the list.
+        ssize_t index = mClients.indexOfKey(mOwner);
+        if (index >= 0) {
+            Client& client(mClients.editValueAt(index));
+            client.revokeAllHeaps();
+        }
+        mOwner = NO_OWNER;
+        mCurrentAllocator.clear();
+        mCallback.clear();
+    }
+}
+
+GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid)
+{
+    ssize_t index = mClients.indexOfKey(pid);
+    if (index < 0) {
+        Client client;
+        client.pid = pid;
+        client.smi.heap = mSMIHeap;
+        client.ebi.heap = mEBIHeap;
+        client.reg.heap = mREGHeap;
+        index = mClients.add(pid, client);
+    }
+    Client& client(mClients.editValueAt(index));
+    client.createClientHeaps();
+    return client;
+}
+
+// ----------------------------------------------------------------------------
+// for debugging / testing ...
+
+sp<SimpleBestFitAllocator> GPUHardware::getAllocator() const {
+    Mutex::Autolock _l(mLock);
+    return mAllocator;
+}
+
+void GPUHardware::unconditionalRevoke()
+{
+    Mutex::Autolock _l(mLock);
+    releaseLocked();
+}
+
+// ---------------------------------------------------------------------------
+
+sp<IMemory> GPUHardware::GPUArea::map() {
+    sp<IMemory> memory;
+    if (clientHeap != 0 && heap != 0) {
+        memory = clientHeap->mapMemory(0, heap->virtualSize());
+    }
+    return memory;
+}
+
+void GPUHardware::Client::createClientHeaps() 
+{
+    if (smi.clientHeap == 0)
+        smi.clientHeap = smi.heap->createClientHeap();
+    if (ebi.clientHeap == 0)
+        ebi.clientHeap = ebi.heap->createClientHeap();
+    if (reg.clientHeap == 0)
+        reg.clientHeap = reg.heap->createClientHeap();
+}
+
+void GPUHardware::Client::revokeAllHeaps() 
+{
+    if (smi.clientHeap != 0)
+        smi.clientHeap->revoke();
+    if (ebi.clientHeap != 0)
+        ebi.clientHeap->revoke();
+    if (reg.clientHeap != 0)
+        reg.clientHeap->revoke();
+}
+
+void GPUHardware::registerCallbackLocked(const sp<IGPUCallback>& callback,
+        Client& client)
+{
+    sp<IBinder> binder = callback->asBinder();
+    if (mRegisteredClients.add(binder, client.pid) >= 0) {
+        binder->linkToDeath(this);
+    }
+}
+
+void GPUHardware::binderDied(const wp<IBinder>& who)
+{
+    Mutex::Autolock _l(mLock);
+    pid_t pid = mRegisteredClients.valueFor(who);
+    if (pid != 0) {
+        ssize_t index = mClients.indexOfKey(pid);
+        if (index >= 0) {
+            //LOGD("*** removing client at %d", index);
+            Client& client(mClients.editValueAt(index));
+            client.revokeAllHeaps(); // not really needed in theory
+            mClients.removeItemsAt(index);
+            if (mClients.size() == 0) {
+                //LOGD("*** was last client closing everything");
+                mCallback.clear();
+                mAllocator.clear();
+                mCurrentAllocator.clear();
+                mSMIHeap.clear();
+                mREGHeap.clear();
+                
+                // NOTE: we cannot clear the EBI heap because surfaceflinger
+                // itself may be using it, since this is where surfaces
+                // are allocated. if we're in the middle of compositing 
+                // a surface (even if its process just died), we cannot
+                // rip the heap under our feet.
+                
+                mOwner = NO_OWNER;
+            }
+        }
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+sp<GPUHardwareInterface> GPUFactory::getGPU()
+{
+    return new GPUHardware();
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.h b/libs/surfaceflinger/GPUHardware/GPUHardware.h
new file mode 100644
index 0000000..3354528
--- /dev/null
+++ b/libs/surfaceflinger/GPUHardware/GPUHardware.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GPU_HARDWARE_H
+#define ANDROID_GPU_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+#include <ui/ISurfaceComposer.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class IGPUCallback;
+
+class GPUHardwareInterface : public virtual RefBase
+{
+public:
+    virtual void                revoke(int pid) = 0;
+    virtual sp<MemoryDealer>    request(int pid) = 0;
+    virtual status_t            request(int pid, const sp<IGPUCallback>& callback,
+            ISurfaceComposer::gpu_info_t* gpu) = 0;
+
+    virtual status_t            friendlyRevoke() = 0;
+    
+    // used for debugging only...
+    virtual sp<SimpleBestFitAllocator> getAllocator() const  = 0;
+    virtual pid_t getOwner() const = 0;
+    virtual void unconditionalRevoke() = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+class GPUFactory
+{    
+public:
+    // the gpu factory
+    static sp<GPUHardwareInterface> getGPU();
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GPU_HARDWARE_H
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
new file mode 100644
index 0000000..f65d669
--- /dev/null
+++ b/libs/surfaceflinger/Layer.cpp
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/properties.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/StopWatch.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/EGLDisplaySurface.h>
+
+#include "clz.h"
+#include "Layer.h"
+#include "LayerBitmap.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+
+#define DEBUG_RESIZE    0
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+const uint32_t Layer::typeInfo = LayerBaseClient::typeInfo | 4;
+const char* const Layer::typeID = "Layer";
+
+// ---------------------------------------------------------------------------
+
+Layer::Layer(SurfaceFlinger* flinger, DisplayID display, Client* c, int32_t i)
+    :   LayerBaseClient(flinger, display, c, i),
+        mSecure(false),
+        mFrontBufferIndex(1),
+        mNeedsBlending(true),
+        mResizeTransactionDone(false),
+        mTextureName(-1U), mTextureWidth(0), mTextureHeight(0)
+{
+    // no OpenGL operation is possible here, since we might not be
+    // in the OpenGL thread.
+}
+
+Layer::~Layer()
+{
+    client->free(clientIndex());
+    // this should always be called from the OpenGL thread
+    if (mTextureName != -1U) {
+        //glDeleteTextures(1, &mTextureName);
+        deletedTextures.add(mTextureName);
+    }
+}
+
+void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags)
+{
+    LayerBase::initStates(w,h,flags);
+
+    if (flags & ISurfaceComposer::eDestroyBackbuffer)
+        lcblk->flags |= eNoCopyBack;
+}
+
+sp<LayerBaseClient::Surface> Layer::getSurface() const
+{
+    return mSurface;
+}
+
+status_t Layer::setBuffers( Client* client,
+                            uint32_t w, uint32_t h,
+                            PixelFormat format, uint32_t flags)
+{
+    PixelFormatInfo info;
+    status_t err = getPixelFormatInfo(format, &info);
+    if (err) return err;
+
+    // TODO: if eHardware is explicitly requested, we should fail
+    // on systems where we can't allocate memory that can be used with
+    // DMA engines for instance.
+    
+    // FIXME: we always ask for hardware for now (this should come from copybit)
+    flags |= ISurfaceComposer::eHardware;
+
+    const uint32_t memory_flags = flags & 
+            (ISurfaceComposer::eGPU | 
+             ISurfaceComposer::eHardware | 
+             ISurfaceComposer::eSecure);
+    
+    // pixel-alignment. the final alignment may be bigger because
+    // we always force a 4-byte aligned bpr.
+    uint32_t alignment = 1;
+
+    if (flags & ISurfaceComposer::eGPU) {
+        // FIXME: this value should come from the h/w
+        alignment = 8; 
+        // FIXME: this is msm7201A specific, as its GPU only supports
+        // BGRA_8888.
+        if (format == PIXEL_FORMAT_RGBA_8888) {
+            format = PIXEL_FORMAT_BGRA_8888;
+        }
+    }
+
+    mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
+    mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
+    sp<MemoryDealer> allocators[2];
+    for (int i=0 ; i<2 ; i++) {
+        allocators[i] = client->createAllocator(memory_flags);
+        if (allocators[i] == 0)
+            return NO_MEMORY;
+        mBuffers[i].init(allocators[i]);
+        int err = mBuffers[i].setBits(w, h, alignment, format, LayerBitmap::SECURE_BITS);
+        if (err != NO_ERROR)
+            return err;
+        mBuffers[i].clear(); // clear the bits for security
+        mBuffers[i].getInfo(lcblk->surface + i);
+    }
+
+    mSurface = new Surface(clientIndex(),
+            allocators[0]->getMemoryHeap(),
+            allocators[1]->getMemoryHeap(),
+            mIdentity);
+
+    return NO_ERROR;
+}
+
+void Layer::reloadTexture(const Region& dirty)
+{
+    if (UNLIKELY(mTextureName == -1U)) {
+        // create the texture name the first time
+        // can't do that in the ctor, because it runs in another thread.
+        mTextureName = createTexture();
+    }
+    const GGLSurface& t(frontBuffer().surface());
+    loadTexture(dirty, mTextureName, t, mTextureWidth, mTextureHeight);
+}
+
+
+void Layer::onDraw(const Region& clip) const
+{
+    if (UNLIKELY(mTextureName == -1LU)) {
+        //LOGW("Layer %p doesn't have a texture", this);
+        // the texture has not been created yet, this Layer has
+        // in fact never been drawn into. this happens frequently with
+        // SurfaceView.
+        clearWithOpenGL(clip);
+        return;
+    }
+
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    const LayerBitmap& front(frontBuffer());
+    const GGLSurface& t(front.surface());
+
+    status_t err = NO_ERROR;
+    const int can_use_copybit = canUseCopybit();
+    if (can_use_copybit)  {
+        // StopWatch watch("copybit");
+        const State& s(drawingState());
+
+        copybit_image_t dst;
+        hw.getDisplaySurface(&dst);
+        const copybit_rect_t& drect
+            = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
+
+        copybit_image_t src;
+        front.getBitmapSurface(&src);
+        copybit_rect_t srect = { 0, 0, t.width, t.height };
+
+        copybit_device_t* copybit = mFlinger->getBlitEngine();
+        copybit->set_parameter(copybit, COPYBIT_TRANSFORM, getOrientation());
+        copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+        copybit->set_parameter(copybit, COPYBIT_DITHER,
+                s.flags & ISurfaceComposer::eLayerDither ?
+                        COPYBIT_ENABLE : COPYBIT_DISABLE);
+
+        region_iterator it(clip);
+        err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+    }
+
+    if (!can_use_copybit || err) {
+        drawWithOpenGL(clip, mTextureName, t);
+    }
+}
+
+status_t Layer::reallocateBuffer(int32_t index, uint32_t w, uint32_t h)
+{
+    LOGD_IF(DEBUG_RESIZE,
+                "reallocateBuffer (layer=%p), "
+                "requested (%dx%d), "
+                "index=%d, (%dx%d), (%dx%d)",
+                this,
+                int(w), int(h),
+                int(index),
+                int(mBuffers[0].width()), int(mBuffers[0].height()),
+                int(mBuffers[1].width()), int(mBuffers[1].height()));
+
+    status_t err = mBuffers[index].resize(w, h);
+    if (err == NO_ERROR) {
+        mBuffers[index].getInfo(lcblk->surface + index);
+    } else {
+        LOGE("resizing buffer %d to (%u,%u) failed [%08x] %s",
+            index, w, h, err, strerror(err));
+        // XXX: what to do, what to do? We could try to free some
+        // hidden surfaces, instead of killing this one?
+    }
+    return err;
+}
+
+uint32_t Layer::doTransaction(uint32_t flags)
+{
+    const Layer::State& front(drawingState());
+    const Layer::State& temp(currentState());
+
+    // the test front.{w|h} != temp.{w|h} is not enough because it is possible
+    // that the size changed back to its previous value before the buffer
+    // was resized (in the eLocked case below), in which case, we still
+    // need to execute the code below so the clients have a chance to be
+    // release. resze() deals with the fact that the size can be the same.
+
+    /*
+     *  Various states we could be in...
+
+         resize = state & eResizeRequested;
+         if (backbufferChanged) {
+             if (resize == 0) {
+                 // ERROR, the resized buffer doesn't have its resize flag set
+             } else if (resize == mask) {
+                 // ERROR one of the buffer has already been resized
+             } else if (resize == mask ^ eResizeRequested) {
+                 // ERROR, the resized buffer doesn't have its resize flag set
+             } else if (resize == eResizeRequested) {
+                 // OK, Normal case, proceed with resize
+             }
+         } else {
+             if (resize == 0) {
+                 // OK, nothing special, do nothing
+             } else if (resize == mask) {
+                 // restarted transaction, do nothing
+             } else if (resize == mask ^ eResizeRequested) {
+                 // restarted transaction, do nothing
+             } else if (resize == eResizeRequested) {
+                 // OK, size reset to previous value, proceed with resize
+             }
+         }
+     */
+
+    // Index of the back buffer
+    const bool backbufferChanged = (front.w != temp.w) || (front.h != temp.h);
+    const uint32_t state = lcblk->swapState;
+    const int32_t clientBackBufferIndex = layer_cblk_t::backBuffer(state);
+    const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0;
+    uint32_t resizeFlags = state & eResizeRequested;
+
+    if (UNLIKELY(backbufferChanged && (resizeFlags != eResizeRequested))) {
+        LOGE(   "backbuffer size changed, but both resize flags are not set! "
+                "(layer=%p), state=%08x, requested (%dx%d), drawing (%d,%d), "
+                "index=%d, (%dx%d), (%dx%d)",
+                this,  state,
+                int(temp.w), int(temp.h),
+                int(drawingState().w), int(drawingState().h),
+                int(clientBackBufferIndex),
+                int(mBuffers[0].width()), int(mBuffers[0].height()),
+                int(mBuffers[1].width()), int(mBuffers[1].height()));
+        // if we get there we're pretty screwed. the only reasonable
+        // thing to do is to pretend we should do the resize since
+        // backbufferChanged is set (this also will give a chance to
+        // client to get unblocked)
+        resizeFlags = eResizeRequested;
+    }
+
+    if (resizeFlags == eResizeRequested)  {
+        // NOTE: asserting that clientBackBufferIndex!=mFrontBufferIndex
+        // here, would be wrong and misleading because by this point
+        // mFrontBufferIndex has not been updated yet.
+
+        LOGD_IF(DEBUG_RESIZE,
+                    "resize (layer=%p), state=%08x, "
+                    "requested (%dx%d), "
+                    "drawing (%d,%d), "
+                    "index=%d, (%dx%d), (%dx%d)",
+                    this,  state,
+                    int(temp.w), int(temp.h),
+                    int(drawingState().w), int(drawingState().h),
+                    int(clientBackBufferIndex),
+                    int(mBuffers[0].width()), int(mBuffers[0].height()),
+                    int(mBuffers[1].width()), int(mBuffers[1].height()));
+
+        if (state & eLocked) {
+            // if the buffer is locked, we can't resize anything because
+            // - the backbuffer is currently in use by the user
+            // - the front buffer is being shown
+            // We just act as if the transaction didn't happen and we
+            // reschedule it later...
+            flags |= eRestartTransaction;
+        } else {
+            // This buffer needs to be resized
+            status_t err =
+                resize(clientBackBufferIndex, temp.w, temp.h, "transaction");
+            if (err == NO_ERROR) {
+                const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0;
+                android_atomic_and(~mask, &(lcblk->swapState));
+                // since a buffer became available, we can let the client go...
+                mFlinger->scheduleBroadcast(client);
+                mResizeTransactionDone = true;
+
+                // we're being resized and there is a freeze display request,
+                // acquire a freeze lock, so that the screen stays put
+                // until we've redrawn at the new size; this is to avoid
+                // glitches upon orientation changes.
+                if (mFlinger->hasFreezeRequest()) {
+                    // if the surface is hidden, don't try to acquire the
+                    // freeze lock, since hidden surfaces may never redraw
+                    if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
+                        mFreezeLock = mFlinger->getFreezeLock();
+                    }
+                }
+            }
+        }
+    }
+    
+    if (temp.sequence != front.sequence) {
+        if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) {
+            // this surface is now hidden, so it shouldn't hold a freeze lock
+            // (it may never redraw, which is fine if it is hidden)
+            mFreezeLock.clear();
+        }
+    }
+        
+    return LayerBase::doTransaction(flags);
+}
+
+status_t Layer::resize(
+        int32_t clientBackBufferIndex,
+        uint32_t width, uint32_t height,
+        const char* what)
+{
+    /*
+     * handle resize (backbuffer and frontbuffer reallocation)
+     */
+
+    const LayerBitmap& clientBackBuffer(mBuffers[clientBackBufferIndex]);
+
+    // if the new (transaction) size is != from the the backbuffer
+    // then we need to reallocate the backbuffer
+    bool backbufferChanged = (clientBackBuffer.width()  != width) ||
+                             (clientBackBuffer.height() != height);
+
+    LOGD_IF(!backbufferChanged,
+            "(%s) eResizeRequested (layer=%p), but size not changed: "
+            "requested (%dx%d), drawing (%d,%d), current (%d,%d),"
+            "state=%08lx, index=%d, (%dx%d), (%dx%d)",
+            what, this,
+            int(width), int(height),
+            int(drawingState().w), int(drawingState().h),
+            int(currentState().w), int(currentState().h),
+            long(lcblk->swapState),
+            int(clientBackBufferIndex),
+            int(mBuffers[0].width()), int(mBuffers[0].height()),
+            int(mBuffers[1].width()), int(mBuffers[1].height()));
+
+    // this can happen when changing the size back and forth quickly
+    status_t err = NO_ERROR;
+    if (backbufferChanged) {
+        err = reallocateBuffer(clientBackBufferIndex, width, height);
+    }
+    if (UNLIKELY(err != NO_ERROR)) {
+        // couldn't reallocate the surface
+        android_atomic_write(eInvalidSurface, &lcblk->swapState);
+        memset(lcblk->surface+clientBackBufferIndex, 0, sizeof(surface_info_t));
+    }
+    return err;
+}
+
+void Layer::setSizeChanged(uint32_t w, uint32_t h)
+{
+    LOGD_IF(DEBUG_RESIZE,
+            "setSizeChanged w=%d, h=%d (old: w=%d, h=%d)",
+            w, h, mCurrentState.w, mCurrentState.h);
+    android_atomic_or(eResizeRequested, &(lcblk->swapState));
+}
+
+// ----------------------------------------------------------------------------
+// pageflip handling...
+// ----------------------------------------------------------------------------
+
+void Layer::lockPageFlip(bool& recomputeVisibleRegions)
+{
+    uint32_t state = android_atomic_or(eBusy, &(lcblk->swapState));
+    // preemptively block the client, because he might set
+    // eFlipRequested at any time and want to use this buffer
+    // for the next frame. This will be unset below if it
+    // turns out we didn't need it.
+
+    uint32_t mask = eInvalidSurface | eFlipRequested | eResizeRequested;
+    if (!(state & mask))
+        return;
+
+    if (UNLIKELY(state & eInvalidSurface)) {
+        // if eInvalidSurface is set, this means the surface
+        // became invalid during a transaction (NO_MEMORY for instance)
+        mFlinger->scheduleBroadcast(client);
+        return;
+    }
+
+    if (UNLIKELY(state & eFlipRequested)) {
+        uint32_t oldState;
+        mPostedDirtyRegion = post(&oldState, recomputeVisibleRegions);
+        if (oldState & eNextFlipPending) {
+            // Process another round (we know at least a buffer
+            // is ready for that client).
+            mFlinger->signalEvent();
+        }
+    }
+}
+
+Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions)
+{
+    // atomically swap buffers and (re)set eFlipRequested
+    int32_t oldValue, newValue;
+    layer_cblk_t * const lcblk = this->lcblk;
+    do {
+        oldValue = lcblk->swapState;
+            // get the current value
+
+        LOG_ASSERT(oldValue&eFlipRequested,
+            "eFlipRequested not set, yet we're flipping! (state=0x%08lx)",
+            long(oldValue));
+
+        newValue = (oldValue ^ eIndex);
+            // swap buffers
+
+        newValue &= ~(eFlipRequested | eNextFlipPending);
+            // clear eFlipRequested and eNextFlipPending
+
+        if (oldValue & eNextFlipPending)
+            newValue |= eFlipRequested;
+            // if eNextFlipPending is set (second buffer already has something
+            // in it) we need to reset eFlipRequested because the client
+            // might never do it
+
+    } while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
+    *previousSate = oldValue;
+
+    const int32_t index = (newValue & eIndex) ^ 1;
+    mFrontBufferIndex = index;
+
+    // ... post the new front-buffer
+    Region dirty(lcblk->region + index);
+    dirty.andSelf(frontBuffer().bounds());
+
+    //LOGI("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n",
+    //    oldValue, newValue, mFrontBufferIndex);
+    //dirty.dump("dirty");
+
+    if (UNLIKELY(oldValue & eResizeRequested)) {
+
+        LOGD_IF(DEBUG_RESIZE,
+                     "post (layer=%p), state=%08x, "
+                     "index=%d, (%dx%d), (%dx%d)",
+                     this,  newValue,
+                     int(1-index),
+                     int(mBuffers[0].width()), int(mBuffers[0].height()),
+                     int(mBuffers[1].width()), int(mBuffers[1].height()));
+
+        // here, we just posted the surface and we have resolved
+        // the front/back buffer indices. The client is blocked, so
+        // it cannot start using the new backbuffer.
+
+        // If the backbuffer was resized in THIS round, we actually cannot
+        // resize the frontbuffer because it has *just* been drawn (and we
+        // would have nothing to draw). In this case we just skip the resize
+        // it'll happen after the next page flip or during the next
+        // transaction.
+
+        const uint32_t mask = (1-index) ? eResizeBuffer1 : eResizeBuffer0;
+        if (mResizeTransactionDone && (newValue & mask)) {
+            // Resize the layer's second buffer only if the transaction
+            // happened. It may not have happened yet if eResizeRequested
+            // was set immediately after the "transactionRequested" test,
+            // in which case the drawing state's size would be wrong.
+            mFreezeLock.clear();
+            const Layer::State& s(drawingState());
+            if (resize(1-index, s.w, s.h, "post") == NO_ERROR) {
+                do {
+                    oldValue = lcblk->swapState;
+                    if ((oldValue & eResizeRequested) == eResizeRequested) {
+                        // ugh, another resize was requested since we processed
+                        // the first buffer, don't free the client, and let
+                        // the next transaction handle everything.
+                        break;
+                    }
+                    newValue = oldValue & ~mask;
+                } while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
+            }
+            mResizeTransactionDone = false;
+            recomputeVisibleRegions = true;
+            this->contentDirty = true;
+        }
+    }
+
+    reloadTexture(dirty);
+
+    return dirty;
+}
+
+Point Layer::getPhysicalSize() const
+{
+    const LayerBitmap& front(frontBuffer());
+    return Point(front.width(), front.height());
+}
+
+void Layer::unlockPageFlip(
+        const Transform& planeTransform, Region& outDirtyRegion)
+{
+    Region dirtyRegion(mPostedDirtyRegion);
+    if (!dirtyRegion.isEmpty()) {
+        mPostedDirtyRegion.clear();
+        // The dirty region is given in the layer's coordinate space
+        // transform the dirty region by the surface's transformation
+        // and the global transformation.
+        const Layer::State& s(drawingState());
+        const Transform tr(planeTransform * s.transform);
+        dirtyRegion = tr.transform(dirtyRegion);
+
+        // At this point, the dirty region is in screen space.
+        // Make sure it's constrained by the visible region (which
+        // is in screen space as well).
+        dirtyRegion.andSelf(visibleRegionScreen);
+        outDirtyRegion.orSelf(dirtyRegion);
+
+        // client could be blocked, so signal them so they get a
+        // chance to reevaluate their condition.
+        mFlinger->scheduleBroadcast(client);
+    }
+}
+
+void Layer::finishPageFlip()
+{
+    if (LIKELY(!(lcblk->swapState & eInvalidSurface))) {
+        LOGE_IF(!(lcblk->swapState & eBusy),
+                "layer %p wasn't locked!", this);
+        android_atomic_and(~eBusy, &(lcblk->swapState));
+    }
+    mFlinger->scheduleBroadcast(client);
+}
+
+
+// ---------------------------------------------------------------------------
+
+
+}; // namespace android
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
new file mode 100644
index 0000000..2867f2b
--- /dev/null
+++ b/libs/surfaceflinger/Layer.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_LAYER_H
+#define ANDROID_LAYER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/PixelFormat.h>
+
+#include <private/ui/SharedState.h>
+#include <private/ui/LayerState.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "LayerBitmap.h"
+#include "LayerBase.h"
+#include "Transform.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Client;
+class LayerBitmap;
+class MemoryDealer;
+class FreezeLock;
+
+// ---------------------------------------------------------------------------
+
+class Layer : public LayerBaseClient
+{
+public:    
+    static const uint32_t typeInfo;
+    static const char* const typeID;
+    virtual char const* getTypeID() const { return typeID; }
+    virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+                 Layer(SurfaceFlinger* flinger, DisplayID display,
+                         Client* c, int32_t i);
+
+        virtual ~Layer();
+
+    inline PixelFormat pixelFormat() const {
+        return frontBuffer().pixelFormat();
+    }
+
+    status_t setBuffers(    Client* client,
+                            uint32_t w, uint32_t h,
+                            PixelFormat format, uint32_t flags=0);
+
+    virtual void onDraw(const Region& clip) const;
+    virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
+    virtual void setSizeChanged(uint32_t w, uint32_t h);
+    virtual uint32_t doTransaction(uint32_t transactionFlags);
+    virtual Point getPhysicalSize() const;
+    virtual void lockPageFlip(bool& recomputeVisibleRegions);
+    virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+    virtual void finishPageFlip();
+    virtual bool needsBlending() const      { return mNeedsBlending; }
+    virtual bool isSecure() const           { return mSecure; }
+    virtual GLuint getTextureName() const   { return mTextureName; }
+    virtual sp<Surface> getSurface() const;
+
+    const LayerBitmap& getBuffer(int i) const { return mBuffers[i]; }
+          LayerBitmap& getBuffer(int i)       { return mBuffers[i]; }
+
+    // only for debugging
+    const sp<FreezeLock>&  getFreezeLock() const { return mFreezeLock; }
+
+private:
+    inline const LayerBitmap&
+            frontBuffer() const { return getBuffer(mFrontBufferIndex); }
+    inline LayerBitmap&
+            frontBuffer()       { return getBuffer(mFrontBufferIndex); }
+    inline const LayerBitmap&
+            backBuffer() const  { return getBuffer(1-mFrontBufferIndex); }
+    inline LayerBitmap&
+            backBuffer()        { return getBuffer(1-mFrontBufferIndex); }
+
+    void reloadTexture(const Region& dirty);
+
+    status_t resize(int32_t index, uint32_t w, uint32_t h, const char* what);
+    Region post(uint32_t* oldState, bool& recomputeVisibleRegions);
+    status_t reallocateBuffer(int32_t index, uint32_t w, uint32_t h);
+
+    sp<Surface>             mSurface;
+
+            bool            mSecure;
+            LayerBitmap     mBuffers[2];
+            int32_t         mFrontBufferIndex;
+            bool            mNeedsBlending;
+            bool            mResizeTransactionDone;
+            Region          mPostedDirtyRegion;
+            sp<FreezeLock>  mFreezeLock;
+            
+            GLuint          mTextureName;
+            GLuint          mTextureWidth;
+            GLuint          mTextureHeight;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_H
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
new file mode 100644
index 0000000..0cf53f7
--- /dev/null
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -0,0 +1,740 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <hardware/hardware.h>
+
+#include "clz.h"
+#include "LayerBase.h"
+#include "LayerBlur.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+
+// We don't honor the premultiplied alpha flags, which means that
+// premultiplied surface may be composed using a non-premultiplied
+// equation. We do this because it may be a lot faster on some hardware
+// The correct value is HONOR_PREMULTIPLIED_ALPHA = 1
+#define HONOR_PREMULTIPLIED_ALPHA   0
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerBase::typeInfo = 1;
+const char* const LayerBase::typeID = "LayerBase";
+
+const uint32_t LayerBaseClient::typeInfo = LayerBase::typeInfo | 2;
+const char* const LayerBaseClient::typeID = "LayerBaseClient";
+
+// ---------------------------------------------------------------------------
+
+Vector<GLuint> LayerBase::deletedTextures; 
+
+int32_t LayerBase::sIdentity = 0;
+
+LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
+    : dpy(display), contentDirty(false),
+      mFlinger(flinger),
+      mTransformed(false),
+      mOrientation(0),
+      mCanUseCopyBit(false),
+      mTransactionFlags(0),
+      mPremultipliedAlpha(true),
+      mIdentity(uint32_t(android_atomic_inc(&sIdentity))),
+      mInvalidate(0)
+{
+    const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
+    mFlags = hw.getFlags();
+}
+
+LayerBase::~LayerBase()
+{
+}
+
+const GraphicPlane& LayerBase::graphicPlane(int dpy) const
+{ 
+    return mFlinger->graphicPlane(dpy);
+}
+
+GraphicPlane& LayerBase::graphicPlane(int dpy)
+{
+    return mFlinger->graphicPlane(dpy); 
+}
+
+void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags)
+{
+    uint32_t layerFlags = 0;
+    if (flags & ISurfaceComposer::eHidden)
+        layerFlags = ISurfaceComposer::eLayerHidden;
+
+    if (flags & ISurfaceComposer::eNonPremultiplied)
+        mPremultipliedAlpha = false;
+
+    mCurrentState.z         = 0;
+    mCurrentState.w         = w;
+    mCurrentState.h         = h;
+    mCurrentState.alpha     = 0xFF;
+    mCurrentState.flags     = layerFlags;
+    mCurrentState.sequence  = 0;
+    mCurrentState.transform.set(0, 0);
+
+    // drawing state & current state are identical
+    mDrawingState = mCurrentState;
+}
+
+void LayerBase::commitTransaction(bool skipSize) {
+    const uint32_t w = mDrawingState.w;
+    const uint32_t h = mDrawingState.h;
+    mDrawingState = mCurrentState;
+    if (skipSize) {
+        mDrawingState.w = w;
+        mDrawingState.h = h;
+    }
+}
+void LayerBase::forceVisibilityTransaction() {
+    // this can be called without SurfaceFlinger.mStateLock, but if we
+    // can atomically increment the sequence number, it doesn't matter.
+    android_atomic_inc(&mCurrentState.sequence);
+    requestTransaction();
+}
+bool LayerBase::requestTransaction() {
+    int32_t old = setTransactionFlags(eTransactionNeeded);
+    return ((old & eTransactionNeeded) == 0);
+}
+uint32_t LayerBase::getTransactionFlags(uint32_t flags) {
+    return android_atomic_and(~flags, &mTransactionFlags) & flags;
+}
+uint32_t LayerBase::setTransactionFlags(uint32_t flags) {
+    return android_atomic_or(flags, &mTransactionFlags);
+}
+
+void LayerBase::setSizeChanged(uint32_t w, uint32_t h) {
+}
+
+bool LayerBase::setPosition(int32_t x, int32_t y) {
+    if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
+        return false;
+    mCurrentState.sequence++;
+    mCurrentState.transform.set(x, y);
+    requestTransaction();
+    return true;
+}
+bool LayerBase::setLayer(uint32_t z) {
+    if (mCurrentState.z == z)
+        return false;
+    mCurrentState.sequence++;
+    mCurrentState.z = z;
+    requestTransaction();
+    return true;
+}
+bool LayerBase::setSize(uint32_t w, uint32_t h) {
+    if (mCurrentState.w == w && mCurrentState.h == h)
+        return false;
+    setSizeChanged(w, h);
+    mCurrentState.w = w;
+    mCurrentState.h = h;
+    requestTransaction();
+    return true;
+}
+bool LayerBase::setAlpha(uint8_t alpha) {
+    if (mCurrentState.alpha == alpha)
+        return false;
+    mCurrentState.sequence++;
+    mCurrentState.alpha = alpha;
+    requestTransaction();
+    return true;
+}
+bool LayerBase::setMatrix(const layer_state_t::matrix22_t& matrix) {
+    // TODO: check the matrix has changed
+    mCurrentState.sequence++;
+    mCurrentState.transform.set(
+            matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
+    requestTransaction();
+    return true;
+}
+bool LayerBase::setTransparentRegionHint(const Region& transparent) {
+    // TODO: check the region has changed
+    mCurrentState.sequence++;
+    mCurrentState.transparentRegion = transparent;
+    requestTransaction();
+    return true;
+}
+bool LayerBase::setFlags(uint8_t flags, uint8_t mask) {
+    const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
+    if (mCurrentState.flags == newFlags)
+        return false;
+    mCurrentState.sequence++;
+    mCurrentState.flags = newFlags;
+    requestTransaction();
+    return true;
+}
+
+Rect LayerBase::visibleBounds() const
+{
+    return mTransformedBounds;
+}      
+
+void LayerBase::setVisibleRegion(const Region& visibleRegion) {
+    // always called from main thread
+    visibleRegionScreen = visibleRegion;
+}
+
+void LayerBase::setCoveredRegion(const Region& coveredRegion) {
+    // always called from main thread
+    coveredRegionScreen = coveredRegion;
+}
+
+uint32_t LayerBase::doTransaction(uint32_t flags)
+{
+    const Layer::State& front(drawingState());
+    const Layer::State& temp(currentState());
+
+    if (temp.sequence != front.sequence) {
+        // invalidate and recompute the visible regions if needed
+        flags |= eVisibleRegion;
+        this->contentDirty = true;
+    }
+    
+    // Commit the transaction
+    commitTransaction(flags & eRestartTransaction);
+    return flags;
+}
+
+Point LayerBase::getPhysicalSize() const
+{
+    const Layer::State& front(drawingState());
+    return Point(front.w, front.h);
+}
+
+void LayerBase::validateVisibility(const Transform& planeTransform)
+{
+    const Layer::State& s(drawingState());
+    const Transform tr(planeTransform * s.transform);
+    const bool transformed = tr.transformed();
+   
+    const Point size(getPhysicalSize());
+    uint32_t w = size.x;
+    uint32_t h = size.y;    
+    tr.transform(mVertices[0], 0, 0);
+    tr.transform(mVertices[1], 0, h);
+    tr.transform(mVertices[2], w, h);
+    tr.transform(mVertices[3], w, 0);
+    if (UNLIKELY(transformed)) {
+        // NOTE: here we could also punt if we have too many rectangles
+        // in the transparent region
+        if (tr.preserveRects()) {
+            // transform the transparent region
+            transparentRegionScreen = tr.transform(s.transparentRegion);
+        } else {
+            // transformation too complex, can't do the transparent region
+            // optimization.
+            transparentRegionScreen.clear();
+        }
+    } else {
+        transparentRegionScreen = s.transparentRegion;
+    }
+
+    // cache a few things...
+    mOrientation = tr.getOrientation();
+    mTransformedBounds = tr.makeBounds(w, h);
+    mTransformed = transformed;
+    mLeft = tr.tx();
+    mTop  = tr.ty();
+
+    // see if we can/should use 2D h/w with the new configuration
+    mCanUseCopyBit = false;
+    copybit_device_t* copybit = mFlinger->getBlitEngine();
+    if (copybit) { 
+        const int step = copybit->get(copybit, COPYBIT_ROTATION_STEP_DEG);
+        const int scaleBits = copybit->get(copybit, COPYBIT_SCALING_FRAC_BITS);
+        mCanUseCopyBit = true;
+        if ((mOrientation < 0) && (step > 1)) {
+            // arbitrary orientations not supported
+            mCanUseCopyBit = false;
+        } else if ((mOrientation > 0) && (step > 90)) {
+            // 90 deg rotations not supported
+            mCanUseCopyBit = false;
+        } else if ((tr.getType() & SkMatrix::kScale_Mask) && (scaleBits < 12)) { 
+            // arbitrary scaling not supported
+            mCanUseCopyBit = false;
+        }
+#if HONOR_PREMULTIPLIED_ALPHA 
+        else if (needsBlending() && mPremultipliedAlpha) {
+            // pre-multiplied alpha not supported
+            mCanUseCopyBit = false;
+        }
+#endif
+        else {
+            // here, we determined we can use copybit
+            if (tr.getType() & SkMatrix::kScale_Mask) {
+                // and we have scaling
+                if (!transparentRegionScreen.isRect()) {
+                    // we punt because blending is cheap (h/w) and the region is
+                    // complex, which may causes artifacts when copying
+                    // scaled content
+                    transparentRegionScreen.clear();
+                }
+            }
+        }
+    }
+}
+
+void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
+{
+}
+
+void LayerBase::unlockPageFlip(
+        const Transform& planeTransform, Region& outDirtyRegion)
+{
+    if ((android_atomic_and(~1, &mInvalidate)&1) == 1) {
+        outDirtyRegion.orSelf(visibleRegionScreen);
+    }
+}
+
+void LayerBase::finishPageFlip()
+{
+}
+
+void LayerBase::invalidate()
+{
+    if ((android_atomic_or(1, &mInvalidate)&1) == 0) {
+        mFlinger->signalEvent();
+    }
+}
+
+void LayerBase::drawRegion(const Region& reg) const
+{
+    Region::iterator iterator(reg);
+    if (iterator) {
+        Rect r;
+        const DisplayHardware& hw(graphicPlane(0).displayHardware());
+        const int32_t fbWidth  = hw.getWidth();
+        const int32_t fbHeight = hw.getHeight();
+        const GLshort vertices[][2] = { { 0, 0 }, { fbWidth, 0 }, 
+                { fbWidth, fbHeight }, { 0, fbHeight }  };
+        glVertexPointer(2, GL_SHORT, 0, vertices);
+        while (iterator.iterate(&r)) {
+            const GLint sy = fbHeight - (r.top + r.height());
+            glScissor(r.left, sy, r.width(), r.height());
+            glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
+        }
+    }
+}
+
+void LayerBase::draw(const Region& inClip) const
+{
+    // invalidate the region we'll update
+    Region clip(inClip);  // copy-on-write, so no-op most of the time
+
+    // Remove the transparent area from the clipping region
+    const State& s = drawingState();
+    if (LIKELY(!s.transparentRegion.isEmpty())) {
+        clip.subtract(transparentRegionScreen);
+        if (clip.isEmpty()) {
+            // usually this won't happen because this should be taken care of
+            // by SurfaceFlinger::computeVisibleRegions()
+            return;
+        }        
+    }
+
+    // reset GL state
+    glEnable(GL_SCISSOR_TEST);
+
+    onDraw(clip);
+
+    /*
+    glDisable(GL_TEXTURE_2D);
+    glDisable(GL_DITHER);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+    glColor4x(0, 0x8000, 0, 0x10000);
+    drawRegion(transparentRegionScreen);
+    glDisable(GL_BLEND);
+    */
+}
+
+GLuint LayerBase::createTexture() const
+{
+    GLuint textureName = -1;
+    glGenTextures(1, &textureName);
+    glBindTexture(GL_TEXTURE_2D, textureName);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    if (mFlags & DisplayHardware::SLOW_CONFIG) {
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    } else {
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    }
+    return textureName;
+}
+
+void LayerBase::clearWithOpenGL(const Region& clip) const
+{
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    const uint32_t fbHeight = hw.getHeight();
+    glColor4x(0,0,0,0);
+    glDisable(GL_TEXTURE_2D);
+    glDisable(GL_BLEND);
+    glDisable(GL_DITHER);
+    Rect r;
+    Region::iterator iterator(clip);
+    if (iterator) {
+        glEnable(GL_SCISSOR_TEST);
+        glVertexPointer(2, GL_FIXED, 0, mVertices);
+        while (iterator.iterate(&r)) {
+            const GLint sy = fbHeight - (r.top + r.height());
+            glScissor(r.left, sy, r.width(), r.height());
+            glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
+        }
+    }
+}
+
+void LayerBase::drawWithOpenGL(const Region& clip,
+        GLint textureName, const GGLSurface& t, int transform) const
+{
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    const uint32_t fbHeight = hw.getHeight();
+    const State& s(drawingState());
+
+    // bind our texture
+    validateTexture(textureName);
+    glEnable(GL_TEXTURE_2D);
+
+    // Dithering...
+    if (s.flags & ISurfaceComposer::eLayerDither) {
+        glEnable(GL_DITHER);
+    } else {
+        glDisable(GL_DITHER);
+    }
+
+    if (UNLIKELY(s.alpha < 0xFF)) {
+        // We have an alpha-modulation. We need to modulate all
+        // texture components by alpha because we're always using 
+        // premultiplied alpha.
+        
+        // If the texture doesn't have an alpha channel we can
+        // use REPLACE and switch to non premultiplied alpha
+        // blending (SRCA/ONE_MINUS_SRCA).
+        
+        GLenum env, src;
+        if (needsBlending()) {
+            env = GL_MODULATE;
+            src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
+        } else {
+            env = GL_REPLACE;
+            src = GL_SRC_ALPHA;
+        }
+        const GGLfixed alpha = (s.alpha << 16)/255;
+        glColor4x(alpha, alpha, alpha, alpha);
+        glEnable(GL_BLEND);
+        glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
+        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
+    } else {
+        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+        glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
+        if (needsBlending()) {
+            GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
+            glEnable(GL_BLEND);
+            glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
+        } else {
+            glDisable(GL_BLEND);
+        }
+    }
+
+    if (UNLIKELY(transformed()
+            || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) )) 
+    {
+        //StopWatch watch("GL transformed");
+        Region::iterator iterator(clip);
+        if (iterator) {
+            // always use high-quality filtering with fast configurations
+            bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG);
+            if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
+                glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+                glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+            }            
+            const GLfixed texCoords[4][2] = {
+                    { 0,        0 },
+                    { 0,        0x10000 },
+                    { 0x10000,  0x10000 },
+                    { 0x10000,  0 }
+            };
+
+            glMatrixMode(GL_TEXTURE);
+            glLoadIdentity();
+            
+            if (transform == HAL_TRANSFORM_ROT_90) {
+                glTranslatef(0, 1, 0);
+                glRotatef(-90, 0, 0, 1);
+            }
+
+            if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
+                // find the smallest power-of-two that will accommodate our surface
+                GLuint tw = 1 << (31 - clz(t.width));
+                GLuint th = 1 << (31 - clz(t.height));
+                if (tw < t.width)  tw <<= 1;
+                if (th < t.height) th <<= 1;
+                // this divide should be relatively fast because it's
+                // a power-of-two (optimized path in libgcc)
+                GLfloat ws = GLfloat(t.width) /tw;
+                GLfloat hs = GLfloat(t.height)/th;
+                glScalef(ws, hs, 1.0f);
+            }
+
+            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+            glVertexPointer(2, GL_FIXED, 0, mVertices);
+            glTexCoordPointer(2, GL_FIXED, 0, texCoords);
+
+            Rect r;
+            while (iterator.iterate(&r)) {
+                const GLint sy = fbHeight - (r.top + r.height());
+                glScissor(r.left, sy, r.width(), r.height());
+                glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
+            }
+
+            if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
+                glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+                glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+            }
+            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+        }
+    } else {
+        Region::iterator iterator(clip);
+        if (iterator) {
+            Rect r;
+            GLint crop[4] = { 0, t.height, t.width, -t.height };
+            glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+            int x = tx();
+            int y = ty();
+            y = fbHeight - (y + t.height);
+            while (iterator.iterate(&r)) {
+                const GLint sy = fbHeight - (r.top + r.height());
+                glScissor(r.left, sy, r.width(), r.height());
+                glDrawTexiOES(x, y, 0, t.width, t.height);
+            }
+        }
+    }
+}
+
+void LayerBase::validateTexture(GLint textureName) const
+{
+    glBindTexture(GL_TEXTURE_2D, textureName);
+    // TODO: reload the texture if needed
+    // this is currently done in loadTexture() below
+}
+
+void LayerBase::loadTexture(const Region& dirty,
+        GLint textureName, const GGLSurface& t,
+        GLuint& textureWidth, GLuint& textureHeight) const
+{
+    // TODO: defer the actual texture reload until LayerBase::validateTexture
+    // is called.
+
+    uint32_t flags = mFlags;
+    glBindTexture(GL_TEXTURE_2D, textureName);
+
+    GLuint tw = t.width;
+    GLuint th = t.height;
+
+    /*
+     * In OpenGL ES we can't specify a stride with glTexImage2D (however,
+     * GL_UNPACK_ALIGNMENT is 4, which in essence allows a limited form of
+     * stride).
+     * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
+     * need to do something reasonable (here creating a bigger texture).
+     * 
+     * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
+     * 
+     * This situation doesn't happen often, but some h/w have a limitation
+     * for their framebuffer (eg: must be multiple of 8 pixels), and
+     * we need to take that into account when using these buffers as
+     * textures.
+     *
+     * This should never be a problem with POT textures
+     */
+
+    tw += (((t.stride - tw) * bytesPerPixel(t.format)) / 4);
+
+    /*
+     * round to POT if needed 
+     */
+    
+    GLuint texture_w = tw;
+    GLuint texture_h = th;
+    if (!(flags & DisplayHardware::NPOT_EXTENSION)) {
+        // find the smallest power-of-two that will accommodate our surface
+        texture_w = 1 << (31 - clz(t.width));
+        texture_h = 1 << (31 - clz(t.height));
+        if (texture_w < t.width)  texture_w <<= 1;
+        if (texture_h < t.height) texture_h <<= 1;
+        if (texture_w != tw || texture_h != th) {
+            // we can't use DIRECT_TEXTURE since we changed the size
+            // of the texture
+            flags &= ~DisplayHardware::DIRECT_TEXTURE;
+        }
+    }
+
+    if (flags & DisplayHardware::DIRECT_TEXTURE) {
+        // here we're guaranteed that texture_{w|h} == t{w|h}
+        if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+            glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
+                    GL_RGB, tw, th, 0,
+                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data);
+        } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+            glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
+                    GL_RGBA, tw, th, 0,
+                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data);
+        } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+            glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
+                    GL_RGBA, tw, th, 0,
+                    GL_RGBA, GL_UNSIGNED_BYTE, t.data);
+        } else if (t.format == GGL_PIXEL_FORMAT_BGRA_8888) {
+            // TODO: add GL_BGRA extension
+        } else {
+            // oops, we don't handle this format, try the regular path
+            goto regular;
+        }
+        textureWidth = tw;
+        textureHeight = th;
+    } else {
+regular:
+        Rect bounds(dirty.bounds());
+        GLvoid* data = 0;
+        if (texture_w!=textureWidth || texture_h!=textureHeight) {
+            // texture size changed, we need to create a new one
+
+            if (!textureWidth || !textureHeight) {
+                // this is the first time, load the whole texture
+                if (texture_w==tw && texture_h==th) {
+                    // we can do it one pass
+                    data = t.data;
+                } else {
+                    // we have to create the texture first because it
+                    // doesn't match the size of the buffer
+                    bounds.set(Rect(tw, th));
+                }
+            }
+            
+            if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+                glTexImage2D(GL_TEXTURE_2D, 0,
+                        GL_RGB, texture_w, texture_h, 0,
+                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
+            } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+                glTexImage2D(GL_TEXTURE_2D, 0,
+                        GL_RGBA, texture_w, texture_h, 0,
+                        GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
+            } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+                glTexImage2D(GL_TEXTURE_2D, 0,
+                        GL_RGBA, texture_w, texture_h, 0,
+                        GL_RGBA, GL_UNSIGNED_BYTE, data);
+            } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
+                        t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
+                // just show the Y plane of YUV buffers
+                data = t.data;
+                glTexImage2D(GL_TEXTURE_2D, 0,
+                        GL_LUMINANCE, texture_w, texture_h, 0,
+                        GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
+            } else {
+                // oops, we don't handle this format!
+                LOGE("layer %p, texture=%d, using format %d, which is not "
+                     "supported by the GL", this, textureName, t.format);
+                textureName = -1;
+            }
+            textureWidth = texture_w;
+            textureHeight = texture_h;
+        }
+        if (!data && textureName>=0) {
+            if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+                glTexSubImage2D(GL_TEXTURE_2D, 0,
+                        0, bounds.top, t.width, bounds.height(),
+                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
+                        t.data + bounds.top*t.width*2);
+            } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+                glTexSubImage2D(GL_TEXTURE_2D, 0,
+                        0, bounds.top, t.width, bounds.height(),
+                        GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
+                        t.data + bounds.top*t.width*2);
+            } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+                glTexSubImage2D(GL_TEXTURE_2D, 0,
+                        0, bounds.top, t.width, bounds.height(),
+                        GL_RGBA, GL_UNSIGNED_BYTE,
+                        t.data + bounds.top*t.width*4);
+            }
+        }
+    }
+}
+
+bool LayerBase::canUseCopybit() const
+{
+    return mCanUseCopyBit;
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
+        Client* c, int32_t i)
+    : LayerBase(flinger, display), client(c),
+      lcblk( c ? &(c->ctrlblk->layers[i]) : 0 ),
+      mIndex(i)
+{
+    if (client) {
+        client->bindLayer(this, i);
+
+        // Initialize this layer's control block
+        memset(this->lcblk, 0, sizeof(layer_cblk_t));
+        this->lcblk->identity = mIdentity;
+        Region::writeEmpty(&(this->lcblk->region[0]), sizeof(flat_region_t));
+        Region::writeEmpty(&(this->lcblk->region[1]), sizeof(flat_region_t));
+    }
+}
+
+LayerBaseClient::~LayerBaseClient()
+{
+    if (client) {
+        client->free(mIndex);
+    }
+}
+
+int32_t LayerBaseClient::serverIndex() const {
+    if (client) {
+        return (client->cid<<16)|mIndex;
+    }
+    return 0xFFFF0000 | mIndex;
+}
+
+sp<LayerBaseClient::Surface> LayerBaseClient::getSurface() const
+{
+    return new Surface(clientIndex(), mIdentity);
+}
+
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
new file mode 100644
index 0000000..a020f44
--- /dev/null
+++ b/libs/surfaceflinger/LayerBase.h
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_LAYER_BASE_H
+#define ANDROID_LAYER_BASE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <private/ui/LayerState.h>
+
+#include <ui/Region.h>
+#include <ui/Overlay.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "Transform.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class SurfaceFlinger;
+class DisplayHardware;
+class GraphicPlane;
+class Client;
+
+// ---------------------------------------------------------------------------
+
+class LayerBase
+{
+    // poor man's dynamic_cast below
+    template<typename T>
+    struct getTypeInfoOfAnyType {
+        static uint32_t get() { return T::typeInfo; }
+    };
+
+    template<typename T>
+    struct getTypeInfoOfAnyType<T*> {
+        static uint32_t get() { return getTypeInfoOfAnyType<T>::get(); }
+    };
+
+public:
+    static const uint32_t typeInfo;
+    static const char* const typeID;
+    virtual char const* getTypeID() const { return typeID; }
+    virtual uint32_t getTypeInfo() const { return typeInfo; }
+    
+    template<typename T>
+    static T dynamicCast(LayerBase* base) {
+        uint32_t mostDerivedInfo = base->getTypeInfo();
+        uint32_t castToInfo = getTypeInfoOfAnyType<T>::get();
+        if ((mostDerivedInfo & castToInfo) == castToInfo)
+            return static_cast<T>(base);
+        return 0;
+    }
+
+    
+    static Vector<GLuint> deletedTextures; 
+
+    LayerBase(SurfaceFlinger* flinger, DisplayID display);
+    virtual ~LayerBase();
+    
+    DisplayID           dpy;
+    mutable bool        contentDirty;
+            Region      visibleRegionScreen;
+            Region      transparentRegionScreen;
+            Region      coveredRegionScreen;
+            
+            struct State {
+                uint32_t        w;
+                uint32_t        h;
+                uint32_t        z;
+                uint8_t         alpha;
+                uint8_t         flags;
+                uint8_t         reserved[2];
+                int32_t         sequence;   // changes when visible regions can change
+                uint32_t        tint;
+                Transform       transform;
+                Region          transparentRegion;
+            };
+
+            // modify current state
+            bool setPosition(int32_t x, int32_t y);
+            bool setLayer(uint32_t z);
+            bool setSize(uint32_t w, uint32_t h);
+            bool setAlpha(uint8_t alpha);
+            bool setMatrix(const layer_state_t::matrix22_t& matrix);
+            bool setTransparentRegionHint(const Region& opaque);
+            bool setFlags(uint8_t flags, uint8_t mask);
+            
+            void commitTransaction(bool skipSize);
+            bool requestTransaction();
+            void forceVisibilityTransaction();
+            
+            uint32_t getTransactionFlags(uint32_t flags);
+            uint32_t setTransactionFlags(uint32_t flags);
+            
+            Rect visibleBounds() const;
+            void drawRegion(const Region& reg) const;
+
+            void invalidate();
+            
+    /**
+     * draw - performs some global clipping optimizations
+     * and calls onDraw().
+     * Typically this method is not overridden, instead implement onDraw()
+     * to perform the actual drawing.  
+     */
+    virtual void draw(const Region& clip) const;
+    
+    /**
+     * onDraw - draws the surface.
+     */
+    virtual void onDraw(const Region& clip) const = 0;
+    
+    /**
+     * initStates - called just after construction
+     */
+    virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
+    
+    /**
+     * setSizeChanged - called when the *current* state's size is changed.
+     */
+    virtual void setSizeChanged(uint32_t w, uint32_t h);
+    
+    /**
+     * doTransaction - process the transaction. This is a good place to figure
+     * out which attributes of the surface have changed.
+     */
+    virtual uint32_t doTransaction(uint32_t transactionFlags);
+    
+    /**
+     * setVisibleRegion - called to set the new visible region. This gives
+     * a chance to update the new visible region or record the fact it changed.
+     */
+    virtual void setVisibleRegion(const Region& visibleRegion);
+    
+    /**
+     * setCoveredRegion - called when the covered region changes. The covered
+     * region correspond to any area of the surface that is covered 
+     * (transparently or not) by another surface.
+     */
+    virtual void setCoveredRegion(const Region& coveredRegion);
+    
+    /**
+     * getPhysicalSize - returns the physical size of the drawing state of
+     * the surface. If the surface is backed by a bitmap, this is the size of
+     * the bitmap (as opposed to the size of the drawing state).
+     */
+    virtual Point getPhysicalSize() const;
+
+    /**
+     * validateVisibility - cache a bunch of things
+     */
+    virtual void validateVisibility(const Transform& globalTransform);
+
+    /**
+     * lockPageFlip - called each time the screen is redrawn and returns whether
+     * the visible regions need to be recomputed (this is a fairly heavy
+     * operation, so this should be set only if needed). Typically this is used
+     * to figure out if the content or size of a surface has changed.
+     */
+    virtual void lockPageFlip(bool& recomputeVisibleRegions);
+    
+    /**
+     * unlockPageFlip - called each time the screen is redrawn. updates the
+     * final dirty region wrt the planeTransform.
+     * At this point, all visible regions, surface position and size, etc... are
+     * correct.
+     */
+    virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+    
+    /**
+     * finishPageFlip - called after all surfaces have drawn.
+     */
+    virtual void finishPageFlip();
+    
+    /**
+     * needsBlending - true if this surface needs blending
+     */
+    virtual bool needsBlending() const  { return false; }
+
+    /**
+     * transformed -- true is this surface needs a to be transformed
+     */
+    virtual bool transformed() const    { return mTransformed; }
+
+    /**
+     * isSecure - true if this surface is secure, that is if it prevents
+     * screenshots or vns servers.
+     */
+    virtual bool isSecure() const       { return false; }
+
+            enum { // flags for doTransaction()
+                eVisibleRegion      = 0x00000002,
+                eRestartTransaction = 0x00000008
+            };
+
+
+    inline  const State&    drawingState() const    { return mDrawingState; }
+    inline  const State&    currentState() const    { return mCurrentState; }
+    inline  State&          currentState()          { return mCurrentState; }
+
+    static int compareCurrentStateZ(LayerBase*const* layerA, LayerBase*const* layerB) {
+        return layerA[0]->currentState().z - layerB[0]->currentState().z;
+    }
+
+    int32_t  getOrientation() const { return mOrientation; }
+    int  tx() const             { return mLeft; }
+    int  ty() const             { return mTop; }
+    
+protected:
+    const GraphicPlane& graphicPlane(int dpy) const;
+          GraphicPlane& graphicPlane(int dpy);
+
+          GLuint createTexture() const;
+    
+          void drawWithOpenGL(const Region& clip,
+                  GLint textureName,
+                  const GGLSurface& surface,
+                  int transform = 0) const;
+
+          void clearWithOpenGL(const Region& clip) const;
+
+          void loadTexture(const Region& dirty,
+                  GLint textureName, const GGLSurface& t,
+                  GLuint& textureWidth, GLuint& textureHeight) const;
+
+          bool canUseCopybit() const;
+          
+                SurfaceFlinger* mFlinger;
+                uint32_t        mFlags;
+
+                // cached during validateVisibility()
+                bool            mTransformed;
+                int32_t         mOrientation;
+                GLfixed         mVertices[4][2];
+                Rect            mTransformedBounds;
+                bool            mCanUseCopyBit;
+                int             mLeft;
+                int             mTop;
+            
+                // these are protected by an external lock
+                State           mCurrentState;
+                State           mDrawingState;
+    volatile    int32_t         mTransactionFlags;
+
+                // don't change, don't need a lock
+                bool            mPremultipliedAlpha;
+
+                // only read
+    const       uint32_t        mIdentity;
+     
+                // atomic
+    volatile    int32_t         mInvalidate;
+                
+
+private:
+                void validateTexture(GLint textureName) const;
+    static      int32_t         sIdentity;
+};
+
+
+// ---------------------------------------------------------------------------
+
+class LayerBaseClient : public LayerBase
+{
+public:
+    class Surface;
+   static const uint32_t typeInfo;
+    static const char* const typeID;
+    virtual char const* getTypeID() const { return typeID; }
+    virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+    LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, 
+            Client* client, int32_t i);
+    virtual ~LayerBaseClient();
+
+
+    Client*             const client;
+    layer_cblk_t*       const lcblk;
+
+    inline  int32_t     clientIndex() const { return mIndex; }
+            int32_t     serverIndex() const;
+
+    virtual sp<Surface> getSurface() const;
+   
+            uint32_t    getIdentity() const { return mIdentity; }
+
+    class Surface : public BnSurface 
+    {
+    public:
+        Surface(SurfaceID id, int identity) { 
+            mParams.token = id;
+            mParams.identity = identity;
+        }
+        Surface(SurfaceID id, 
+                const sp<IMemoryHeap>& heap0,
+                const sp<IMemoryHeap>& heap1,
+                int identity)
+        {
+            mParams.token = id;
+            mParams.identity = identity;
+            mParams.heap[0] = heap0;
+            mParams.heap[1] = heap1;
+        }
+        virtual ~Surface() {
+            // TODO: We now have a point here were we can clean-up the
+            // client's mess.
+            // This is also where surface id should be recycled.
+            //LOGD("Surface %d, heaps={%p, %p} destroyed",
+            //        mId, mHeap[0].get(), mHeap[1].get());
+        }
+
+        virtual void getSurfaceData(
+                ISurfaceFlingerClient::surface_data_t* params) const {
+            *params = mParams;
+        }
+
+        virtual status_t registerBuffers(const ISurface::BufferHeap& buffers) 
+                { return INVALID_OPERATION; }
+        virtual void postBuffer(ssize_t offset) { }
+        virtual void unregisterBuffers() { };
+        virtual sp<OverlayRef> createOverlay(
+                uint32_t w, uint32_t h, int32_t format) {
+            return NULL;
+        };
+
+    private:
+        ISurfaceFlingerClient::surface_data_t mParams;
+    };
+
+private:
+    int32_t mIndex;
+
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BASE_H
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
new file mode 100644
index 0000000..e844350
--- /dev/null
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/memory.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/MemoryDealer.h>
+#include <utils/IMemory.h>
+#include <ui/PixelFormat.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include "LayerBitmap.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+LayerBitmap::LayerBitmap()
+    : mAllocFlags(0), mOffset(0), mSize(-1U), mAlignment(2)
+{
+    memset(&mSurface, 0, sizeof(mSurface));
+}
+
+LayerBitmap::~LayerBitmap()
+{
+    mSurface.data = 0;
+}
+
+status_t LayerBitmap::init(const sp<MemoryDealer>& allocator)
+{
+    if (mAllocator != NULL)
+        return BAD_VALUE;
+    mAllocator = allocator;
+    return NO_ERROR;
+}
+
+status_t LayerBitmap::setBits(uint32_t w, uint32_t h, uint32_t alignment, 
+        PixelFormat format, uint32_t flags)
+{
+    const sp<MemoryDealer>& allocator(mAllocator);
+    if (allocator == NULL)
+        return NO_INIT;
+
+    if (UNLIKELY(w == mSurface.width && h == mSurface.height &&
+            format == mSurface.format))
+    { // same format and size, do nothing.
+        return NO_ERROR;
+    }
+
+    PixelFormatInfo info;
+    getPixelFormatInfo(format, &info);
+
+    uint32_t allocFlags = MemoryDealer::PAGE_ALIGNED;
+    const uint32_t align = 4; // must match GL_UNPACK_ALIGNMENT
+    const uint32_t Bpp = info.bytesPerPixel;
+    uint32_t stride = (w + (alignment-1)) & ~(alignment-1);
+    stride = ((stride * Bpp + (align-1)) & ~(align-1)) / Bpp;
+    size_t size = info.getScanlineSize(stride) * h;
+    if (allocFlags & MemoryDealer::PAGE_ALIGNED) {
+        size_t pagesize = getpagesize();
+        size = (size + (pagesize-1)) & ~(pagesize-1);
+    }
+
+    /* FIXME: we should be able to have a h/v stride because the user of the
+     * surface might have stride limitation (for instance h/w codecs often do)
+     */
+    int32_t vstride = 0;
+
+    mAlignment = alignment;
+    mAllocFlags = allocFlags;
+    mOffset = 0;
+    if (mSize != size) {
+        // would be nice to have a reallocate() api
+        mBitsMemory.clear(); // free-memory
+        mBitsMemory = allocator->allocate(size, allocFlags);
+        mSize = size;
+    } else {
+        // don't erase memory if we didn't have to reallocate
+        flags &= ~SECURE_BITS;
+    }
+    if (mBitsMemory != 0) {
+        mOffset = mBitsMemory->offset();
+        mSurface.data = static_cast<GGLubyte*>(mBitsMemory->pointer());
+        mSurface.version = sizeof(GGLSurface);
+        mSurface.width  = w;
+        mSurface.height = h;
+        mSurface.stride = stride;
+        mSurface.vstride = vstride;
+        mSurface.format = format;
+        if (flags & SECURE_BITS)
+            clear();
+    }
+
+    if (mBitsMemory==0 || mSurface.data==0) {
+        LOGE("not enough memory for layer bitmap size=%u", size);
+        allocator->dump("LayerBitmap");
+        mSurface.data = 0;
+        mSize = -1U;
+        return NO_MEMORY;
+    }
+    return NO_ERROR;
+}
+
+void LayerBitmap::clear()
+{
+    // NOTE: this memset should not be necessary, at least for
+    // opaque surface. However, for security reasons it's better to keep it
+    // (in the case of pmem, it's possible that the memory contains old
+    // data)
+    if (mSurface.data) {
+        memset(mSurface.data, 0, mSize);
+        //if (bytesPerPixel(mSurface.format) == 4) {
+        //    android_memset32((uint32_t*)mSurface.data, 0xFF0000FF, mSize);
+        //} else  {
+        //    android_memset16((uint16_t*)mSurface.data, 0xF800, mSize);
+        //}
+    }
+}
+
+status_t LayerBitmap::getInfo(surface_info_t* info) const
+{
+    if (mSurface.data == 0) {
+        memset(info, 0, sizeof(surface_info_t));
+        info->bits_offset = NO_MEMORY;
+        return NO_MEMORY;
+    }
+    info->w     = uint16_t(width());
+    info->h     = uint16_t(height());
+    info->stride= uint16_t(stride());
+    info->bpr   = uint16_t(stride() * bytesPerPixel(pixelFormat()));
+    info->format= uint8_t(pixelFormat());
+    info->flags = surface_info_t::eBufferDirty;
+    info->bits_offset = ssize_t(mOffset);
+    return NO_ERROR;
+}
+
+status_t LayerBitmap::resize(uint32_t w, uint32_t h)
+{
+    int err = setBits(w, h, mAlignment, pixelFormat(), SECURE_BITS);
+    return err;
+}
+
+size_t LayerBitmap::size() const
+{
+    return mSize;
+}
+
+void LayerBitmap::getBitmapSurface(copybit_image_t* img) const
+{
+    const sp<IMemoryHeap>& mh(getAllocator()->getMemoryHeap());
+    void* sbase = mh->base();
+    const GGLSurface& t(surface());
+    img->w = t.stride  ?: t.width;
+    img->h = t.vstride ?: t.height;
+    img->format = t.format;
+    img->offset = intptr_t(t.data) - intptr_t(sbase);
+    img->base = sbase;
+    img->fd = mh->heapID();
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerBitmap.h b/libs/surfaceflinger/LayerBitmap.h
new file mode 100644
index 0000000..9ad64c4
--- /dev/null
+++ b/libs/surfaceflinger/LayerBitmap.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_LAYER_BITMAP_H
+#define ANDROID_LAYER_BITMAP_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <private/ui/SharedState.h>
+#include <pixelflinger/pixelflinger.h>
+
+class copybit_image_t;
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class IMemory;
+class MemoryDealer;
+class LayerBitmap;
+
+// ---------------------------------------------------------------------------
+
+class LayerBitmap
+{
+public:
+
+    enum {
+        // erase memory to ensure security when necessary
+        SECURE_BITS = 0x00000001
+    };
+
+                LayerBitmap();
+                ~LayerBitmap();
+    status_t    init(const sp<MemoryDealer>& allocator);
+
+    status_t    setBits(uint32_t w, uint32_t h, uint32_t alignment,
+                        PixelFormat format, uint32_t flags = 0);
+    void        clear();
+
+    status_t    getInfo(surface_info_t* info) const;
+    status_t    resize(uint32_t w, uint32_t h);
+
+    const GGLSurface& surface() const   { return mSurface; }
+    Rect bounds() const                 { return Rect(width(), height()); }
+    uint32_t width() const              { return surface().width; }
+    uint32_t height() const             { return surface().height; }
+    uint32_t stride() const             { return surface().stride; }
+    PixelFormat pixelFormat() const     { return surface().format; }
+    void* serverBits() const            { return surface().data; }
+    size_t size() const;
+    const sp<MemoryDealer>& getAllocator() const { return mAllocator; }
+    void getBitmapSurface(copybit_image_t* img) const;
+
+private:
+    sp<MemoryDealer>        mAllocator;
+    sp<IMemory>             mBitsMemory;
+    uint32_t                mAllocFlags;
+    ssize_t                 mOffset;
+    GGLSurface              mSurface;
+    size_t                  mSize;
+    uint32_t                mAlignment;
+};
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BITMAP_H
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
new file mode 100644
index 0000000..d3e456f
--- /dev/null
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include "BlurFilter.h"
+#include "LayerBlur.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerBlur::typeInfo = LayerBaseClient::typeInfo | 8;
+const char* const LayerBlur::typeID = "LayerBlur";
+
+// ---------------------------------------------------------------------------
+
+LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
+        Client* client, int32_t i)
+     : LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
+     mRefreshCache(true), mCacheAge(0), mTextureName(-1U)
+{
+}
+
+LayerBlur::~LayerBlur()
+{
+    if (mTextureName != -1U) {
+        //glDeleteTextures(1, &mTextureName);
+        deletedTextures.add(mTextureName);
+    }
+}
+
+void LayerBlur::setVisibleRegion(const Region& visibleRegion)
+{
+    LayerBaseClient::setVisibleRegion(visibleRegion);
+    if (visibleRegionScreen.isEmpty()) {
+        if (mTextureName != -1U) {
+            // We're not visible, free the texture up.
+            glBindTexture(GL_TEXTURE_2D, 0);
+            glDeleteTextures(1, &mTextureName);
+            mTextureName = -1U;
+        }
+    }
+}
+
+uint32_t LayerBlur::doTransaction(uint32_t flags)
+{
+    // we're doing a transaction, refresh the cache!
+    if (!mFlinger->isFrozen()) {
+        mRefreshCache = true;
+        mCacheDirty = true;
+        flags |= eVisibleRegion;
+        this->contentDirty = true;
+    }
+    return LayerBase::doTransaction(flags);    
+}
+
+void LayerBlur::unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion)
+{
+    // this code-path must be as tight as possible, it's called each time
+    // the screen is composited.
+    if (UNLIKELY(!visibleRegionScreen.isEmpty())) {
+        // if anything visible below us is invalidated, the cache becomes dirty
+        if (!mCacheDirty && 
+                !visibleRegionScreen.intersect(outDirtyRegion).isEmpty()) {
+            mCacheDirty = true;
+        }
+        if (mCacheDirty) {
+            if (!mFlinger->isFrozen()) {
+                // update everything below us that is visible
+                outDirtyRegion.orSelf(visibleRegionScreen);
+                nsecs_t now = systemTime();
+                if ((now - mCacheAge) >= ms2ns(500)) {
+                    mCacheAge = now;
+                    mRefreshCache = true;
+                    mCacheDirty = false;
+                } else {
+                    if (!mAutoRefreshPending) {
+                        mFlinger->signalDelayedEvent(ms2ns(500));
+                        mAutoRefreshPending = true;
+                    }
+                }
+            }
+        }
+    }
+    LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);
+}
+
+void LayerBlur::onDraw(const Region& clip) const
+{
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    const uint32_t fbHeight = hw.getHeight();
+    int x = mTransformedBounds.left;
+    int y = mTransformedBounds.top;
+    int w = mTransformedBounds.width();
+    int h = mTransformedBounds.height();
+    GLint X = x;
+    GLint Y = fbHeight - (y + h);
+    if (X < 0) {
+        w += X;
+        X = 0;
+    }
+    if (Y < 0) {
+        h += Y;
+        Y = 0;
+    }
+    if (w<0 || h<0) {
+        // we're outside of the framebuffer
+        return;
+    }
+
+    if (mTextureName == -1U) {
+        // create the texture name the first time
+        // can't do that in the ctor, because it runs in another thread.
+        glGenTextures(1, &mTextureName);
+    }
+
+    Region::iterator iterator(clip);
+    if (iterator) {
+        glEnable(GL_TEXTURE_2D);
+        glBindTexture(GL_TEXTURE_2D, mTextureName);
+    
+        if (mRefreshCache) {
+            mRefreshCache = false;
+            mAutoRefreshPending = false;
+            
+            // allocate enough memory for 4-bytes (2 pixels) aligned data
+            const int32_t s = (w + 1) & ~1;
+            uint16_t* const pixels = (uint16_t*)malloc(s*h*2);
+
+            // This reads the frame-buffer, so a h/w GL would have to
+            // finish() its rendering first. we don't want to do that
+            // too often. Read data is 4-bytes aligned.
+            glReadPixels(X, Y, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+            
+            // blur that texture.
+            GGLSurface bl;
+            bl.version = sizeof(GGLSurface);
+            bl.width = w;
+            bl.height = h;
+            bl.stride = s;
+            bl.format = GGL_PIXEL_FORMAT_RGB_565;
+            bl.data = (GGLubyte*)pixels;            
+            blurFilter(&bl, 8, 2);
+            
+            // NOTE: this works only because we have POT. we'd have to round the
+            // texture size up, otherwise.
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
+                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+
+            free((void*)pixels);
+        }
+        
+        const State& s = drawingState();
+        if (UNLIKELY(s.alpha < 0xFF)) {
+            const GGLfixed alpha = (s.alpha << 16)/255;
+            glColor4x(0, 0, 0, alpha);
+            glEnable(GL_BLEND);
+            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+            glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+        } else {
+            glDisable(GL_BLEND);
+        }
+
+        glDisable(GL_DITHER);
+        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+        if (UNLIKELY(transformed()
+                || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) )) {
+            // This is a very rare scenario.
+            glMatrixMode(GL_TEXTURE);
+            glLoadIdentity();
+            glScalef(1.0f/w, -1.0f/h, 1);
+            glTranslatef(-x, -y, 0);
+            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+            glVertexPointer(2, GL_FIXED, 0, mVertices);
+            glTexCoordPointer(2, GL_FIXED, 0, mVertices);
+            Rect r;
+            while (iterator.iterate(&r)) {
+                const GLint sy = fbHeight - (r.top + r.height());
+                glScissor(r.left, sy, r.width(), r.height());
+                glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
+            }       
+        } else {
+            Region::iterator iterator(clip);
+            if (iterator) {
+                // NOTE: this is marginally faster with the software gl, because
+                // glReadPixels() reads the fb bottom-to-top, however we'll
+                // skip all the jaccobian computations.
+                Rect r;
+                GLint crop[4] = { 0, 0, w, h };
+                glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+                y = fbHeight - (y + h);
+                while (iterator.iterate(&r)) {
+                    const GLint sy = fbHeight - (r.top + r.height());
+                    glScissor(r.left, sy, r.width(), r.height());
+                    glDrawTexiOES(x, y, 0, w, h);
+                }
+            }
+        }
+    }
+
+    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
new file mode 100644
index 0000000..24b1156
--- /dev/null
+++ b/libs/surfaceflinger/LayerBlur.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_LAYER_BLUR_H
+#define ANDROID_LAYER_BLUR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <private/ui/LayerState.h>
+
+#include <ui/Region.h>
+
+#include "LayerBase.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class LayerBlur : public LayerBaseClient
+{
+public:    
+    static const uint32_t typeInfo;
+    static const char* const typeID;
+    virtual char const* getTypeID() const { return typeID; }
+    virtual uint32_t getTypeInfo() const { return typeInfo; }
+    
+                LayerBlur(SurfaceFlinger* flinger, DisplayID display,
+                        Client* client, int32_t i);
+        virtual ~LayerBlur();
+
+    virtual void onDraw(const Region& clip) const;
+    virtual bool needsBlending() const  { return true; }
+    virtual bool isSecure() const       { return false; }
+
+    virtual uint32_t doTransaction(uint32_t flags);
+    virtual void setVisibleRegion(const Region& visibleRegion);
+    virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+
+private:
+            bool    mCacheDirty;
+    mutable bool    mRefreshCache;
+    mutable bool    mAutoRefreshPending;
+            nsecs_t mCacheAge;
+    mutable GLuint  mTextureName;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BLUR_H
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
new file mode 100644
index 0000000..00fab70
--- /dev/null
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -0,0 +1,655 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/StopWatch.h>
+
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBuffer.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerBuffer::typeInfo = LayerBaseClient::typeInfo | 0x20;
+const char* const LayerBuffer::typeID = "LayerBuffer";
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
+        Client* client, int32_t i)
+    : LayerBaseClient(flinger, display, client, i),
+      mNeedsBlending(false)
+{
+}
+
+LayerBuffer::~LayerBuffer()
+{
+    sp<SurfaceBuffer> s(getClientSurface());
+    if (s != 0) {
+        s->disown();
+        mClientSurface.clear();
+    }
+}
+
+sp<LayerBuffer::SurfaceBuffer> LayerBuffer::getClientSurface() const
+{
+    Mutex::Autolock _l(mLock);
+    return mClientSurface.promote();
+}
+
+sp<LayerBaseClient::Surface> LayerBuffer::getSurface() const
+{
+    sp<SurfaceBuffer> s;
+    Mutex::Autolock _l(mLock);
+    s = mClientSurface.promote();
+    if (s == 0) {
+        s = new SurfaceBuffer(clientIndex(),
+                const_cast<LayerBuffer *>(this));
+        mClientSurface = s;
+    }
+    return s;
+}
+
+bool LayerBuffer::needsBlending() const {
+    return mNeedsBlending;
+}
+
+void LayerBuffer::setNeedsBlending(bool blending) {
+    mNeedsBlending = blending;
+}
+
+void LayerBuffer::postBuffer(ssize_t offset)
+{
+    sp<Source> source(getSource());
+    if (source != 0)
+        source->postBuffer(offset);
+}
+
+void LayerBuffer::unregisterBuffers()
+{
+    sp<Source> source(clearSource());
+    if (source != 0)
+        source->unregisterBuffers();
+}
+
+uint32_t LayerBuffer::doTransaction(uint32_t flags)
+{
+    sp<Source> source(getSource());
+    if (source != 0)
+        source->onTransaction(flags);
+    return LayerBase::doTransaction(flags);    
+}
+
+void LayerBuffer::unlockPageFlip(const Transform& planeTransform,
+        Region& outDirtyRegion)
+{
+    // this code-path must be as tight as possible, it's called each time
+    // the screen is composited.
+    sp<Source> source(getSource());
+    if (source != 0)
+        source->onVisibilityResolved(planeTransform);
+    LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);    
+}
+
+void LayerBuffer::onDraw(const Region& clip) const
+{
+    sp<Source> source(getSource());
+    if (LIKELY(source != 0)) {
+        source->onDraw(clip);
+    } else {
+        clearWithOpenGL(clip);
+    }
+}
+
+bool LayerBuffer::transformed() const
+{
+    sp<Source> source(getSource());
+    if (LIKELY(source != 0))
+        return source->transformed();
+    return false;
+}
+
+/**
+ * This creates a "buffer" source for this surface
+ */
+status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
+{
+    Mutex::Autolock _l(mLock);
+    if (mSource != 0)
+        return INVALID_OPERATION;
+
+    sp<BufferSource> source = new BufferSource(*this, buffers);
+
+    status_t result = source->getStatus();
+    if (result == NO_ERROR) {
+        mSource = source;
+    }
+    return result;
+}    
+
+/**
+ * This creates an "overlay" source for this surface
+ */
+sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f)
+{
+    sp<OverlayRef> result;
+    Mutex::Autolock _l(mLock);
+    if (mSource != 0)
+        return result;
+
+    sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f);
+    if (result != 0) {
+        mSource = source;
+    }
+    return result;
+}
+
+sp<LayerBuffer::Source> LayerBuffer::getSource() const {
+    Mutex::Autolock _l(mLock);
+    return mSource;
+}
+
+sp<LayerBuffer::Source> LayerBuffer::clearSource() {
+    sp<Source> source;
+    Mutex::Autolock _l(mLock);
+    source = mSource;
+    mSource.clear();
+    return source;
+}
+
+// ============================================================================
+// LayerBuffer::SurfaceBuffer
+// ============================================================================
+
+LayerBuffer::SurfaceBuffer::SurfaceBuffer(SurfaceID id, LayerBuffer* owner)
+: LayerBaseClient::Surface(id, owner->getIdentity()), mOwner(owner)
+{
+}
+
+LayerBuffer::SurfaceBuffer::~SurfaceBuffer()
+{
+    unregisterBuffers();
+    mOwner = 0;
+}
+
+status_t LayerBuffer::SurfaceBuffer::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case REGISTER_BUFFERS:
+        case UNREGISTER_BUFFERS:
+        case CREATE_OVERLAY:
+        {
+            // codes that require permission check
+            IPCThreadState* ipc = IPCThreadState::self();
+            const int pid = ipc->getCallingPid();
+            const int self_pid = getpid();
+            if (LIKELY(pid != self_pid)) {
+                // we're called from a different process, do the real check
+                if (!checkCallingPermission(
+                        String16("android.permission.ACCESS_SURFACE_FLINGER")))
+                {
+                    const int uid = ipc->getCallingUid();
+                    LOGE("Permission Denial: "
+                            "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+                    return PERMISSION_DENIED;
+                }
+            }
+        }
+    }
+    return LayerBaseClient::Surface::onTransact(code, data, reply, flags);
+}
+
+status_t LayerBuffer::SurfaceBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
+{
+    LayerBuffer* owner(getOwner());
+    if (owner)
+        return owner->registerBuffers(buffers);
+    return NO_INIT;
+}
+
+void LayerBuffer::SurfaceBuffer::postBuffer(ssize_t offset)
+{
+    LayerBuffer* owner(getOwner());
+    if (owner)
+        owner->postBuffer(offset);
+}
+
+void LayerBuffer::SurfaceBuffer::unregisterBuffers()
+{
+    LayerBuffer* owner(getOwner());
+    if (owner)
+        owner->unregisterBuffers();
+}
+
+sp<OverlayRef> LayerBuffer::SurfaceBuffer::createOverlay(
+        uint32_t w, uint32_t h, int32_t format) {
+    sp<OverlayRef> result;
+    LayerBuffer* owner(getOwner());
+    if (owner)
+        result = owner->createOverlay(w, h, format);
+    return result;
+}
+
+void LayerBuffer::SurfaceBuffer::disown()
+{
+    Mutex::Autolock _l(mLock);
+    mOwner = 0;
+}
+
+// ============================================================================
+// LayerBuffer::Buffer
+// ============================================================================
+
+LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset)
+    : mBufferHeap(buffers)
+{
+    NativeBuffer& src(mNativeBuffer);
+    src.crop.l = 0;
+    src.crop.t = 0;
+    src.crop.r = buffers.w;
+    src.crop.b = buffers.h;
+    src.img.w = buffers.hor_stride ?: buffers.w;
+    src.img.h = buffers.ver_stride ?: buffers.h;
+    src.img.format = buffers.format;
+    src.img.offset = offset;
+    src.img.base   = buffers.heap->base();
+    src.img.fd     = buffers.heap->heapID();
+}
+
+LayerBuffer::Buffer::~Buffer()
+{
+}
+
+// ============================================================================
+// LayerBuffer::Source
+// LayerBuffer::BufferSource
+// LayerBuffer::OverlaySource
+// ============================================================================
+
+LayerBuffer::Source::Source(LayerBuffer& layer)
+    : mLayer(layer)
+{    
+}
+LayerBuffer::Source::~Source() {    
+}
+void LayerBuffer::Source::onDraw(const Region& clip) const {
+}
+void LayerBuffer::Source::onTransaction(uint32_t flags) {
+}
+void LayerBuffer::Source::onVisibilityResolved(
+        const Transform& planeTransform) {
+}
+void LayerBuffer::Source::postBuffer(ssize_t offset) {
+}
+void LayerBuffer::Source::unregisterBuffers() {
+}
+bool LayerBuffer::Source::transformed() const {
+    return mLayer.mTransformed; 
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
+        const ISurface::BufferHeap& buffers)
+    : Source(layer), mStatus(NO_ERROR), 
+      mBufferSize(0), mTextureName(-1U)
+{
+    if (buffers.heap == NULL) {
+        // this is allowed, but in this case, it is illegal to receive
+        // postBuffer(). The surface just erases the framebuffer with
+        // fully transparent pixels.
+        mBufferHeap = buffers;
+        mLayer.setNeedsBlending(false);
+        return;
+    }
+
+    status_t err = (buffers.heap->heapID() >= 0) ? NO_ERROR : NO_INIT;
+    if (err != NO_ERROR) {
+        LOGE("LayerBuffer::BufferSource: invalid heap (%s)", strerror(err));
+        mStatus = err;
+        return;
+    }
+    
+    PixelFormatInfo info;
+    err = getPixelFormatInfo(buffers.format, &info);
+    if (err != NO_ERROR) {
+        LOGE("LayerBuffer::BufferSource: invalid format %d (%s)",
+                buffers.format, strerror(err));
+        mStatus = err;
+        return;
+    }
+
+    if (buffers.hor_stride<0 || buffers.ver_stride<0) {
+        LOGE("LayerBuffer::BufferSource: invalid parameters "
+             "(w=%d, h=%d, xs=%d, ys=%d)", 
+             buffers.w, buffers.h, buffers.hor_stride, buffers.ver_stride);
+        mStatus = BAD_VALUE;
+        return;
+    }
+
+    mBufferHeap = buffers;
+    mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);    
+    mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
+    mLayer.forceVisibilityTransaction();
+    
+}
+
+LayerBuffer::BufferSource::~BufferSource()
+{    
+    if (mTextureName != -1U) {
+        LayerBase::deletedTextures.add(mTextureName);
+    }
+}
+
+void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
+{    
+    ISurface::BufferHeap buffers;
+    { // scope for the lock
+        Mutex::Autolock _l(mLock);
+        buffers = mBufferHeap;
+        if (buffers.heap != 0) {
+            const size_t memorySize = buffers.heap->getSize();
+            if ((size_t(offset) + mBufferSize) > memorySize) {
+                LOGE("LayerBuffer::BufferSource::postBuffer() "
+                     "invalid buffer (offset=%d, size=%d, heap-size=%d",
+                     int(offset), int(mBufferSize), int(memorySize));
+                return;
+            }
+        }
+    }
+
+    sp<Buffer> buffer;
+    if (buffers.heap != 0) {
+        buffer = new LayerBuffer::Buffer(buffers, offset);
+        if (buffer->getStatus() != NO_ERROR)
+            buffer.clear();
+        setBuffer(buffer);
+        mLayer.invalidate();
+    }
+}
+
+void LayerBuffer::BufferSource::unregisterBuffers()
+{
+    Mutex::Autolock _l(mLock);
+    mBufferHeap.heap.clear();
+    mBuffer.clear();
+    mLayer.invalidate();
+}
+
+sp<LayerBuffer::Buffer> LayerBuffer::BufferSource::getBuffer() const
+{
+    Mutex::Autolock _l(mLock);
+    return mBuffer;
+}
+
+void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
+{
+    Mutex::Autolock _l(mLock);
+    mBuffer = buffer;
+}
+
+bool LayerBuffer::BufferSource::transformed() const
+{
+    return mBufferHeap.transform ? true : Source::transformed(); 
+}
+
+void LayerBuffer::BufferSource::onDraw(const Region& clip) const 
+{
+    sp<Buffer> buffer(getBuffer());
+    if (UNLIKELY(buffer == 0))  {
+        // nothing to do, we don't have a buffer
+        mLayer.clearWithOpenGL(clip);
+        return;
+    }
+
+    status_t err = NO_ERROR;
+    NativeBuffer src(buffer->getBuffer());
+    const Rect& transformedBounds = mLayer.getTransformedBounds();
+    const int can_use_copybit = mLayer.canUseCopybit();
+
+    if (can_use_copybit)  {
+        const int src_width  = src.crop.r - src.crop.l;
+        const int src_height = src.crop.b - src.crop.t;
+        int W = transformedBounds.width();
+        int H = transformedBounds.height();
+        if (mLayer.getOrientation() & Transform::ROT_90) {
+            int t(W); W=H; H=t;
+        }
+
+        /* With LayerBuffer, it is likely that we'll have to rescale the
+         * surface, because this is often used for video playback or
+         * camera-preview. Since we want these operation as fast as possible
+         * we make sure we can use the 2D H/W even if it doesn't support
+         * the requested scale factor, in which case we perform the scaling
+         * in several passes. */
+
+        copybit_device_t* copybit = mLayer.mFlinger->getBlitEngine();
+        const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
+        const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
+
+        float xscale = 1.0f;
+        if (src_width > W*min)          xscale = 1.0f / min;
+        else if (src_width*mag < W)     xscale = mag;
+
+        float yscale = 1.0f;
+        if (src_height > H*min)         yscale = 1.0f / min;
+        else if (src_height*mag < H)    yscale = mag;
+
+        if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
+            if (UNLIKELY(mTemporaryDealer == 0)) {
+                // allocate a memory-dealer for this the first time
+                mTemporaryDealer = mLayer.mFlinger->getSurfaceHeapManager()
+                    ->createHeap(ISurfaceComposer::eHardware);
+                mTempBitmap.init(mTemporaryDealer);
+            }
+
+            const int tmp_w = floorf(src_width  * xscale);
+            const int tmp_h = floorf(src_height * yscale);
+            err = mTempBitmap.setBits(tmp_w, tmp_h, 1, src.img.format);
+
+            if (LIKELY(err == NO_ERROR)) {
+                NativeBuffer tmp;
+                mTempBitmap.getBitmapSurface(&tmp.img);
+                tmp.crop.l = 0;
+                tmp.crop.t = 0;
+                tmp.crop.r = tmp.img.w;
+                tmp.crop.b = tmp.img.h;
+
+                region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
+                copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+                copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+                copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+                err = copybit->stretch(copybit,
+                        &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
+                src = tmp;
+            }
+        }
+
+        const DisplayHardware& hw(mLayer.graphicPlane(0).displayHardware());
+        copybit_image_t dst;
+        hw.getDisplaySurface(&dst);
+        const copybit_rect_t& drect
+            = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
+        const State& s(mLayer.drawingState());
+        region_iterator it(clip);
+        
+        // pick the right orientation for this buffer
+        int orientation = mLayer.getOrientation();
+        if (UNLIKELY(mBufferHeap.transform)) {
+            Transform rot90;
+            GraphicPlane::orientationToTransfrom(
+                    ISurfaceComposer::eOrientation90, 0, 0, &rot90);
+            const Transform& planeTransform(mLayer.graphicPlane(0).transform());
+            const Layer::State& s(mLayer.drawingState());
+            Transform tr(planeTransform * s.transform * rot90);
+            orientation = tr.getOrientation();
+        }
+        
+        copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
+        copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+        copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+
+        err = copybit->stretch(copybit,
+                &dst, &src.img, &drect, &src.crop, &it);
+        if (err != NO_ERROR) {
+            LOGE("copybit failed (%s)", strerror(err));
+        }
+    }
+
+    if (!can_use_copybit || err) {
+        if (UNLIKELY(mTextureName == -1LU)) {
+            mTextureName = mLayer.createTexture();
+        }
+        GLuint w = 0;
+        GLuint h = 0;
+        GGLSurface t;
+        t.version = sizeof(GGLSurface);
+        t.width  = src.crop.r;
+        t.height = src.crop.b;
+        t.stride = src.img.w;
+        t.vstride= src.img.h;
+        t.format = src.img.format;
+        t.data = (GGLubyte*)(intptr_t(src.img.base) + src.img.offset);
+        const Region dirty(Rect(t.width, t.height));
+        mLayer.loadTexture(dirty, mTextureName, t, w, h);
+        mLayer.drawWithOpenGL(clip, mTextureName, t, mBufferHeap.transform);
+    }
+}
+
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
+        sp<OverlayRef>* overlayRef, 
+        uint32_t w, uint32_t h, int32_t format)
+    : Source(layer), mVisibilityChanged(false),
+    mOverlay(0), mOverlayHandle(0), mOverlayDevice(0)
+{
+    overlay_control_device_t* overlay_dev = mLayer.mFlinger->getOverlayEngine();
+    if (overlay_dev == NULL) {
+        // overlays not supported
+        return;
+    }
+
+    mOverlayDevice = overlay_dev;
+    overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format);
+    if (overlay == NULL) {
+        // couldn't create the overlay (no memory? no more overlays?)
+        return;
+    }
+
+    // enable dithering...
+    overlay_dev->setParameter(overlay_dev, overlay, 
+            OVERLAY_DITHER, OVERLAY_ENABLE);
+
+    mOverlay = overlay;
+    mWidth = overlay->w;
+    mHeight = overlay->h;
+    mFormat = overlay->format; 
+    mWidthStride = overlay->w_stride;
+    mHeightStride = overlay->h_stride;
+
+    mOverlayHandle = overlay->getHandleRef(overlay);
+    
+    // NOTE: here it's okay to acquire a reference to "this"m as long as
+    // the reference is not released before we leave the ctor.
+    sp<OverlayChannel> channel = new OverlayChannel(this);
+
+    *overlayRef = new OverlayRef(mOverlayHandle, channel,
+            mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
+}
+
+LayerBuffer::OverlaySource::~OverlaySource()
+{
+    if (mOverlay && mOverlayDevice) {
+        overlay_control_device_t* overlay_dev = mOverlayDevice;
+        overlay_dev->destroyOverlay(overlay_dev, mOverlay);
+    }
+}
+
+void LayerBuffer::OverlaySource::onTransaction(uint32_t flags)
+{
+    const Layer::State& front(mLayer.drawingState());
+    const Layer::State& temp(mLayer.currentState());
+    if (temp.sequence != front.sequence) {
+        mVisibilityChanged = true;
+    }
+}
+
+void LayerBuffer::OverlaySource::onVisibilityResolved(
+        const Transform& planeTransform)
+{
+    // this code-path must be as tight as possible, it's called each time
+    // the screen is composited.
+    if (UNLIKELY(mOverlay != 0)) {
+        if (mVisibilityChanged) {
+            mVisibilityChanged = false;
+            const Rect& bounds = mLayer.getTransformedBounds();
+            int x = bounds.left;
+            int y = bounds.top;
+            int w = bounds.width();
+            int h = bounds.height();
+            
+            // we need a lock here to protect "destroy"
+            Mutex::Autolock _l(mLock);
+            if (mOverlay) {
+                overlay_control_device_t* overlay_dev = mOverlayDevice;
+                overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h);
+                overlay_dev->setParameter(overlay_dev, mOverlay, 
+                        OVERLAY_TRANSFORM, mLayer.getOrientation());
+            }
+        }
+    }
+}
+
+void LayerBuffer::OverlaySource::serverDestroy() 
+{
+    mLayer.clearSource();
+    destroyOverlay();
+}
+
+void LayerBuffer::OverlaySource::destroyOverlay() 
+{
+    // we need a lock here to protect "onVisibilityResolved"
+    Mutex::Autolock _l(mLock);
+    if (mOverlay) {
+        overlay_control_device_t* overlay_dev = mOverlayDevice;
+        overlay_dev->destroyOverlay(overlay_dev, mOverlay);
+        mOverlay = 0;
+    }
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
new file mode 100644
index 0000000..2dc77f1
--- /dev/null
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_LAYER_BUFFER_H
+#define ANDROID_LAYER_BUFFER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/IMemory.h>
+#include <private/ui/LayerState.h>
+#include <EGL/eglnatives.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MemoryDealer;
+class Region;
+class OverlayRef;
+
+class LayerBuffer : public LayerBaseClient
+{
+    class Source : public LightRefBase<Source> {
+    public:
+        Source(LayerBuffer& layer);
+        virtual ~Source();
+        virtual void onDraw(const Region& clip) const;
+        virtual void onTransaction(uint32_t flags);
+        virtual void onVisibilityResolved(const Transform& planeTransform);
+        virtual void postBuffer(ssize_t offset);
+        virtual void unregisterBuffers();
+        virtual bool transformed() const;
+    protected:
+        LayerBuffer& mLayer;
+    };
+
+
+public:
+    static const uint32_t typeInfo;
+    static const char* const typeID;
+    virtual char const* getTypeID() const { return typeID; }
+    virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+            LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
+                        Client* client, int32_t i);
+        virtual ~LayerBuffer();
+
+    virtual bool needsBlending() const;
+
+    virtual sp<LayerBaseClient::Surface> getSurface() const;
+    virtual void onDraw(const Region& clip) const;
+    virtual uint32_t doTransaction(uint32_t flags);
+    virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+    virtual bool transformed() const;
+
+    status_t registerBuffers(const ISurface::BufferHeap& buffers);
+    void postBuffer(ssize_t offset);
+    void unregisterBuffers();
+    sp<OverlayRef> createOverlay(uint32_t w, uint32_t h, int32_t format);
+    
+    sp<Source> getSource() const;
+    sp<Source> clearSource();
+    void setNeedsBlending(bool blending);
+    const Rect& getTransformedBounds() const {
+        return mTransformedBounds;
+    }
+
+private:
+    struct NativeBuffer {
+        copybit_image_t   img;
+        copybit_rect_t    crop;
+    };
+
+    class Buffer : public LightRefBase<Buffer> {
+    public:
+        Buffer(const ISurface::BufferHeap& buffers, ssize_t offset);
+        inline status_t getStatus() const {
+            return mBufferHeap.heap!=0 ? NO_ERROR : NO_INIT;
+        }
+        inline const NativeBuffer& getBuffer() const {
+            return mNativeBuffer;
+        }
+    protected:
+        friend class LightRefBase<Buffer>;
+        Buffer& operator = (const Buffer& rhs);
+        Buffer(const Buffer& rhs);
+        ~Buffer();
+    private:
+        ISurface::BufferHeap    mBufferHeap;
+        NativeBuffer            mNativeBuffer;
+    };
+
+    class BufferSource : public Source {
+    public:
+        BufferSource(LayerBuffer& layer, const ISurface::BufferHeap& buffers);
+        virtual ~BufferSource();
+
+        status_t getStatus() const { return mStatus; }
+        sp<Buffer> getBuffer() const;
+        void setBuffer(const sp<Buffer>& buffer);
+
+        virtual void onDraw(const Region& clip) const;
+        virtual void postBuffer(ssize_t offset);
+        virtual void unregisterBuffers();
+        virtual bool transformed() const;
+    private:
+        mutable Mutex   mLock;
+        sp<Buffer>      mBuffer;
+        status_t        mStatus;
+        ISurface::BufferHeap mBufferHeap;
+        size_t          mBufferSize;
+        mutable sp<MemoryDealer> mTemporaryDealer;
+        mutable LayerBitmap mTempBitmap;
+        mutable GLuint  mTextureName;
+    };
+    
+    class OverlaySource : public Source {
+    public:
+        OverlaySource(LayerBuffer& layer,
+                sp<OverlayRef>* overlayRef, 
+                uint32_t w, uint32_t h, int32_t format);
+        virtual ~OverlaySource();
+        virtual void onTransaction(uint32_t flags);
+        virtual void onVisibilityResolved(const Transform& planeTransform);
+    private:
+        void serverDestroy(); 
+        void destroyOverlay(); 
+        class OverlayChannel : public BnOverlay {
+            mutable Mutex mLock;
+            sp<OverlaySource> mSource;
+            virtual void destroy() {
+                sp<OverlaySource> source;
+                { // scope for the lock;
+                    Mutex::Autolock _l(mLock);
+                    source = mSource;
+                    mSource.clear();
+                }
+                if (source != 0) {
+                    source->serverDestroy();
+                }
+            }
+        public:
+            OverlayChannel(const sp<OverlaySource>& source)
+                : mSource(source) {
+            }
+        };
+        friend class OverlayChannel;
+        bool mVisibilityChanged;
+
+        overlay_t* mOverlay;        
+        overlay_handle_t mOverlayHandle;
+        overlay_control_device_t* mOverlayDevice;
+        uint32_t mWidth;
+        uint32_t mHeight;
+        int32_t mFormat;
+        int32_t mWidthStride;
+        int32_t mHeightStride;
+        mutable Mutex mLock;
+    };
+
+
+    class SurfaceBuffer : public LayerBaseClient::Surface
+    {
+    public:
+                SurfaceBuffer(SurfaceID id, LayerBuffer* owner);
+        virtual ~SurfaceBuffer();
+        virtual status_t onTransact(
+            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+        virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
+        virtual void postBuffer(ssize_t offset);
+        virtual void unregisterBuffers();
+        virtual sp<OverlayRef> createOverlay(
+                uint32_t w, uint32_t h, int32_t format);
+       void disown();
+    private:
+        LayerBuffer* getOwner() const {
+            Mutex::Autolock _l(mLock);
+            return mOwner;
+        }
+        mutable Mutex   mLock;
+        LayerBuffer*    mOwner;
+    };
+
+    friend class SurfaceFlinger;
+    sp<SurfaceBuffer>   getClientSurface() const;
+
+    mutable Mutex   mLock;
+    sp<Source>      mSource;
+
+    bool            mInvalidate;
+    bool            mNeedsBlending;
+    mutable wp<SurfaceBuffer> mClientSurface;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BUFFER_H
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
new file mode 100644
index 0000000..0c347cc
--- /dev/null
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "LayerDim.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerDim::typeInfo = LayerBaseClient::typeInfo | 0x10;
+const char* const LayerDim::typeID = "LayerDim";
+sp<MemoryDealer> LayerDim::mDimmerDealer;
+LayerBitmap LayerDim::mDimmerBitmap;
+
+// ---------------------------------------------------------------------------
+
+LayerDim::LayerDim(SurfaceFlinger* flinger, DisplayID display,
+        Client* client, int32_t i)
+     : LayerBaseClient(flinger, display, client, i)
+{
+}
+
+void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h)
+{
+    // must only be called once.
+    mDimmerDealer = flinger->getSurfaceHeapManager()
+            ->createHeap(ISurfaceComposer::eHardware);
+    if (mDimmerDealer != 0) {
+        mDimmerBitmap.init(mDimmerDealer);
+        mDimmerBitmap.setBits(w, h, 1, PIXEL_FORMAT_RGB_565);
+        mDimmerBitmap.clear();
+    }
+}
+
+LayerDim::~LayerDim()
+{
+}
+
+void LayerDim::onDraw(const Region& clip) const
+{
+    const State& s(drawingState());
+
+    Region::iterator iterator(clip);
+    if (s.alpha>0 && iterator) {
+        const DisplayHardware& hw(graphicPlane(0).displayHardware());
+
+        status_t err = NO_ERROR;
+        const int can_use_copybit = canUseCopybit();
+        if (can_use_copybit)  {
+            // StopWatch watch("copybit");
+            copybit_image_t dst;
+            hw.getDisplaySurface(&dst);
+            const copybit_rect_t& drect
+                = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
+
+            copybit_image_t src;
+            mDimmerBitmap.getBitmapSurface(&src);
+            const copybit_rect_t& srect(drect);
+
+            copybit_device_t* copybit = mFlinger->getBlitEngine();
+            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+            copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+            region_iterator it(clip);
+            err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+        }
+
+        if (!can_use_copybit || err) {
+            const GGLfixed alpha = (s.alpha << 16)/255;
+            const uint32_t fbHeight = hw.getHeight();
+            glDisable(GL_TEXTURE_2D);
+            glDisable(GL_DITHER);
+            glEnable(GL_BLEND);
+            glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+            glColor4x(0, 0, 0, alpha);
+            glVertexPointer(2, GL_FIXED, 0, mVertices);
+            Rect r;
+            while (iterator.iterate(&r)) {
+                const GLint sy = fbHeight - (r.top + r.height());
+                glScissor(r.left, sy, r.width(), r.height());
+                glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
+            }
+        }
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerDim.h b/libs/surfaceflinger/LayerDim.h
new file mode 100644
index 0000000..3e37a47
--- /dev/null
+++ b/libs/surfaceflinger/LayerDim.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_LAYER_DIM_H
+#define ANDROID_LAYER_DIM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class LayerDim : public LayerBaseClient
+{
+public:    
+    static const uint32_t typeInfo;
+    static const char* const typeID;
+    virtual char const* getTypeID() const { return typeID; }
+    virtual uint32_t getTypeInfo() const { return typeInfo; }
+    
+                LayerDim(SurfaceFlinger* flinger, DisplayID display,
+                        Client* client, int32_t i);
+        virtual ~LayerDim();
+
+    virtual void onDraw(const Region& clip) const;
+    virtual bool needsBlending() const  { return true; }
+    virtual bool isSecure() const       { return false; }
+
+    static void initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h);
+
+private:
+    static sp<MemoryDealer> mDimmerDealer;
+    static LayerBitmap mDimmerBitmap;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_DIM_H
diff --git a/libs/surfaceflinger/LayerOrientationAnim.cpp b/libs/surfaceflinger/LayerOrientationAnim.cpp
new file mode 100644
index 0000000..2b72d7c
--- /dev/null
+++ b/libs/surfaceflinger/LayerOrientationAnim.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <core/SkBitmap.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnim::typeInfo = LayerBase::typeInfo | 0x80;
+const char* const LayerOrientationAnim::typeID = "LayerOrientationAnim";
+
+// ---------------------------------------------------------------------------
+
+LayerOrientationAnim::LayerOrientationAnim(
+        SurfaceFlinger* flinger, DisplayID display, 
+        OrientationAnimation* anim, 
+        const LayerBitmap& bitmap,
+        const LayerBitmap& bitmapIn)
+    : LayerBase(flinger, display), mAnim(anim), 
+      mBitmap(bitmap), mBitmapIn(bitmapIn), 
+      mTextureName(-1), mTextureNameIn(-1)
+{
+    mStartTime = systemTime();
+    mFinishTime = 0;
+    mOrientationCompleted = false;
+    mFirstRedraw = false;
+    mLastNormalizedTime = 0;
+    mLastScale = 0;
+    mNeedsBlending = false;
+}
+
+LayerOrientationAnim::~LayerOrientationAnim()
+{
+    if (mTextureName != -1U) {
+        LayerBase::deletedTextures.add(mTextureName);
+    }
+    if (mTextureNameIn != -1U) {
+        LayerBase::deletedTextures.add(mTextureNameIn);
+    }
+}
+
+bool LayerOrientationAnim::needsBlending() const 
+{
+    return mNeedsBlending; 
+}
+
+Point LayerOrientationAnim::getPhysicalSize() const
+{
+    const GraphicPlane& plane(graphicPlane(0));
+    const DisplayHardware& hw(plane.displayHardware());
+    return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnim::validateVisibility(const Transform&)
+{
+    const Layer::State& s(drawingState());
+    const Transform tr(s.transform);
+    const Point size(getPhysicalSize());
+    uint32_t w = size.x;
+    uint32_t h = size.y;
+    mTransformedBounds = tr.makeBounds(w, h);
+    mLeft = tr.tx();
+    mTop  = tr.ty();
+    transparentRegionScreen.clear();
+    mTransformed = true;
+    mCanUseCopyBit = false;
+    copybit_device_t* copybit = mFlinger->getBlitEngine();
+    if (copybit) { 
+        mCanUseCopyBit = true;
+    }
+}
+
+void LayerOrientationAnim::onOrientationCompleted()
+{
+    mFinishTime = systemTime();
+    mOrientationCompleted = true;
+    mFirstRedraw = true;
+    mNeedsBlending = true;
+    mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnim::onDraw(const Region& clip) const
+{
+    // Animation...
+    const float MIN_SCALE = 0.5f;
+    const float DURATION = ms2ns(200);
+    const float BOUNCES_PER_SECOND = 1.618f;
+    const float BOUNCES_AMPLITUDE = 1.0f/32.0f;
+
+    const nsecs_t now = systemTime();
+    float scale, alpha;
+    
+    if (mOrientationCompleted) {
+        if (mFirstRedraw) {
+            mFirstRedraw = false;
+            
+            // make a copy of what's on screen
+            copybit_image_t image;
+            mBitmapIn.getBitmapSurface(&image);
+            const DisplayHardware& hw(graphicPlane(0).displayHardware());
+            hw.copyBackToImage(image);
+
+            // and erase the screen for this round
+            glDisable(GL_BLEND);
+            glDisable(GL_DITHER);
+            glDisable(GL_SCISSOR_TEST);
+            glClearColor(0,0,0,0);
+            glClear(GL_COLOR_BUFFER_BIT);
+            
+            // FIXME: code below is gross
+            mNeedsBlending = false;
+            LayerOrientationAnim* self(const_cast<LayerOrientationAnim*>(this));
+            mFlinger->invalidateLayerVisibility(self);
+        }
+
+        // make sure pick-up where we left off
+        const float duration = DURATION * mLastNormalizedTime;
+        const float normalizedTime = (float(now - mFinishTime) / duration);
+        if (normalizedTime <= 1.0f) {
+            const float squaredTime = normalizedTime*normalizedTime;
+            scale = (1.0f - mLastScale)*squaredTime + mLastScale;
+            alpha = (1.0f - normalizedTime);
+            alpha *= alpha;
+            alpha *= alpha;
+        } else {
+            mAnim->onAnimationFinished();
+            scale = 1.0f;
+            alpha = 0.0f;
+        }
+    } else {
+        const float normalizedTime = float(now - mStartTime) / DURATION;
+        if (normalizedTime <= 1.0f) {
+            mLastNormalizedTime = normalizedTime;
+            const float squaredTime = normalizedTime*normalizedTime;
+            scale = (MIN_SCALE-1.0f)*squaredTime + 1.0f;
+            alpha = 1.0f;
+        } else {
+            mLastNormalizedTime = 1.0f;
+            const float to_seconds = DURATION / seconds(1);
+            const float phi = BOUNCES_PER_SECOND * 
+                    (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+            scale = MIN_SCALE + BOUNCES_AMPLITUDE * (1.0f - cosf(phi));
+            alpha = 1.0f;
+        }
+        mLastScale = scale;
+    }
+    drawScaled(scale, alpha);
+}
+
+void LayerOrientationAnim::drawScaled(float f, float alpha) const
+{
+    copybit_image_t dst;
+    const GraphicPlane& plane(graphicPlane(0));
+    const DisplayHardware& hw(plane.displayHardware());
+    hw.getDisplaySurface(&dst);
+
+    // clear screen
+    // TODO: with update on demand, we may be able 
+    // to not erase the screen at all during the animation 
+    if (!mOrientationCompleted) {
+        glDisable(GL_BLEND);
+        glDisable(GL_DITHER);
+        glDisable(GL_SCISSOR_TEST);
+        glClearColor(0,0,0,0);
+        glClear(GL_COLOR_BUFFER_BIT);
+    }
+    
+    const int w = dst.w*f; 
+    const int h = dst.h*f; 
+    const int xc = uint32_t(dst.w-w)/2;
+    const int yc = uint32_t(dst.h-h)/2;
+    const copybit_rect_t drect = { xc, yc, xc+w, yc+h }; 
+
+    copybit_image_t src;
+    mBitmap.getBitmapSurface(&src);
+    const copybit_rect_t srect = { 0, 0, src.w, src.h };
+
+    int err = NO_ERROR;
+    const int can_use_copybit = canUseCopybit();
+    if (can_use_copybit)  {
+        copybit_device_t* copybit = mFlinger->getBlitEngine();
+        copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+        copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+
+        if (alpha < 1.0f) {
+            copybit_image_t srcIn;
+            mBitmapIn.getBitmapSurface(&srcIn);
+            region_iterator it(Region(Rect( drect.l, drect.t, drect.r, drect.b )));
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+            err = copybit->stretch(copybit, &dst, &srcIn, &drect, &srect, &it);
+        }
+
+        if (!err && alpha > 0.0f) {
+            region_iterator it(Region(Rect( drect.l, drect.t, drect.r, drect.b )));
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, int(alpha*255));
+            err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+        }
+        LOGE_IF(err != NO_ERROR, "copybit failed (%s)", strerror(err));
+    }
+    if (!can_use_copybit || err) {   
+        GGLSurface t;
+        t.version = sizeof(GGLSurface);
+        t.width  = src.w;
+        t.height = src.h;
+        t.stride = src.w;
+        t.vstride= src.h;
+        t.format = src.format;
+        t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+        Transform tr;
+        tr.set(f,0,0,f);
+        tr.set(xc, yc);
+        
+        // FIXME: we should not access mVertices and mDrawingState like that,
+        // but since we control the animation, we know it's going to work okay.
+        // eventually we'd need a more formal way of doing things like this.
+        LayerOrientationAnim& self(const_cast<LayerOrientationAnim&>(*this));
+        tr.transform(self.mVertices[0], 0, 0);
+        tr.transform(self.mVertices[1], 0, src.h);
+        tr.transform(self.mVertices[2], src.w, src.h);
+        tr.transform(self.mVertices[3], src.w, 0);
+        if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+            // Too slow to do this in software
+            self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+        }
+
+        if (alpha < 1.0f) {
+            copybit_image_t src;
+            mBitmapIn.getBitmapSurface(&src);
+            t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+            if (UNLIKELY(mTextureNameIn == -1LU)) {
+                mTextureNameIn = createTexture();
+                GLuint w=0, h=0;
+                const Region dirty(Rect(t.width, t.height));
+                loadTexture(dirty, mTextureNameIn, t, w, h);
+            }
+            self.mDrawingState.alpha = 255;
+            const Region clip(Rect( drect.l, drect.t, drect.r, drect.b ));
+            drawWithOpenGL(clip, mTextureName, t);
+        }
+
+        t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+        if (UNLIKELY(mTextureName == -1LU)) {
+            mTextureName = createTexture();
+            GLuint w=0, h=0;
+            const Region dirty(Rect(t.width, t.height));
+            loadTexture(dirty, mTextureName, t, w, h);
+        }
+        self.mDrawingState.alpha = int(alpha*255);
+        const Region clip(Rect( drect.l, drect.t, drect.r, drect.b ));
+        drawWithOpenGL(clip, mTextureName, t);
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerOrientationAnim.h b/libs/surfaceflinger/LayerOrientationAnim.h
new file mode 100644
index 0000000..7367685
--- /dev/null
+++ b/libs/surfaceflinger/LayerOrientationAnim.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_LAYER_ORIENTATION_ANIM_H
+#define ANDROID_LAYER_ORIENTATION_ANIM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <utils/Parcel.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+class OrientationAnimation;
+
+class LayerOrientationAnim : public LayerBase
+{
+public:    
+    static const uint32_t typeInfo;
+    static const char* const typeID;
+    virtual char const* getTypeID() const { return typeID; }
+    virtual uint32_t getTypeInfo() const { return typeInfo; }
+    
+                LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
+                        OrientationAnimation* anim, 
+                        const LayerBitmap& zoomOut,
+                        const LayerBitmap& zoomIn);
+        virtual ~LayerOrientationAnim();
+
+            void onOrientationCompleted();
+
+    virtual void onDraw(const Region& clip) const;
+    virtual Point getPhysicalSize() const;
+    virtual void validateVisibility(const Transform& globalTransform);
+    virtual bool needsBlending() const;
+    virtual bool isSecure() const       { return false; }
+private:
+    void drawScaled(float scale, float alpha) const;
+
+    OrientationAnimation* mAnim;
+    LayerBitmap mBitmap;
+    LayerBitmap mBitmapIn;
+    nsecs_t mStartTime;
+    nsecs_t mFinishTime;
+    bool mOrientationCompleted;
+    mutable bool mFirstRedraw;
+    mutable float mLastNormalizedTime;
+    mutable float mLastScale;
+    mutable GLuint  mTextureName;
+    mutable GLuint  mTextureNameIn;
+    mutable bool mNeedsBlending;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_ORIENTATION_ANIM_H
diff --git a/libs/surfaceflinger/MODULE_LICENSE_APACHE2 b/libs/surfaceflinger/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/surfaceflinger/MODULE_LICENSE_APACHE2
diff --git a/libs/surfaceflinger/OrientationAnimation.cpp b/libs/surfaceflinger/OrientationAnimation.cpp
new file mode 100644
index 0000000..f6f1326
--- /dev/null
+++ b/libs/surfaceflinger/OrientationAnimation.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include "LayerOrientationAnim.h"
+#include "OrientationAnimation.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+OrientationAnimation::OrientationAnimation(const sp<SurfaceFlinger>& flinger)
+    : mFlinger(flinger), mLayerOrientationAnim(NULL), mState(DONE)
+{
+    // allocate a memory-dealer for this the first time
+    mTemporaryDealer = mFlinger->getSurfaceHeapManager()->createHeap(
+            ISurfaceComposer::eHardware);
+}
+
+OrientationAnimation::~OrientationAnimation()
+{
+}
+
+void OrientationAnimation::onOrientationChanged()
+{
+    if (mState == DONE)
+        mState = PREPARE;
+}
+
+void OrientationAnimation::onAnimationFinished()
+{
+    if (mState != DONE)
+        mState = FINISH;
+}
+
+bool OrientationAnimation::run_impl()
+{
+    bool skip_frame;
+    switch (mState) {
+        default:
+        case DONE:
+            skip_frame = done();
+            break;
+        case PREPARE:
+            skip_frame = prepare();
+            break;
+        case PHASE1:
+            skip_frame = phase1();
+            break;
+        case PHASE2:
+            skip_frame = phase2();
+            break;
+        case FINISH:
+            skip_frame = finished();
+            break;
+    }
+    return skip_frame;
+}
+
+bool OrientationAnimation::done()
+{
+    if (mFlinger->isFrozen()) {
+        // we are not allowed to draw, but pause a bit to make sure
+        // apps don't end up using the whole CPU, if they depend on
+        // surfaceflinger for synchronization.
+        usleep(8333); // 8.3ms ~ 120fps
+        return true;
+    }
+    return false;
+}
+
+bool OrientationAnimation::prepare()
+{
+    mState = PHASE1;
+    
+    const GraphicPlane& plane(mFlinger->graphicPlane(0));
+    const DisplayHardware& hw(plane.displayHardware());
+    const uint32_t w = hw.getWidth();
+    const uint32_t h = hw.getHeight();
+
+    LayerBitmap bitmap;
+    bitmap.init(mTemporaryDealer);
+    bitmap.setBits(w, h, 1, hw.getFormat());
+
+    LayerBitmap bitmapIn;
+    bitmapIn.init(mTemporaryDealer);
+    bitmapIn.setBits(w, h, 1, hw.getFormat());
+
+    copybit_image_t front;
+    bitmap.getBitmapSurface(&front);
+    hw.copyFrontToImage(front);
+
+    LayerOrientationAnim* l = new LayerOrientationAnim(
+            mFlinger.get(), 0, this, bitmap, bitmapIn);
+    l->initStates(w, h, 0);
+    l->setLayer(INT_MAX-1);
+    mFlinger->addLayer(l);
+    mLayerOrientationAnim = l;
+    return true;
+}
+
+bool OrientationAnimation::phase1()
+{
+    if (mFlinger->isFrozen() == false) {
+        // start phase 2
+        mState = PHASE2;
+        mLayerOrientationAnim->onOrientationCompleted();
+        mLayerOrientationAnim->invalidate();
+        return true;
+        
+    }
+    mLayerOrientationAnim->invalidate();
+    return false;
+}
+
+bool OrientationAnimation::phase2()
+{
+    // do the 2nd phase of the animation
+    mLayerOrientationAnim->invalidate();
+    return false;
+}
+
+bool OrientationAnimation::finished()
+{
+    mState = DONE;
+    mFlinger->removeLayer(mLayerOrientationAnim);
+    mLayerOrientationAnim = NULL;
+    return true;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/OrientationAnimation.h b/libs/surfaceflinger/OrientationAnimation.h
new file mode 100644
index 0000000..ba33fce
--- /dev/null
+++ b/libs/surfaceflinger/OrientationAnimation.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_ORIENTATION_ANIMATION_H
+#define ANDROID_ORIENTATION_ANIMATION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class SurfaceFlinger;
+class MemoryDealer;
+class LayerOrientationAnim;
+
+class OrientationAnimation
+{
+public:    
+                 OrientationAnimation(const sp<SurfaceFlinger>& flinger);
+        virtual ~OrientationAnimation();
+
+   void onOrientationChanged();
+   void onAnimationFinished();
+   inline bool run() {
+       if (LIKELY(mState == DONE))
+           return false;
+       return run_impl();
+   }
+
+private:
+    enum {
+        DONE = 0,
+        PREPARE,
+        PHASE1,
+        PHASE2,
+        FINISH
+    };
+
+    bool run_impl();
+    bool done();
+    bool prepare();
+    bool phase1();
+    bool phase2();
+    bool finished();
+
+    sp<SurfaceFlinger> mFlinger;
+    sp<MemoryDealer> mTemporaryDealer;
+    LayerOrientationAnim* mLayerOrientationAnim;
+    int mState;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ORIENTATION_ANIMATION_H
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
new file mode 100644
index 0000000..900282a
--- /dev/null
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -0,0 +1,1840 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+#include <utils/MemoryDealer.h>
+#include <utils/MemoryBase.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/StopWatch.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/DisplayInfo.h>
+#include <ui/EGLDisplaySurface.h>
+
+#include <pixelflinger/pixelflinger.h>
+#include <GLES/gl.h>
+
+#include "clz.h"
+#include "CPUGauge.h"
+#include "Layer.h"
+#include "LayerBlur.h"
+#include "LayerBuffer.h"
+#include "LayerDim.h"
+#include "LayerBitmap.h"
+#include "LayerOrientationAnim.h"
+#include "OrientationAnimation.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+#include "DisplayHardware/DisplayHardware.h"
+#include "GPUHardware/GPUHardware.h"
+
+
+#define DISPLAY_COUNT       1
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+void SurfaceFlinger::instantiate() {
+    defaultServiceManager()->addService(
+            String16("SurfaceFlinger"), new SurfaceFlinger());
+}
+
+void SurfaceFlinger::shutdown() {
+    // we should unregister here, but not really because
+    // when (if) the service manager goes away, all the services
+    // it has a reference to will leave too.
+}
+
+// ---------------------------------------------------------------------------
+
+SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs)
+    : lookup(rhs.lookup), layers(rhs.layers)
+{
+}
+
+ssize_t SurfaceFlinger::LayerVector::indexOf(
+        LayerBase* key, size_t guess) const
+{
+    if (guess<size() && lookup.keyAt(guess) == key)
+        return guess;
+    const ssize_t i = lookup.indexOfKey(key);
+    if (i>=0) {
+        const size_t idx = lookup.valueAt(i);
+        LOG_ASSERT(layers[idx]==key,
+            "LayerVector[%p]: layers[%d]=%p, key=%p",
+            this, int(idx), layers[idx], key);
+        return idx;
+    }
+    return i;
+}
+
+ssize_t SurfaceFlinger::LayerVector::add(
+        LayerBase* layer,
+        Vector<LayerBase*>::compar_t cmp)
+{
+    size_t count = layers.size();
+    ssize_t l = 0;
+    ssize_t h = count-1;
+    ssize_t mid;
+    LayerBase* const* a = layers.array();
+    while (l <= h) {
+        mid = l + (h - l)/2;
+        const int c = cmp(a+mid, &layer);
+        if (c == 0)     { l = mid; break; }
+        else if (c<0)   { l = mid+1; }
+        else            { h = mid-1; }
+    }
+    size_t order = l;
+    while (order<count && !cmp(&layer, a+order)) {
+        order++;
+    }
+    count = lookup.size();
+    for (size_t i=0 ; i<count ; i++) {
+        if (lookup.valueAt(i) >= order) {
+            lookup.editValueAt(i)++;
+        }
+    }
+    layers.insertAt(layer, order);
+    lookup.add(layer, order);
+    return order;
+}
+
+ssize_t SurfaceFlinger::LayerVector::remove(LayerBase* layer)
+{
+    const ssize_t keyIndex = lookup.indexOfKey(layer);
+    if (keyIndex >= 0) {
+        const size_t index = lookup.valueAt(keyIndex);
+        LOG_ASSERT(layers[index]==layer,
+                "LayerVector[%p]: layers[%u]=%p, layer=%p",
+                this, int(index), layers[index], layer);
+        layers.removeItemsAt(index);
+        lookup.removeItemsAt(keyIndex);
+        const size_t count = lookup.size();
+        for (size_t i=0 ; i<count ; i++) {
+            if (lookup.valueAt(i) >= size_t(index)) {
+                lookup.editValueAt(i)--;
+            }
+        }
+        return index;
+    }
+    return NAME_NOT_FOUND;
+}
+
+ssize_t SurfaceFlinger::LayerVector::reorder(
+        LayerBase* layer,
+        Vector<LayerBase*>::compar_t cmp)
+{
+    // XXX: it's a little lame. but oh well...
+    ssize_t err = remove(layer);
+    if (err >=0)
+        err = add(layer, cmp);
+    return err;
+}
+
+// ---------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+SurfaceFlinger::SurfaceFlinger()
+    :   BnSurfaceComposer(), Thread(false),
+        mTransactionFlags(0),
+        mTransactionCount(0),
+        mBootTime(systemTime()),
+        mLastScheduledBroadcast(NULL),
+        mVisibleRegionsDirty(false),
+        mDeferReleaseConsole(false),
+        mFreezeDisplay(false),
+        mFreezeCount(0),
+        mDebugRegion(0),
+        mDebugCpu(0),
+        mDebugFps(0),
+        mDebugBackground(0),
+        mDebugNoBootAnimation(0),
+        mSyncObject(),
+        mDeplayedTransactionPending(0),
+        mConsoleSignals(0),
+        mSecureFrameBuffer(0)
+{
+    init();
+}
+
+void SurfaceFlinger::init()
+{
+    LOGI("SurfaceFlinger is starting");
+
+    // debugging stuff...
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.sf.showupdates", value, "0");
+    mDebugRegion = atoi(value);
+    property_get("debug.sf.showcpu", value, "0");
+    mDebugCpu = atoi(value);
+    property_get("debug.sf.showbackground", value, "0");
+    mDebugBackground = atoi(value);
+    property_get("debug.sf.showfps", value, "0");
+    mDebugFps = atoi(value);
+    property_get("debug.sf.nobootanimation", value, "0");
+    mDebugNoBootAnimation = atoi(value);
+
+    LOGI_IF(mDebugRegion,           "showupdates enabled");
+    LOGI_IF(mDebugCpu,              "showcpu enabled");
+    LOGI_IF(mDebugBackground,       "showbackground enabled");
+    LOGI_IF(mDebugFps,              "showfps enabled");
+    LOGI_IF(mDebugNoBootAnimation,  "boot animation disabled");
+}
+
+SurfaceFlinger::~SurfaceFlinger()
+{
+    glDeleteTextures(1, &mWormholeTexName);
+    delete mOrientationAnimation;
+}
+
+copybit_device_t* SurfaceFlinger::getBlitEngine() const
+{
+    return graphicPlane(0).displayHardware().getBlitEngine();
+}
+
+overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const
+{
+    return graphicPlane(0).displayHardware().getOverlayEngine();
+}
+
+sp<IMemory> SurfaceFlinger::getCblk() const
+{
+    return mServerCblkMemory;
+}
+
+status_t SurfaceFlinger::requestGPU(const sp<IGPUCallback>& callback,
+        gpu_info_t* gpu)
+{
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    status_t err = mGPU->request(pid, callback, gpu);
+    return err;
+}
+
+status_t SurfaceFlinger::revokeGPU()
+{
+    return mGPU->friendlyRevoke();
+}
+
+sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()
+{
+    Mutex::Autolock _l(mStateLock);
+    uint32_t token = mTokens.acquire();
+
+    Client* client = new Client(token, this);
+    if ((client == 0) || (client->ctrlblk == 0)) {
+        mTokens.release(token);
+        return 0;
+    }
+    status_t err = mClientsMap.add(token, client);
+    if (err < 0) {
+        delete client;
+        mTokens.release(token);
+        return 0;
+    }
+    sp<BClient> bclient =
+        new BClient(this, token, client->controlBlockMemory());
+    return bclient;
+}
+
+void SurfaceFlinger::destroyConnection(ClientID cid)
+{
+    Mutex::Autolock _l(mStateLock);
+    Client* const client = mClientsMap.valueFor(cid);
+    if (client) {
+        // free all the layers this client owns
+        const Vector<LayerBaseClient*>& layers = client->getLayers();
+        const size_t count = layers.size();
+        for (size_t i=0 ; i<count ; i++) {
+            LayerBaseClient* const layer = layers[i];
+            removeLayer_l(layer);
+        }
+
+        // the resources associated with this client will be freed
+        // during the next transaction, after these surfaces have been
+        // properly removed from the screen
+
+        // remove this client from our ClientID->Client mapping.
+        mClientsMap.removeItem(cid);
+
+        // and add it to the list of disconnected clients
+        mDisconnectedClients.add(client);
+
+        // request a transaction
+        setTransactionFlags(eTransactionNeeded);
+    }
+}
+
+const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const
+{
+    LOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy);
+    const GraphicPlane& plane(mGraphicPlanes[dpy]);
+    return plane;
+}
+
+GraphicPlane& SurfaceFlinger::graphicPlane(int dpy)
+{
+    return const_cast<GraphicPlane&>(
+        const_cast<SurfaceFlinger const *>(this)->graphicPlane(dpy));
+}
+
+void SurfaceFlinger::bootFinished()
+{
+    const nsecs_t now = systemTime();
+    const nsecs_t duration = now - mBootTime;
+    LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
+    if (mBootAnimation != 0) {
+        mBootAnimation->requestExit();
+        mBootAnimation.clear();
+    }
+}
+
+void SurfaceFlinger::onFirstRef()
+{
+    run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
+
+    // Wait for the main thread to be done with its initialization
+    mReadyToRunBarrier.wait();
+}
+
+
+static inline uint16_t pack565(int r, int g, int b) {
+    return (r<<11)|(g<<5)|b;
+}
+
+// this is defined in libGLES_CM.so
+extern ISurfaceComposer* GLES_localSurfaceManager;
+
+status_t SurfaceFlinger::readyToRun()
+{
+    LOGI(   "SurfaceFlinger's main thread ready to run. "
+            "Initializing graphics H/W...");
+
+    // create the shared control-block
+    mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);
+    LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
+
+    mServerCblkMemory = mServerHeap->allocate(4096);
+    LOGE_IF(mServerCblkMemory==0, "can't create shared control block");
+
+    mServerCblk = static_cast<surface_flinger_cblk_t *>(mServerCblkMemory->pointer());
+    LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
+    new(mServerCblk) surface_flinger_cblk_t;
+
+    // get a reference to the GPU if we have one
+    mGPU = GPUFactory::getGPU();
+
+    // create the surface Heap manager, which manages the heaps
+    // (be it in RAM or VRAM) where surfaces are allocated
+    // We give 8 MB per client.
+    mSurfaceHeapManager = new SurfaceHeapManager(this, 8 << 20);
+
+    
+    GLES_localSurfaceManager = static_cast<ISurfaceComposer*>(this);
+
+    // we only support one display currently
+    int dpy = 0;
+
+    {
+        // initialize the main display
+        GraphicPlane& plane(graphicPlane(dpy));
+        DisplayHardware* const hw = new DisplayHardware(this, dpy);
+        plane.setDisplayHardware(hw);
+    }
+
+    // initialize primary screen
+    // (other display should be initialized in the same manner, but
+    // asynchronously, as they could come and go. None of this is supported
+    // yet).
+    const GraphicPlane& plane(graphicPlane(dpy));
+    const DisplayHardware& hw = plane.displayHardware();
+    const uint32_t w = hw.getWidth();
+    const uint32_t h = hw.getHeight();
+    const uint32_t f = hw.getFormat();
+    hw.makeCurrent();
+
+    // initialize the shared control block
+    mServerCblk->connected |= 1<<dpy;
+    display_cblk_t* dcblk = mServerCblk->displays + dpy;
+    memset(dcblk, 0, sizeof(display_cblk_t));
+    dcblk->w            = w;
+    dcblk->h            = h;
+    dcblk->format       = f;
+    dcblk->orientation  = ISurfaceComposer::eOrientationDefault;
+    dcblk->xdpi         = hw.getDpiX();
+    dcblk->ydpi         = hw.getDpiY();
+    dcblk->fps          = hw.getRefreshRate();
+    dcblk->density      = hw.getDensity();
+    asm volatile ("":::"memory");
+
+    // Initialize OpenGL|ES
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+    glPixelStorei(GL_PACK_ALIGNMENT, 4); 
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glEnable(GL_SCISSOR_TEST);
+    glShadeModel(GL_FLAT);
+    glDisable(GL_DITHER);
+    glDisable(GL_CULL_FACE);
+
+    const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
+    const uint16_t g1 = pack565(0x17,0x2f,0x17);
+    const uint16_t textureData[4] = { g0, g1, g1, g0 };
+    glGenTextures(1, &mWormholeTexName);
+    glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
+            GL_RGB, GL_UNSIGNED_SHORT_5_6_5, textureData);
+
+    glViewport(0, 0, w, h);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrthof(0, w, h, 0, 0, 1);
+
+   LayerDim::initDimmer(this, w, h);
+
+    mReadyToRunBarrier.open();
+
+    /*
+     *  We're now ready to accept clients...
+     */
+
+    mOrientationAnimation = new OrientationAnimation(this);
+    
+    // start CPU gauge display
+    if (mDebugCpu)
+        mCpuGauge = new CPUGauge(this, ms2ns(500));
+
+    // the boot animation!
+    if (mDebugNoBootAnimation == false)
+        mBootAnimation = new BootAnimation(this);
+
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Events Handler
+#endif
+
+void SurfaceFlinger::waitForEvent()
+{
+    // wait for something to do
+    if (UNLIKELY(isFrozen())) {
+        // wait 5 seconds
+        int err = mSyncObject.wait(ms2ns(5000));
+        if (err != NO_ERROR) {
+            if (isFrozen()) {
+                // we timed out and are still frozen
+                LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
+                        mFreezeDisplay, mFreezeCount);
+                mFreezeCount = 0;
+            }
+        }
+    } else {
+        mSyncObject.wait();
+    }
+}
+
+void SurfaceFlinger::signalEvent() {
+    mSyncObject.open();
+}
+
+void SurfaceFlinger::signal() const {
+    mSyncObject.open();
+}
+
+void SurfaceFlinger::signalDelayedEvent(nsecs_t delay)
+{
+    if (android_atomic_or(1, &mDeplayedTransactionPending) == 0) {
+        sp<DelayedTransaction> delayedEvent(new DelayedTransaction(this, delay));
+        delayedEvent->run("DelayedeEvent", PRIORITY_URGENT_DISPLAY);
+    }
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Main loop
+#endif
+
+bool SurfaceFlinger::threadLoop()
+{
+    waitForEvent();
+
+    // check for transactions
+    if (UNLIKELY(mConsoleSignals)) {
+        handleConsoleEvents();
+    }
+
+    if (LIKELY(mTransactionCount == 0)) {
+        // if we're in a global transaction, don't do anything.
+        const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+        uint32_t transactionFlags = getTransactionFlags(mask);
+        if (LIKELY(transactionFlags)) {
+            handleTransaction(transactionFlags);
+        }
+    }
+
+    // post surfaces (if needed)
+    handlePageFlip();
+
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    if (LIKELY(hw.canDraw())) {
+        // repaint the framebuffer (if needed)
+        handleRepaint();
+
+        // release the clients before we flip ('cause flip might block)
+        unlockClients();
+        executeScheduledBroadcasts();
+
+        // sample the cpu gauge
+        if (UNLIKELY(mDebugCpu)) {
+            handleDebugCpu();
+        }
+
+        postFramebuffer();
+    } else {
+        // pretend we did the post
+        unlockClients();
+        executeScheduledBroadcasts();
+        usleep(16667); // 60 fps period
+    }
+    return true;
+}
+
+void SurfaceFlinger::postFramebuffer()
+{
+    const bool skip = mOrientationAnimation->run();
+    if (UNLIKELY(skip)) {
+        return;
+    }
+
+    if (!mInvalidRegion.isEmpty()) {
+        const DisplayHardware& hw(graphicPlane(0).displayHardware());
+
+        if (UNLIKELY(mDebugFps)) {
+            debugShowFPS();
+        }
+
+        hw.flip(mInvalidRegion);
+
+        mInvalidRegion.clear();
+
+        if (Layer::deletedTextures.size()) {
+            glDeleteTextures(
+                    Layer::deletedTextures.size(),
+                    Layer::deletedTextures.array());
+            Layer::deletedTextures.clear();
+        }
+    }
+}
+
+void SurfaceFlinger::handleConsoleEvents()
+{
+    // something to do with the console
+    const DisplayHardware& hw = graphicPlane(0).displayHardware();
+
+    int what = android_atomic_and(0, &mConsoleSignals);
+    if (what & eConsoleAcquired) {
+        hw.acquireScreen();
+    }
+
+    if (mDeferReleaseConsole && hw.canDraw()) {
+        // We got the release signal before the aquire signal
+        mDeferReleaseConsole = false;
+        revokeGPU();
+        hw.releaseScreen();
+    }
+
+    if (what & eConsoleReleased) {
+        if (hw.canDraw()) {
+            revokeGPU();
+            hw.releaseScreen();
+        } else {
+            mDeferReleaseConsole = true;
+        }
+    }
+
+    mDirtyRegion.set(hw.bounds());
+}
+
+void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
+{
+    Mutex::Autolock _l(mStateLock);
+
+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+    const size_t count = currentLayers.size();
+
+    /*
+     * Traversal of the children
+     * (perform the transaction for each of them if needed)
+     */
+
+    const bool layersNeedTransaction = transactionFlags & eTraversalNeeded;
+    if (layersNeedTransaction) {
+        for (size_t i=0 ; i<count ; i++) {
+            LayerBase* const layer = currentLayers[i];
+            uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
+            if (!trFlags) continue;
+
+            const uint32_t flags = layer->doTransaction(0);
+            if (flags & Layer::eVisibleRegion)
+                mVisibleRegionsDirty = true;
+
+            if (flags & Layer::eRestartTransaction) {
+                // restart the transaction, but back-off a little
+                layer->setTransactionFlags(eTransactionNeeded);
+                setTransactionFlags(eTraversalNeeded, ms2ns(8));
+            }
+        }
+    }
+
+    /*
+     * Perform our own transaction if needed
+     */
+
+    if (transactionFlags & eTransactionNeeded) {
+        if (mCurrentState.orientation != mDrawingState.orientation) {
+            // the orientation has changed, recompute all visible regions
+            // and invalidate everything.
+
+            const int dpy = 0;
+            const int orientation = mCurrentState.orientation;
+            GraphicPlane& plane(graphicPlane(dpy));
+            plane.setOrientation(orientation);
+
+            // update the shared control block
+            const DisplayHardware& hw(plane.displayHardware());
+            volatile display_cblk_t* dcblk = mServerCblk->displays + dpy;
+            dcblk->orientation = orientation;
+            if (orientation & eOrientationSwapMask) {
+                // 90 or 270 degrees orientation
+                dcblk->w = hw.getHeight();
+                dcblk->h = hw.getWidth();
+            } else {
+                dcblk->w = hw.getWidth();
+                dcblk->h = hw.getHeight();
+            }
+
+            mVisibleRegionsDirty = true;
+            mDirtyRegion.set(hw.bounds());
+
+            mOrientationAnimation->onOrientationChanged();
+        }
+
+        if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
+            // freezing or unfreezing the display -> trigger animation if needed
+            mFreezeDisplay = mCurrentState.freezeDisplay;
+            const nsecs_t now = systemTime();
+            if (mFreezeDisplay) {
+                mFreezeDisplayTime = now;
+            } else {
+                //LOGD("Screen was frozen for %llu us",
+                //        ns2us(now-mFreezeDisplayTime));
+            }
+        }
+
+        // some layers might have been removed, so
+        // we need to update the regions they're exposing.
+        size_t c = mRemovedLayers.size();
+        if (c) {
+            mVisibleRegionsDirty = true;
+        }
+
+        const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+        if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
+            // layers have been added
+            mVisibleRegionsDirty = true;
+        }
+
+        // get rid of all resources we don't need anymore
+        // (layers and clients)
+        free_resources_l();
+    }
+
+    commitTransaction();
+}
+
+sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
+{
+    return new FreezeLock(const_cast<SurfaceFlinger *>(this));
+}
+
+void SurfaceFlinger::computeVisibleRegions(
+    LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
+{
+    const GraphicPlane& plane(graphicPlane(0));
+    const Transform& planeTransform(plane.transform());
+
+    Region aboveOpaqueLayers;
+    Region aboveCoveredLayers;
+    Region dirty;
+
+    bool secureFrameBuffer = false;
+
+    size_t i = currentLayers.size();
+    while (i--) {
+        LayerBase* const layer = currentLayers[i];
+        layer->validateVisibility(planeTransform);
+
+        // start with the whole surface at its current location
+        const Layer::State& s = layer->drawingState();
+        const Rect bounds(layer->visibleBounds());
+
+        // handle hidden surfaces by setting the visible region to empty
+        Region opaqueRegion;
+        Region visibleRegion;
+        Region coveredRegion;
+        if (UNLIKELY((s.flags & ISurfaceComposer::eLayerHidden) || !s.alpha)) {
+            visibleRegion.clear();
+        } else {
+            const bool translucent = layer->needsBlending();
+            visibleRegion.set(bounds);
+            coveredRegion = visibleRegion;
+
+            // Remove the transparent area from the visible region
+            if (translucent) {
+                visibleRegion.subtractSelf(layer->transparentRegionScreen);
+            }
+
+            // compute the opaque region
+            if (s.alpha==255 && !translucent && layer->getOrientation()>=0) {
+                // the opaque region is the visible region
+                opaqueRegion = visibleRegion;
+            }
+        }
+
+        // subtract the opaque region covered by the layers above us
+        visibleRegion.subtractSelf(aboveOpaqueLayers);
+        coveredRegion.andSelf(aboveCoveredLayers);
+
+        // compute this layer's dirty region
+        if (layer->contentDirty) {
+            // we need to invalidate the whole region
+            dirty = visibleRegion;
+            // as well, as the old visible region
+            dirty.orSelf(layer->visibleRegionScreen);
+            layer->contentDirty = false;
+        } else {
+            // compute the exposed region
+            // dirty = what's visible now - what's wasn't covered before
+            //       = what's visible now & what's was covered before
+            dirty = visibleRegion.intersect(layer->coveredRegionScreen);            
+        }
+        dirty.subtractSelf(aboveOpaqueLayers);
+
+        // accumulate to the screen dirty region
+        dirtyRegion.orSelf(dirty);
+
+        // updade aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer
+        aboveOpaqueLayers.orSelf(opaqueRegion);
+        aboveCoveredLayers.orSelf(bounds);
+        
+        // Store the visible region is screen space
+        layer->setVisibleRegion(visibleRegion);
+        layer->setCoveredRegion(coveredRegion);
+
+        // If a secure layer is partially visible, lockdown the screen!
+        if (layer->isSecure() && !visibleRegion.isEmpty()) {
+            secureFrameBuffer = true;
+        }
+    }
+
+    mSecureFrameBuffer = secureFrameBuffer;
+    opaqueRegion = aboveOpaqueLayers;
+}
+
+
+void SurfaceFlinger::commitTransaction()
+{
+    mDrawingState = mCurrentState;
+    mTransactionCV.signal();
+}
+
+void SurfaceFlinger::handlePageFlip()
+{
+    bool visibleRegions = mVisibleRegionsDirty;
+    LayerVector& currentLayers = const_cast<LayerVector&>(mDrawingState.layersSortedByZ);
+    visibleRegions |= lockPageFlip(currentLayers);
+
+        const DisplayHardware& hw = graphicPlane(0).displayHardware();
+        const Region screenRegion(hw.bounds());
+        if (visibleRegions) {
+            Region opaqueRegion;
+            computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
+            mWormholeRegion = screenRegion.subtract(opaqueRegion);
+            mVisibleRegionsDirty = false;
+        }
+
+    unlockPageFlip(currentLayers);
+    mDirtyRegion.andSelf(screenRegion);
+}
+
+bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)
+{
+    bool recomputeVisibleRegions = false;
+    size_t count = currentLayers.size();
+    LayerBase* const* layers = currentLayers.array();
+    for (size_t i=0 ; i<count ; i++) {
+        LayerBase* const layer = layers[i];
+        layer->lockPageFlip(recomputeVisibleRegions);
+    }
+    return recomputeVisibleRegions;
+}
+
+void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
+{
+    const GraphicPlane& plane(graphicPlane(0));
+    const Transform& planeTransform(plane.transform());
+    size_t count = currentLayers.size();
+    LayerBase* const* layers = currentLayers.array();
+    for (size_t i=0 ; i<count ; i++) {
+        LayerBase* const layer = layers[i];
+        layer->unlockPageFlip(planeTransform, mDirtyRegion);
+    }
+}
+
+void SurfaceFlinger::handleRepaint()
+{
+    // set the frame buffer
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    if (UNLIKELY(mDebugRegion)) {
+        debugFlashRegions();
+    }
+
+    // compute the invalid region
+    mInvalidRegion.orSelf(mDirtyRegion);
+
+    uint32_t flags = hw.getFlags();
+    if (flags & DisplayHardware::BUFFER_PRESERVED) {
+        // here we assume DisplayHardware::flip()'s  implementation
+        // performs the copy-back optimization.
+    } else {
+        if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
+            // we need to fully redraw the part that will be updated
+            mDirtyRegion.set(mInvalidRegion.bounds());
+        } else {
+            // we need to redraw everything
+            mDirtyRegion.set(hw.bounds());
+            mInvalidRegion = mDirtyRegion;
+        }
+    }
+
+    // compose all surfaces
+    composeSurfaces(mDirtyRegion);
+
+    // clear the dirty regions
+    mDirtyRegion.clear();
+}
+
+void SurfaceFlinger::composeSurfaces(const Region& dirty)
+{
+    if (UNLIKELY(!mWormholeRegion.isEmpty())) {
+        // should never happen unless the window manager has a bug
+        // draw something...
+        drawWormhole();
+    }
+    const SurfaceFlinger& flinger(*this);
+    const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
+    const size_t count = drawingLayers.size();
+    LayerBase const* const* const layers = drawingLayers.array();
+    for (size_t i=0 ; i<count ; ++i) {
+        LayerBase const * const layer = layers[i];
+        const Region& visibleRegion(layer->visibleRegionScreen);
+        if (!visibleRegion.isEmpty())  {
+            const Region clip(dirty.intersect(visibleRegion));
+            if (!clip.isEmpty()) {
+                layer->draw(clip);
+            }
+        }
+    }
+}
+
+void SurfaceFlinger::unlockClients()
+{
+    const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
+    const size_t count = drawingLayers.size();
+    LayerBase* const* const layers = drawingLayers.array();
+    for (size_t i=0 ; i<count ; ++i) {
+        LayerBase* const layer = layers[i];
+        layer->finishPageFlip();
+    }
+}
+
+void SurfaceFlinger::scheduleBroadcast(Client* client)
+{
+    if (mLastScheduledBroadcast != client) {
+        mLastScheduledBroadcast = client;
+        mScheduledBroadcasts.add(client);
+    }
+}
+
+void SurfaceFlinger::executeScheduledBroadcasts()
+{
+    SortedVector<Client*>& list = mScheduledBroadcasts;
+    size_t count = list.size();
+    while (count--) {
+        per_client_cblk_t* const cblk = list[count]->ctrlblk;
+        if (cblk->lock.tryLock() == NO_ERROR) {
+            cblk->cv.broadcast();
+            list.removeAt(count);
+            cblk->lock.unlock();
+        } else {
+            // schedule another round
+            LOGW("executeScheduledBroadcasts() skipped, "
+                "contention on the client. We'll try again later...");
+            signalDelayedEvent(ms2ns(4));
+        }
+    }
+    mLastScheduledBroadcast = 0;
+}
+
+void SurfaceFlinger::handleDebugCpu()
+{
+    Mutex::Autolock _l(mDebugLock);
+    if (mCpuGauge != 0)
+        mCpuGauge->sample();
+}
+
+void SurfaceFlinger::debugFlashRegions()
+{
+    if (UNLIKELY(!mDirtyRegion.isRect())) {
+        // TODO: do this only if we don't have preserving
+        // swapBuffer. If we don't have update-on-demand,
+        // redraw everything.
+        composeSurfaces(Region(mDirtyRegion.bounds()));
+    }
+
+    glDisable(GL_TEXTURE_2D);
+    glDisable(GL_BLEND);
+    glDisable(GL_DITHER);
+    glDisable(GL_SCISSOR_TEST);
+
+    glColor4x(0x10000, 0, 0x10000, 0x10000);
+
+    Rect r;
+    Region::iterator iterator(mDirtyRegion);
+    while (iterator.iterate(&r)) {
+        GLfloat vertices[][2] = {
+                { r.left,  r.top },
+                { r.left,  r.bottom },
+                { r.right, r.bottom },
+                { r.right, r.top }
+        };
+        glVertexPointer(2, GL_FLOAT, 0, vertices);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+    }
+
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    hw.flip(mDirtyRegion.merge(mInvalidRegion));
+    mInvalidRegion.clear();
+
+    if (mDebugRegion > 1)
+       usleep(mDebugRegion * 1000);
+
+    glEnable(GL_SCISSOR_TEST);
+    //mDirtyRegion.dump("mDirtyRegion");
+}
+
+void SurfaceFlinger::drawWormhole() const
+{
+    const Region region(mWormholeRegion.intersect(mDirtyRegion));
+    if (region.isEmpty())
+        return;
+
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    const int32_t width = hw.getWidth();
+    const int32_t height = hw.getHeight();
+
+    glDisable(GL_BLEND);
+    glDisable(GL_DITHER);
+
+    if (LIKELY(!mDebugBackground)) {
+        glClearColorx(0,0,0,0);
+        Rect r;
+        Region::iterator iterator(region);
+        while (iterator.iterate(&r)) {
+            const GLint sy = height - (r.top + r.height());
+            glScissor(r.left, sy, r.width(), r.height());
+            glClear(GL_COLOR_BUFFER_BIT);
+        }
+    } else {
+        const GLshort vertices[][2] = { { 0, 0 }, { width, 0 },
+                { width, height }, { 0, height }  };
+        const GLshort tcoords[][2] = { { 0, 0 }, { 1, 0 },  { 1, 1 }, { 0, 1 } };
+        glVertexPointer(2, GL_SHORT, 0, vertices);
+        glTexCoordPointer(2, GL_SHORT, 0, tcoords);
+        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+        glEnable(GL_TEXTURE_2D);
+        glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
+        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+        glMatrixMode(GL_TEXTURE);
+        glLoadIdentity();
+        glScalef(width*(1.0f/32.0f), height*(1.0f/32.0f), 1);
+        Rect r;
+        Region::iterator iterator(region);
+        while (iterator.iterate(&r)) {
+            const GLint sy = height - (r.top + r.height());
+            glScissor(r.left, sy, r.width(), r.height());
+            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+        }
+        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    }
+}
+
+void SurfaceFlinger::debugShowFPS() const
+{
+    static int mFrameCount;
+    static int mLastFrameCount = 0;
+    static nsecs_t mLastFpsTime = 0;
+    static float mFps = 0;
+    mFrameCount++;
+    nsecs_t now = systemTime();
+    nsecs_t diff = now - mLastFpsTime;
+    if (diff > ms2ns(250)) {
+        mFps =  ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
+        mLastFpsTime = now;
+        mLastFrameCount = mFrameCount;
+    }
+    // XXX: mFPS has the value we want
+ }
+
+status_t SurfaceFlinger::addLayer(LayerBase* layer)
+{
+    Mutex::Autolock _l(mStateLock);
+    addLayer_l(layer);
+    setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeLayer(LayerBase* layer)
+{
+    Mutex::Autolock _l(mStateLock);
+    removeLayer_l(layer);
+    setTransactionFlags(eTransactionNeeded);
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::invalidateLayerVisibility(LayerBase* layer)
+{
+    layer->forceVisibilityTransaction();
+    setTransactionFlags(eTraversalNeeded);
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::addLayer_l(LayerBase* layer)
+{
+    ssize_t i = mCurrentState.layersSortedByZ.add(
+                layer, &LayerBase::compareCurrentStateZ);
+    LayerBaseClient* lbc = LayerBase::dynamicCast<LayerBaseClient*>(layer);
+    if (lbc) {
+        mLayerMap.add(lbc->serverIndex(), lbc);
+    }
+    mRemovedLayers.remove(layer);
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeLayer_l(LayerBase* layerBase)
+{
+    ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
+    if (index >= 0) {
+        mRemovedLayers.add(layerBase);
+        LayerBaseClient* layer = LayerBase::dynamicCast<LayerBaseClient*>(layerBase);
+        if (layer) {
+            mLayerMap.removeItem(layer->serverIndex());
+        }
+        return NO_ERROR;
+    }
+    // it's possible that we don't find a layer, because it might
+    // have been destroyed already -- this is not technically an error
+    // from the user because there is a race between destroySurface,
+    // destroyclient and destroySurface-from-a-transaction.
+    return (index == NAME_NOT_FOUND) ? status_t(NO_ERROR) : index;
+}
+
+void SurfaceFlinger::free_resources_l()
+{
+    // Destroy layers that were removed
+    destroy_all_removed_layers_l();
+
+    // free resources associated with disconnected clients
+    SortedVector<Client*>& scheduledBroadcasts(mScheduledBroadcasts);
+    Vector<Client*>& disconnectedClients(mDisconnectedClients);
+    const size_t count = disconnectedClients.size();
+    for (size_t i=0 ; i<count ; i++) {
+        Client* client = disconnectedClients[i];
+        // if this client is the scheduled broadcast list,
+        // remove it from there (and we don't need to signal it
+        // since it is dead).
+        int32_t index = scheduledBroadcasts.indexOf(client);
+        if (index >= 0) {
+            scheduledBroadcasts.removeItemsAt(index);
+        }
+        mTokens.release(client->cid);
+        delete client;
+    }
+    disconnectedClients.clear();
+}
+
+void SurfaceFlinger::destroy_all_removed_layers_l()
+{
+    size_t c = mRemovedLayers.size();
+    while (c--) {
+        LayerBase* const removed_layer = mRemovedLayers[c];
+
+        LOGE_IF(mCurrentState.layersSortedByZ.indexOf(removed_layer) >= 0,
+            "layer %p removed but still in the current state list",
+            removed_layer);
+
+        delete removed_layer;
+    }
+    mRemovedLayers.clear();
+}
+
+
+uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
+{
+    return android_atomic_and(~flags, &mTransactionFlags) & flags;
+}
+
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, nsecs_t delay)
+{
+    uint32_t old = android_atomic_or(flags, &mTransactionFlags);
+    if ((old & flags)==0) { // wake the server up
+        if (delay > 0) {
+            signalDelayedEvent(delay);
+        } else {
+            signalEvent();
+        }
+    }
+    return old;
+}
+
+void SurfaceFlinger::openGlobalTransaction()
+{
+    android_atomic_inc(&mTransactionCount);
+}
+
+void SurfaceFlinger::closeGlobalTransaction()
+{
+    if (android_atomic_dec(&mTransactionCount) == 1) {
+        signalEvent();
+    }
+}
+
+status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags)
+{
+    if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
+        return BAD_VALUE;
+
+    Mutex::Autolock _l(mStateLock);
+    mCurrentState.freezeDisplay = 1;
+    setTransactionFlags(eTransactionNeeded);
+
+    // flags is intended to communicate some sort of animation behavior
+    // (for instance fadding)
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags)
+{
+    if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
+        return BAD_VALUE;
+
+    Mutex::Autolock _l(mStateLock);
+    mCurrentState.freezeDisplay = 0;
+    setTransactionFlags(eTransactionNeeded);
+
+    // flags is intended to communicate some sort of animation behavior
+    // (for instance fadding)
+    return NO_ERROR;
+}
+
+int SurfaceFlinger::setOrientation(DisplayID dpy, int orientation)
+{
+    if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
+        return BAD_VALUE;
+
+    Mutex::Autolock _l(mStateLock);
+    if (mCurrentState.orientation != orientation) {
+        if (uint32_t(orientation)<=eOrientation270 || orientation==42) {
+            mCurrentState.orientation = orientation;
+            setTransactionFlags(eTransactionNeeded);
+            mTransactionCV.wait(mStateLock);
+        } else {
+            orientation = BAD_VALUE;
+        }
+    }
+    return orientation;
+}
+
+sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
+        ISurfaceFlingerClient::surface_data_t* params,
+        DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
+        uint32_t flags)
+{
+    LayerBaseClient* layer = 0;
+    sp<LayerBaseClient::Surface> surfaceHandle;
+    Mutex::Autolock _l(mStateLock);
+    Client* const c = mClientsMap.valueFor(clientId);
+    if (UNLIKELY(!c)) {
+        LOGE("createSurface() failed, client not found (id=%d)", clientId);
+        return surfaceHandle;
+    }
+
+    //LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
+    int32_t id = c->generateId(pid);
+    if (uint32_t(id) >= NUM_LAYERS_MAX) {
+        LOGE("createSurface() failed, generateId = %d", id);
+        return surfaceHandle;
+    }
+
+    switch (flags & eFXSurfaceMask) {
+        case eFXSurfaceNormal:
+            if (UNLIKELY(flags & ePushBuffers)) {
+                layer = createPushBuffersSurfaceLocked(c, d, id, w, h, flags);
+            } else {
+                layer = createNormalSurfaceLocked(c, d, id, w, h, format, flags);
+            }
+            break;
+        case eFXSurfaceBlur:
+            layer = createBlurSurfaceLocked(c, d, id, w, h, flags);
+            break;
+        case eFXSurfaceDim:
+            layer = createDimSurfaceLocked(c, d, id, w, h, flags);
+            break;
+    }
+
+    if (layer) {
+        setTransactionFlags(eTransactionNeeded);
+        surfaceHandle = layer->getSurface();
+        if (surfaceHandle != 0)
+            surfaceHandle->getSurfaceData(params);
+    }
+
+    return surfaceHandle;
+}
+
+LayerBaseClient* SurfaceFlinger::createNormalSurfaceLocked(
+        Client* client, DisplayID display,
+        int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+{
+    // initialize the surfaces
+    switch (format) { // TODO: take h/w into account
+    case PIXEL_FORMAT_TRANSPARENT:
+    case PIXEL_FORMAT_TRANSLUCENT:
+        format = PIXEL_FORMAT_RGBA_8888;
+        break;
+    case PIXEL_FORMAT_OPAQUE:
+        format = PIXEL_FORMAT_RGB_565;
+        break;
+    }
+
+    Layer* layer = new Layer(this, display, client, id);
+    status_t err = layer->setBuffers(client, w, h, format, flags);
+    if (LIKELY(err == NO_ERROR)) {
+        layer->initStates(w, h, flags);
+        addLayer_l(layer);
+    } else {
+        LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));
+        delete layer;
+        return 0;
+    }
+    return layer;
+}
+
+LayerBaseClient* SurfaceFlinger::createBlurSurfaceLocked(
+        Client* client, DisplayID display,
+        int32_t id, uint32_t w, uint32_t h, uint32_t flags)
+{
+    LayerBlur* layer = new LayerBlur(this, display, client, id);
+    layer->initStates(w, h, flags);
+    addLayer_l(layer);
+    return layer;
+}
+
+LayerBaseClient* SurfaceFlinger::createDimSurfaceLocked(
+        Client* client, DisplayID display,
+        int32_t id, uint32_t w, uint32_t h, uint32_t flags)
+{
+    LayerDim* layer = new LayerDim(this, display, client, id);
+    layer->initStates(w, h, flags);
+    addLayer_l(layer);
+    return layer;
+}
+
+LayerBaseClient* SurfaceFlinger::createPushBuffersSurfaceLocked(
+        Client* client, DisplayID display,
+        int32_t id, uint32_t w, uint32_t h, uint32_t flags)
+{
+    LayerBuffer* layer = new LayerBuffer(this, display, client, id);
+    layer->initStates(w, h, flags);
+    addLayer_l(layer);
+    return layer;
+}
+
+status_t SurfaceFlinger::destroySurface(SurfaceID index)
+{
+    Mutex::Autolock _l(mStateLock);
+    LayerBaseClient* const layer = getLayerUser_l(index);
+    status_t err = removeLayer_l(layer);
+    if (err < 0)
+        return err;
+    setTransactionFlags(eTransactionNeeded);
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setClientState(
+        ClientID cid,
+        int32_t count,
+        const layer_state_t* states)
+{
+    Mutex::Autolock _l(mStateLock);
+    uint32_t flags = 0;
+    cid <<= 16;
+    for (int i=0 ; i<count ; i++) {
+        const layer_state_t& s = states[i];
+        LayerBaseClient* layer = getLayerUser_l(s.surface | cid);
+        if (layer) {
+            const uint32_t what = s.what;
+            // check if it has been destroyed first
+            if (what & eDestroyed) {
+                if (removeLayer_l(layer) == NO_ERROR) {
+                    flags |= eTransactionNeeded;
+                    // we skip everything else... well, no, not really
+                    // we skip ONLY that transaction.
+                    continue;
+                }
+            }
+            if (what & ePositionChanged) {
+                if (layer->setPosition(s.x, s.y))
+                    flags |= eTraversalNeeded;
+            }
+            if (what & eLayerChanged) {
+                if (layer->setLayer(s.z)) {
+                    mCurrentState.layersSortedByZ.reorder(
+                            layer, &Layer::compareCurrentStateZ);
+                    // we need traversal (state changed)
+                    // AND transaction (list changed)
+                    flags |= eTransactionNeeded|eTraversalNeeded;
+                }
+            }
+            if (what & eSizeChanged) {
+                if (layer->setSize(s.w, s.h))
+                    flags |= eTraversalNeeded;
+            }
+            if (what & eAlphaChanged) {
+                if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
+                    flags |= eTraversalNeeded;
+            }
+            if (what & eMatrixChanged) {
+                if (layer->setMatrix(s.matrix))
+                    flags |= eTraversalNeeded;
+            }
+            if (what & eTransparentRegionChanged) {
+                if (layer->setTransparentRegionHint(s.transparentRegion))
+                    flags |= eTraversalNeeded;
+            }
+            if (what & eVisibilityChanged) {
+                if (layer->setFlags(s.flags, s.mask))
+                    flags |= eTraversalNeeded;
+            }
+        }
+    }
+    if (flags) {
+        setTransactionFlags(flags);
+    }
+    return NO_ERROR;
+}
+
+LayerBaseClient* SurfaceFlinger::getLayerUser_l(SurfaceID s) const
+{
+    return mLayerMap.valueFor(s);
+}
+
+void SurfaceFlinger::screenReleased(int dpy)
+{
+    // this may be called by a signal handler, we can't do too much in here
+    android_atomic_or(eConsoleReleased, &mConsoleSignals);
+    signalEvent();
+}
+
+void SurfaceFlinger::screenAcquired(int dpy)
+{
+    // this may be called by a signal handler, we can't do too much in here
+    android_atomic_or(eConsoleAcquired, &mConsoleSignals);
+    signalEvent();
+}
+
+status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 1024;
+    char buffer[SIZE];
+    String8 result;
+    if (checkCallingPermission(
+            String16("android.permission.DUMP")) == false)
+    { // not allowed
+        snprintf(buffer, SIZE, "Permission Denial: "
+                "can't dump SurfaceFlinger from pid=%d, uid=%d\n",
+                IPCThreadState::self()->getCallingPid(),
+                IPCThreadState::self()->getCallingUid());
+        result.append(buffer);
+    } else {
+        Mutex::Autolock _l(mStateLock);
+        size_t s = mClientsMap.size();
+        char name[64];
+        for (size_t i=0 ; i<s ; i++) {
+            Client* client = mClientsMap.valueAt(i);
+            sprintf(name, "  Client (id=0x%08x)", client->cid);
+            client->dump(name);
+        }
+        const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+        const size_t count = currentLayers.size();
+        for (size_t i=0 ; i<count ; i++) {
+            /*** LayerBase ***/
+            LayerBase const * const layer = currentLayers[i];
+            const Layer::State& s = layer->drawingState();
+            snprintf(buffer, SIZE,
+                    "+ %s %p\n"
+                    "      "
+                    "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
+                    "needsBlending=%1d, invalidate=%1d, "
+                    "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
+                    layer->getTypeID(), layer,
+                    s.z, layer->tx(), layer->ty(), s.w, s.h,
+                    layer->needsBlending(), layer->contentDirty,
+                    s.alpha, s.flags,
+                    s.transform[0], s.transform[1],
+                    s.transform[2], s.transform[3]);
+            result.append(buffer);
+            buffer[0] = 0;
+            /*** LayerBaseClient ***/
+            LayerBaseClient* const lbc =
+                LayerBase::dynamicCast<LayerBaseClient*>((LayerBase*)layer);
+            if (lbc) {
+                snprintf(buffer, SIZE,
+                        "      "
+                        "id=0x%08x, client=0x%08x, identity=%u\n",
+                        lbc->clientIndex(), lbc->client ? lbc->client->cid : 0,
+                        lbc->getIdentity());
+            }
+            result.append(buffer);
+            buffer[0] = 0;
+            /*** Layer ***/
+            Layer* const l = LayerBase::dynamicCast<Layer*>((LayerBase*)layer);
+            if (l) {
+                const LayerBitmap& buf0(l->getBuffer(0));
+                const LayerBitmap& buf1(l->getBuffer(1));
+                snprintf(buffer, SIZE,
+                        "      "
+                        "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u], mTextureName=%d,"
+                        " freezeLock=%p, swapState=0x%08x\n",
+                        l->pixelFormat(),
+                        buf0.width(), buf0.height(), buf0.stride(),
+                        buf1.width(), buf1.height(), buf1.stride(),
+                        l->getTextureName(), l->getFreezeLock().get(),
+                        l->lcblk->swapState);
+            }
+            result.append(buffer);
+            buffer[0] = 0;
+            s.transparentRegion.dump(result, "transparentRegion");
+            layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
+            layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
+        }
+        mWormholeRegion.dump(result, "WormholeRegion");
+        const DisplayHardware& hw(graphicPlane(0).displayHardware());
+        snprintf(buffer, SIZE,
+                "  display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n",
+                mFreezeDisplay?"yes":"no", mFreezeCount,
+                mCurrentState.orientation, hw.canDraw());
+        result.append(buffer);
+
+        sp<AllocatorInterface> allocator;
+        if (mGPU != 0) {
+            snprintf(buffer, SIZE, "  GPU owner: %d\n", mGPU->getOwner());
+            result.append(buffer);
+            allocator = mGPU->getAllocator();
+            if (allocator != 0) {
+                allocator->dump(result, "GPU Allocator");
+            }
+        }
+        allocator = mSurfaceHeapManager->getAllocator(NATIVE_MEMORY_TYPE_PMEM);
+        if (allocator != 0) {
+            allocator->dump(result, "PMEM Allocator");
+        }
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case CREATE_CONNECTION:
+        case OPEN_GLOBAL_TRANSACTION:
+        case CLOSE_GLOBAL_TRANSACTION:
+        case SET_ORIENTATION:
+        case FREEZE_DISPLAY:
+        case UNFREEZE_DISPLAY:
+        case BOOT_FINISHED:
+        case REVOKE_GPU:
+        {
+            // codes that require permission check
+            IPCThreadState* ipc = IPCThreadState::self();
+            const int pid = ipc->getCallingPid();
+            const int self_pid = getpid();
+            if (UNLIKELY(pid != self_pid)) {
+                // we're called from a different process, do the real check
+                if (!checkCallingPermission(
+                        String16("android.permission.ACCESS_SURFACE_FLINGER")))
+                {
+                    const int uid = ipc->getCallingUid();
+                    LOGE("Permission Denial: "
+                            "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+                    return PERMISSION_DENIED;
+                }
+            }
+        }
+    }
+
+    status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
+    if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
+        // HARDWARE_TEST stuff...
+        if (UNLIKELY(checkCallingPermission(
+                String16("android.permission.HARDWARE_TEST")) == false))
+        { // not allowed
+            LOGE("Permission Denial: pid=%d, uid=%d\n",
+                    IPCThreadState::self()->getCallingPid(),
+                    IPCThreadState::self()->getCallingUid());
+            return PERMISSION_DENIED;
+        }
+        int n;
+        switch (code) {
+            case 1000: // SHOW_CPU
+                n = data.readInt32();
+                mDebugCpu = n ? 1 : 0;
+                if (mDebugCpu) {
+                    if (mCpuGauge == 0) {
+                        mCpuGauge = new CPUGauge(this, ms2ns(500));
+                    }
+                } else {
+                    if (mCpuGauge != 0) {
+                        mCpuGauge->requestExitAndWait();
+                        Mutex::Autolock _l(mDebugLock);
+                        mCpuGauge.clear();
+                    }
+                }
+                return NO_ERROR;
+            case 1001:  // SHOW_FPS
+                n = data.readInt32();
+                mDebugFps = n ? 1 : 0;
+                return NO_ERROR;
+            case 1002:  // SHOW_UPDATES
+                n = data.readInt32();
+                mDebugRegion = n ? n : (mDebugRegion ? 0 : 1);
+                return NO_ERROR;
+            case 1003:  // SHOW_BACKGROUND
+                n = data.readInt32();
+                mDebugBackground = n ? 1 : 0;
+                return NO_ERROR;
+            case 1004:{ // repaint everything
+                Mutex::Autolock _l(mStateLock);
+                const DisplayHardware& hw(graphicPlane(0).displayHardware());
+                mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
+                signalEvent();
+            }
+            return NO_ERROR;
+            case 1005: // ask GPU revoke
+                mGPU->friendlyRevoke();
+                return NO_ERROR;
+            case 1006: // revoke GPU
+                mGPU->unconditionalRevoke();
+                return NO_ERROR;
+            case 1007: // set mFreezeCount
+                mFreezeCount = data.readInt32();
+                return NO_ERROR;
+            case 1010:  // interrogate.
+                reply->writeInt32(mDebugCpu);
+                reply->writeInt32(0);
+                reply->writeInt32(mDebugRegion);
+                reply->writeInt32(mDebugBackground);
+                return NO_ERROR;
+            case 1013: {
+                Mutex::Autolock _l(mStateLock);
+                const DisplayHardware& hw(graphicPlane(0).displayHardware());
+                reply->writeInt32(hw.getPageFlipCount());
+            }
+            return NO_ERROR;
+        }
+    }
+    return err;
+}
+
+// ---------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)
+    : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
+{
+    mSharedHeapAllocator = getSurfaceHeapManager()->createHeap();
+    const int pgsize = getpagesize();
+    const int cblksize=((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
+    mCblkHeap = new MemoryDealer(cblksize);
+    mCblkMemory = mCblkHeap->allocate(cblksize);
+    if (mCblkMemory != 0) {
+        ctrlblk = static_cast<per_client_cblk_t *>(mCblkMemory->pointer());
+        if (ctrlblk) { // construct the shared structure in-place.
+            new(ctrlblk) per_client_cblk_t;
+        }
+    }
+}
+
+Client::~Client() {
+    if (ctrlblk) {
+        const int pgsize = getpagesize();
+        ctrlblk->~per_client_cblk_t();  // destroy our shared-structure.
+    }
+}
+
+const sp<SurfaceHeapManager>& Client::getSurfaceHeapManager() const {
+    return mFlinger->getSurfaceHeapManager();
+}
+
+int32_t Client::generateId(int pid)
+{
+    const uint32_t i = clz( ~mBitmap );
+    if (i >= NUM_LAYERS_MAX) {
+        return NO_MEMORY;
+    }
+    mPid = pid;
+    mInUse.add(uint8_t(i));
+    mBitmap |= 1<<(31-i);
+    return i;
+}
+status_t Client::bindLayer(LayerBaseClient* layer, int32_t id)
+{
+    ssize_t idx = mInUse.indexOf(id);
+    if (idx < 0)
+        return NAME_NOT_FOUND;
+    return mLayers.insertAt(layer, idx);
+}
+void Client::free(int32_t id)
+{
+    ssize_t idx = mInUse.remove(uint8_t(id));
+    if (idx >= 0) {
+        mBitmap &= ~(1<<(31-id));
+        mLayers.removeItemsAt(idx);
+    }
+}
+
+sp<MemoryDealer> Client::createAllocator(uint32_t flags)
+{
+    sp<MemoryDealer> allocator;
+    allocator = getSurfaceHeapManager()->createHeap(
+            flags, getClientPid(), mSharedHeapAllocator);
+    return allocator;
+}
+
+bool Client::isValid(int32_t i) const {
+    return (uint32_t(i)<NUM_LAYERS_MAX) && (mBitmap & (1<<(31-i)));
+}
+const uint8_t* Client::inUseArray() const {
+    return mInUse.array();
+}
+size_t Client::numActiveLayers() const {
+    return mInUse.size();
+}
+LayerBaseClient* Client::getLayerUser(int32_t i) const {
+    ssize_t idx = mInUse.indexOf(uint8_t(i));
+    if (idx<0) return 0;
+    return mLayers[idx];
+}
+
+void Client::dump(const char* what)
+{
+}
+
+// ---------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemory>& cblk)
+    : mId(cid), mFlinger(flinger), mCblk(cblk)
+{
+}
+
+BClient::~BClient() {
+    // destroy all resources attached to this client
+    mFlinger->destroyConnection(mId);
+}
+
+void BClient::getControlBlocks(sp<IMemory>* ctrl) const {
+    *ctrl = mCblk;
+}
+
+sp<ISurface> BClient::createSurface(
+        ISurfaceFlingerClient::surface_data_t* params, int pid,
+        DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+        uint32_t flags)
+{
+    return mFlinger->createSurface(mId, pid, params, display, w, h, format, flags);
+}
+
+status_t BClient::destroySurface(SurfaceID sid)
+{
+    sid |= (mId << 16); // add the client-part to id
+    return mFlinger->destroySurface(sid);
+}
+
+status_t BClient::setState(int32_t count, const layer_state_t* states)
+{
+    return mFlinger->setClientState(mId, count, states);
+}
+
+// ---------------------------------------------------------------------------
+
+GraphicPlane::GraphicPlane()
+    : mHw(0)
+{
+}
+
+GraphicPlane::~GraphicPlane() {
+    delete mHw;
+}
+
+bool GraphicPlane::initialized() const {
+    return mHw ? true : false;
+}
+
+void GraphicPlane::setDisplayHardware(DisplayHardware *hw) {
+    mHw = hw;
+}
+
+void GraphicPlane::setTransform(const Transform& tr) {
+    mTransform = tr;
+    mGlobalTransform = mOrientationTransform * mTransform;
+}
+
+status_t GraphicPlane::orientationToTransfrom(
+        int orientation, int w, int h, Transform* tr)
+{    
+    float a, b, c, d, x, y;
+    switch (orientation) {
+    case ISurfaceComposer::eOrientationDefault:
+        a=1; b=0; c=0; d=1; x=0; y=0;
+        break;
+    case ISurfaceComposer::eOrientation90:
+        a=0; b=-1; c=1; d=0; x=w; y=0;
+        break;
+    case ISurfaceComposer::eOrientation180:
+        a=-1; b=0; c=0; d=-1; x=w; y=h;
+        break;
+    case ISurfaceComposer::eOrientation270:
+        a=0; b=1; c=-1; d=0; x=0; y=h;
+        break;
+    default:
+        return BAD_VALUE;
+    }
+    tr->set(a, b, c, d);
+    tr->set(x, y);
+    return NO_ERROR;
+}
+
+status_t GraphicPlane::setOrientation(int orientation)
+{
+    const DisplayHardware& hw(displayHardware());
+    const float w = hw.getWidth();
+    const float h = hw.getHeight();
+
+    if (orientation == ISurfaceComposer::eOrientationDefault) {
+        // make sure the default orientation is optimal
+        mOrientationTransform.reset();
+        mGlobalTransform = mTransform;
+        return NO_ERROR;
+    }
+
+    // If the rotation can be handled in hardware, this is where
+    // the magic should happen.
+    if (UNLIKELY(orientation == 42)) {
+        float a, b, c, d, x, y;
+        const float r = (3.14159265f / 180.0f) * 42.0f;
+        const float si = sinf(r);
+        const float co = cosf(r);
+        a=co; b=-si; c=si; d=co;
+        x = si*(h*0.5f) + (1-co)*(w*0.5f);
+        y =-si*(w*0.5f) + (1-co)*(h*0.5f);
+        mOrientationTransform.set(a, b, c, d);
+        mOrientationTransform.set(x, y);
+    } else {
+        GraphicPlane::orientationToTransfrom(orientation, w, h,
+                &mOrientationTransform);
+    }
+    
+    mGlobalTransform = mOrientationTransform * mTransform;
+    return NO_ERROR;
+}
+
+const DisplayHardware& GraphicPlane::displayHardware() const {
+    return *mHw;
+}
+
+const Transform& GraphicPlane::transform() const {
+    return mGlobalTransform;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
new file mode 100644
index 0000000..f7d7764
--- /dev/null
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_SURFACE_FLINGER_H
+#define ANDROID_SURFACE_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/MemoryDealer.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/ISurfaceComposer.h>
+#include <ui/ISurfaceFlingerClient.h>
+
+#include <private/ui/SharedState.h>
+#include <private/ui/LayerState.h>
+#include <private/ui/SurfaceFlingerSynchro.h>
+
+#include "Barrier.h"
+#include "BootAnimation.h"
+#include "CPUGauge.h"
+#include "Layer.h"
+#include "Tokenizer.h"
+
+struct copybit_device_t;
+struct overlay_device_t;
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Client;
+class BClient;
+class DisplayHardware;
+class FreezeLock;
+class GPUHardwareInterface;
+class IGPUCallback;
+class Layer;
+class LayerBuffer;
+class LayerOrientationAnim;
+class OrientationAnimation;
+class SurfaceHeapManager;
+
+typedef int32_t ClientID;
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+class Client
+{
+public:
+            Client(ClientID cid, const sp<SurfaceFlinger>& flinger);
+            ~Client();
+
+            int32_t                 generateId(int pid);
+            void                    free(int32_t id);
+            status_t                bindLayer(LayerBaseClient* layer, int32_t id);
+            sp<MemoryDealer>        createAllocator(uint32_t memory_type);
+
+    inline  bool                    isValid(int32_t i) const;
+    inline  const uint8_t*          inUseArray() const;
+    inline  size_t                  numActiveLayers() const;
+    LayerBaseClient*                getLayerUser(int32_t i) const;
+    const Vector<LayerBaseClient*>& getLayers() const { return mLayers; }
+    const sp<IMemory>&              controlBlockMemory() const { return mCblkMemory; }
+    void                            dump(const char* what);
+    const sp<SurfaceHeapManager>&   getSurfaceHeapManager() const;
+    
+    // pointer to this client's control block
+    per_client_cblk_t*      ctrlblk;
+    ClientID                cid;
+
+    
+private:
+    int                     getClientPid() const { return mPid; }
+        
+    int                         mPid;
+    uint32_t                    mBitmap;
+    SortedVector<uint8_t>       mInUse;
+    Vector<LayerBaseClient*>    mLayers;
+    sp<MemoryDealer>            mCblkHeap;
+    sp<SurfaceFlinger>          mFlinger;
+    sp<MemoryDealer>            mSharedHeapAllocator;
+    sp<MemoryDealer>            mPMemAllocator;
+    sp<IMemory>                 mCblkMemory;
+};
+
+// ---------------------------------------------------------------------------
+
+class GraphicPlane
+{
+public:
+    static status_t orientationToTransfrom(int orientation, int w, int h,
+            Transform* tr);
+
+                                GraphicPlane();
+                                ~GraphicPlane();
+
+        bool                    initialized() const;
+
+        void                    setDisplayHardware(DisplayHardware *);
+        void                    setTransform(const Transform& tr);
+        status_t                setOrientation(int orientation);
+
+        const DisplayHardware&  displayHardware() const;
+        const Transform&        transform() const;
+private:
+                                GraphicPlane(const GraphicPlane&);
+        GraphicPlane            operator = (const GraphicPlane&);
+
+        DisplayHardware*        mHw;
+        Transform               mTransform;
+        Transform               mOrientationTransform;
+        Transform               mGlobalTransform;
+};
+
+// ---------------------------------------------------------------------------
+
+enum {
+    eTransactionNeeded      = 0x01,
+    eTraversalNeeded        = 0x02
+};
+
+class SurfaceFlinger : public BnSurfaceComposer, protected Thread
+{
+public:
+    static void instantiate();
+    static void shutdown();
+
+                    SurfaceFlinger();
+    virtual         ~SurfaceFlinger();
+            void    init();
+
+    virtual status_t onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
+    // ISurfaceComposer interface
+    virtual sp<ISurfaceFlingerClient>   createConnection();
+    virtual sp<IMemory>                 getCblk() const;
+    virtual void                        bootFinished();
+    virtual void                        openGlobalTransaction();
+    virtual void                        closeGlobalTransaction();
+    virtual status_t                    freezeDisplay(DisplayID dpy, uint32_t flags);
+    virtual status_t                    unfreezeDisplay(DisplayID dpy, uint32_t flags);
+    virtual int                         setOrientation(DisplayID dpy, int orientation);
+    virtual void                        signal() const;
+    virtual status_t requestGPU(const sp<IGPUCallback>& callback, 
+            gpu_info_t* gpu);
+    virtual status_t revokeGPU();
+
+            void                        screenReleased(DisplayID dpy);
+            void                        screenAcquired(DisplayID dpy);
+
+            const sp<SurfaceHeapManager>& getSurfaceHeapManager() const { 
+                return mSurfaceHeapManager; 
+            }
+
+            const sp<GPUHardwareInterface>& getGPU() const {
+                return mGPU; 
+            }
+
+            copybit_device_t* getBlitEngine() const;
+            overlay_control_device_t* getOverlayEngine() const;
+
+            
+    status_t removeLayer(LayerBase* layer);
+    status_t addLayer(LayerBase* layer);
+    status_t invalidateLayerVisibility(LayerBase* layer);
+    
+private:
+    friend class BClient;
+    friend class LayerBase;
+    friend class LayerBuffer;
+    friend class LayerBaseClient;
+    friend class Layer;
+    friend class LayerBlur;
+
+    sp<ISurface> createSurface(ClientID client, int pid, 
+            ISurfaceFlingerClient::surface_data_t* params,
+            DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+            uint32_t flags);
+
+    LayerBaseClient* createNormalSurfaceLocked(Client* client, DisplayID display,
+            int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+
+    LayerBaseClient* createBlurSurfaceLocked(Client* client, DisplayID display,
+            int32_t id, uint32_t w, uint32_t h, uint32_t flags);
+
+    LayerBaseClient* createDimSurfaceLocked(Client* client, DisplayID display,
+            int32_t id, uint32_t w, uint32_t h, uint32_t flags);
+
+    LayerBaseClient* createPushBuffersSurfaceLocked(Client* client, DisplayID display,
+            int32_t id, uint32_t w, uint32_t h, uint32_t flags);
+
+    status_t    destroySurface(SurfaceID surface_id);
+    status_t    setClientState(ClientID cid, int32_t count, const layer_state_t* states);
+
+
+    class LayerVector {
+    public:
+        inline              LayerVector() { }
+                            LayerVector(const LayerVector&);
+        inline size_t       size() const { return layers.size(); }
+        inline LayerBase*const* array() const { return layers.array(); }
+        ssize_t             add(LayerBase*, Vector<LayerBase*>::compar_t);
+        ssize_t             remove(LayerBase*);
+        ssize_t             reorder(LayerBase*, Vector<LayerBase*>::compar_t);
+        ssize_t             indexOf(LayerBase* key, size_t guess=0) const;
+        inline LayerBase*   operator [] (size_t i) const { return layers[i]; }
+    private:
+        KeyedVector<LayerBase*, size_t> lookup;
+        Vector<LayerBase*>              layers;
+    };
+
+    struct State {
+        State() {
+            orientation = ISurfaceComposer::eOrientationDefault;
+            freezeDisplay = 0;
+        }
+        LayerVector     layersSortedByZ;
+        uint8_t         orientation;
+        uint8_t         freezeDisplay;
+    };
+
+    class DelayedTransaction : public Thread
+    {
+        friend class SurfaceFlinger;
+        sp<SurfaceFlinger>  mFlinger;
+        nsecs_t             mDelay;
+    public:
+        DelayedTransaction(const sp<SurfaceFlinger>& flinger, nsecs_t delay)
+            : Thread(false), mFlinger(flinger), mDelay(delay) {
+        }
+        virtual bool threadLoop() {
+            usleep(mDelay / 1000);
+            if (android_atomic_and(~1,
+                    &mFlinger->mDeplayedTransactionPending) == 1) {
+                mFlinger->signalEvent();
+            }
+            return false;
+        }
+    };
+
+    virtual bool        threadLoop();
+    virtual status_t    readyToRun();
+    virtual void        onFirstRef();
+
+    const GraphicPlane&     graphicPlane(int dpy) const;
+          GraphicPlane&     graphicPlane(int dpy);
+
+            void        waitForEvent();
+            void        signalEvent();
+            void        signalDelayedEvent(nsecs_t delay);
+
+            void        handleConsoleEvents();
+            void        handleTransaction(uint32_t transactionFlags);
+
+            void        computeVisibleRegions(
+                            LayerVector& currentLayers,
+                            Region& dirtyRegion,
+                            Region& wormholeRegion);
+
+            void        handlePageFlip();
+            bool        lockPageFlip(const LayerVector& currentLayers);
+            void        unlockPageFlip(const LayerVector& currentLayers);
+            void        handleRepaint();
+            void        handleDebugCpu();
+            void        scheduleBroadcast(Client* client);
+            void        executeScheduledBroadcasts();
+            void        postFramebuffer();
+            void        composeSurfaces(const Region& dirty);
+            void        unlockClients();
+
+
+            void        destroyConnection(ClientID cid);
+            LayerBaseClient* getLayerUser_l(SurfaceID index) const;
+            status_t    addLayer_l(LayerBase* layer);
+            status_t    removeLayer_l(LayerBase* layer);
+            void        destroy_all_removed_layers_l();
+            void        free_resources_l();
+
+            uint32_t    getTransactionFlags(uint32_t flags);
+            uint32_t    setTransactionFlags(uint32_t flags, nsecs_t delay = 0);
+            void        commitTransaction();
+
+
+            friend class FreezeLock;
+            sp<FreezeLock> getFreezeLock() const;
+            inline void incFreezeCount() { mFreezeCount++; }
+            inline void decFreezeCount() { if (mFreezeCount > 0) mFreezeCount--; }
+            inline bool hasFreezeRequest() const { return mFreezeDisplay; }
+            inline bool isFrozen() const { 
+                return mFreezeDisplay || mFreezeCount>0;
+            }
+
+            
+            void        debugFlashRegions();
+            void        debugShowFPS() const;
+            void        drawWormhole() const;
+           
+                // access must be protected by mStateLock
+    mutable     Mutex                   mStateLock;
+                State                   mCurrentState;
+                State                   mDrawingState;
+    volatile    int32_t                 mTransactionFlags;
+    volatile    int32_t                 mTransactionCount;
+                Condition               mTransactionCV;
+
+                // protected by mStateLock (but we could use another lock)
+                Tokenizer                               mTokens;
+                DefaultKeyedVector<ClientID, Client*>   mClientsMap;
+                DefaultKeyedVector<SurfaceID, LayerBaseClient*>   mLayerMap;
+                GraphicPlane                            mGraphicPlanes[1];
+                SortedVector<LayerBase*>                mRemovedLayers;
+                Vector<Client*>                         mDisconnectedClients;
+
+                // constant members (no synchronization needed for access)
+                sp<MemoryDealer>            mServerHeap;
+                sp<IMemory>                 mServerCblkMemory;
+                surface_flinger_cblk_t*     mServerCblk;
+                sp<SurfaceHeapManager>      mSurfaceHeapManager;
+                sp<GPUHardwareInterface>    mGPU;
+                GLuint                      mWormholeTexName;
+                sp<BootAnimation>           mBootAnimation;
+                nsecs_t                     mBootTime;
+                
+                // Can only accessed from the main thread, these members
+                // don't need synchronization
+                Region                      mDirtyRegion;
+                Region                      mInvalidRegion;
+                Region                      mWormholeRegion;
+                Client*                     mLastScheduledBroadcast;
+                SortedVector<Client*>       mScheduledBroadcasts;
+                bool                        mVisibleRegionsDirty;
+                bool                        mDeferReleaseConsole;
+                bool                        mFreezeDisplay;
+                int32_t                     mFreezeCount;
+                nsecs_t                     mFreezeDisplayTime;
+                friend class OrientationAnimation;
+                OrientationAnimation*       mOrientationAnimation;
+
+                // access protected by mDebugLock
+    mutable     Mutex                       mDebugLock;
+                sp<CPUGauge>                mCpuGauge;
+
+                // don't use a lock for these, we don't care
+                int                         mDebugRegion;
+                int                         mDebugCpu;
+                int                         mDebugFps;
+                int                         mDebugBackground;
+                int                         mDebugNoBootAnimation;
+
+                // these are thread safe
+    mutable     Barrier                     mReadyToRunBarrier;
+    mutable     SurfaceFlingerSynchro       mSyncObject;
+    volatile    int32_t                     mDeplayedTransactionPending;
+
+                // atomic variables
+                enum {
+                    eConsoleReleased = 1,
+                    eConsoleAcquired = 2
+                };
+   volatile     int32_t                     mConsoleSignals;
+
+   // only written in the main thread, only read in other threads
+   volatile     int32_t                     mSecureFrameBuffer;
+};
+
+// ---------------------------------------------------------------------------
+
+class FreezeLock : public LightRefBase<FreezeLock> {
+    SurfaceFlinger* mFlinger;
+public:
+    FreezeLock(SurfaceFlinger* flinger)
+        : mFlinger(flinger) {
+        mFlinger->incFreezeCount();
+    }
+    ~FreezeLock() {
+        mFlinger->decFreezeCount();
+    }
+};
+
+// ---------------------------------------------------------------------------
+
+class BClient : public BnSurfaceFlingerClient
+{
+public:
+    BClient(SurfaceFlinger *flinger, ClientID cid,
+            const sp<IMemory>& cblk);
+    ~BClient();
+
+    // ISurfaceFlingerClient interface
+    virtual void getControlBlocks(sp<IMemory>* ctrl) const;
+
+    virtual sp<ISurface> createSurface(
+            surface_data_t* params, int pid,
+            DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
+            uint32_t flags);
+
+    virtual status_t destroySurface(SurfaceID surfaceId);
+    virtual status_t setState(int32_t count, const layer_state_t* states);
+
+private:
+    ClientID            mId;
+    SurfaceFlinger*     mFlinger;
+    sp<IMemory>         mCblk;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SURFACE_FLINGER_H
diff --git a/libs/surfaceflinger/Tokenizer.cpp b/libs/surfaceflinger/Tokenizer.cpp
new file mode 100644
index 0000000..ef51d6a
--- /dev/null
+++ b/libs/surfaceflinger/Tokenizer.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2007 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 "Tokenizer.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+ANDROID_BASIC_TYPES_TRAITS(Tokenizer::run_t)
+
+Tokenizer::Tokenizer()
+{
+}
+
+Tokenizer::Tokenizer(const Tokenizer& other)
+    : mRanges(other.mRanges)
+{
+}
+
+Tokenizer::~Tokenizer()
+{
+}
+
+uint32_t Tokenizer::acquire()
+{
+    if (!mRanges.size() || mRanges[0].first) {
+        _insertTokenAt(0,0);
+        return 0;
+    }
+    
+    // just extend the first run
+    const run_t& run = mRanges[0];
+    uint32_t token = run.first + run.length;
+    _insertTokenAt(token, 1);
+    return token;
+}
+
+bool Tokenizer::isAcquired(uint32_t token) const
+{
+    return (_indexOrderOf(token) >= 0);
+}
+
+status_t Tokenizer::reserve(uint32_t token)
+{
+    size_t o;
+    const ssize_t i = _indexOrderOf(token, &o);
+    if (i >= 0) {
+        return BAD_VALUE; // this token is already taken
+    }
+    ssize_t err = _insertTokenAt(token, o);
+    return (err<0) ? err : status_t(NO_ERROR);
+}
+
+status_t Tokenizer::release(uint32_t token)
+{
+    const ssize_t i = _indexOrderOf(token);
+    if (i >= 0) {
+        const run_t& run = mRanges[i];
+        if ((token >= run.first) && (token < run.first+run.length)) {
+            // token in this range, we need to split
+            run_t& run = mRanges.editItemAt(i);
+            if ((token == run.first) || (token == run.first+run.length-1)) {
+                if (token == run.first) {
+                    run.first += 1;
+                }
+                run.length -= 1;
+                if (run.length == 0) {
+                    // XXX: should we systematically remove a run that's empty?
+                    mRanges.removeItemsAt(i);
+                }
+            } else {
+                // split the run
+                run_t new_run;
+                new_run.first = token+1;
+                new_run.length = run.first+run.length - new_run.first;
+                run.length = token - run.first;
+                mRanges.insertAt(new_run, i+1);
+            }
+            return NO_ERROR;
+        }
+    }
+    return NAME_NOT_FOUND;
+}
+
+ssize_t Tokenizer::_indexOrderOf(uint32_t token, size_t* order) const
+{
+    // binary search
+    ssize_t err = NAME_NOT_FOUND;
+    ssize_t l = 0;
+    ssize_t h = mRanges.size()-1;
+    ssize_t mid;
+    const run_t* a = mRanges.array();
+    while (l <= h) {
+        mid = l + (h - l)/2;
+        const run_t* const curr = a + mid;
+        int c = 0;
+        if (token < curr->first)                        c = 1;
+        else if (token >= curr->first+curr->length)     c = -1;
+        if (c == 0) {
+            err = l = mid;
+            break;
+        } else if (c < 0) {
+            l = mid + 1;
+        } else {
+            h = mid - 1;
+        }
+    }
+    if (order) *order = l;
+    return err;
+}
+
+ssize_t Tokenizer::_insertTokenAt(uint32_t token, size_t index)
+{
+    const size_t c = mRanges.size();
+
+    if (index >= 1) {
+        // do we need to merge with the previous run?
+        run_t& p = mRanges.editItemAt(index-1);
+        if (p.first+p.length == token) {
+            p.length += 1;
+            if (index < c) {
+                const run_t& n = mRanges[index];
+                if (token+1 == n.first) {
+                    p.length += n.length;
+                    mRanges.removeItemsAt(index);
+                }
+            }
+            return index;
+        }
+    }
+    
+    if (index < c) {
+        // do we need to merge with the next run?
+        run_t& n = mRanges.editItemAt(index);
+        if (token+1 == n.first) {
+            n.first -= 1;
+            n.length += 1;
+            return index;
+        }
+    }
+
+    return mRanges.insertAt(run_t(token,1), index);
+}
+
+void Tokenizer::dump() const
+{
+    const run_t* ranges = mRanges.array();
+    const size_t c = mRanges.size();
+    printf("Tokenizer (%p, size = %lu)\n", this, c);
+    for (size_t i=0 ; i<c ; i++) {
+        printf("%lu: (%u, %u)\n", i, ranges[i].first, ranges[i].length);
+    }
+}
+
+}; // namespace android
+
diff --git a/libs/surfaceflinger/Tokenizer.h b/libs/surfaceflinger/Tokenizer.h
new file mode 100644
index 0000000..6b3057d
--- /dev/null
+++ b/libs/surfaceflinger/Tokenizer.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_TOKENIZER_H
+#define ANDROID_TOKENIZER_H
+
+#include <utils/Vector.h>
+#include <utils/Errors.h>
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+class Tokenizer
+{
+public:
+                Tokenizer();
+                Tokenizer(const Tokenizer& other);
+                ~Tokenizer();
+
+    uint32_t    acquire();
+    status_t    reserve(uint32_t token);
+    status_t    release(uint32_t token);
+    bool        isAcquired(uint32_t token) const;
+
+    void dump() const;
+
+    struct run_t {
+        run_t() {};
+        run_t(uint32_t f, uint32_t l) : first(f), length(l) {}
+        uint32_t    first;
+        uint32_t    length;
+    };
+private:
+    ssize_t _indexOrderOf(uint32_t token, size_t* order=0) const;
+    ssize_t _insertTokenAt(uint32_t token, size_t index);
+    Vector<run_t>   mRanges;
+};
+
+}; // namespace android
+
+// ----------------------------------------------------------------------------
+
+#endif // ANDROID_TOKENIZER_H
diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp
new file mode 100644
index 0000000..bec7a64
--- /dev/null
+++ b/libs/surfaceflinger/Transform.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2007 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 <ui/Region.h>
+
+#include <private/pixelflinger/ggl_fixed.h>
+
+#include "Transform.h"
+
+// ---------------------------------------------------------------------------
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+Transform::Transform()
+    : mType(0)
+{
+    mTransform.reset();
+}
+
+Transform::Transform(const Transform&  other)
+    : mTransform(other.mTransform), mType(other.mType)
+{
+}
+
+Transform::~Transform() {
+}
+
+Transform Transform::operator * (const Transform& rhs) const
+{
+    if (LIKELY(mType == 0))
+        return rhs;
+
+    Transform r(*this);
+    r.mTransform.preConcat(rhs.mTransform);
+    r.mType |= rhs.mType;
+    return r;
+}
+
+float Transform::operator [] (int i) const
+{
+    float r = 0;
+    switch(i) {
+        case 0: r = SkScalarToFloat( mTransform[SkMatrix::kMScaleX] );  break;
+        case 1: r = SkScalarToFloat( mTransform[SkMatrix::kMSkewX] );   break;
+        case 2: r = SkScalarToFloat( mTransform[SkMatrix::kMSkewY] );   break;
+        case 3: r = SkScalarToFloat( mTransform[SkMatrix::kMScaleY] );  break;
+    }
+    return r;
+}
+
+uint8_t Transform::type() const
+{
+    if (UNLIKELY(mType & 0x80000000)) {
+        mType = mTransform.getType();
+    }
+    return uint8_t(mType & 0xFF);
+}
+
+bool Transform::transformed() const {
+    return type() > SkMatrix::kTranslate_Mask;
+}
+
+int Transform::tx() const {
+    return SkScalarRound( mTransform[SkMatrix::kMTransX] );
+}
+
+int Transform::ty() const {
+    return SkScalarRound( mTransform[SkMatrix::kMTransY] );
+}
+
+void Transform::reset() {
+    mTransform.reset();
+    mType = 0;
+}
+
+void Transform::set( float xx, float xy,
+                     float yx, float yy)
+{
+    mTransform.set(SkMatrix::kMScaleX, SkFloatToScalar(xx));
+    mTransform.set(SkMatrix::kMSkewX, SkFloatToScalar(xy));
+    mTransform.set(SkMatrix::kMSkewY, SkFloatToScalar(yx));
+    mTransform.set(SkMatrix::kMScaleY, SkFloatToScalar(yy));
+    mType |= 0x80000000;
+}
+
+void Transform::set(int tx, int ty)
+{
+    if (tx | ty) {
+        mTransform.set(SkMatrix::kMTransX, SkIntToScalar(tx));
+        mTransform.set(SkMatrix::kMTransY, SkIntToScalar(ty));
+        mType |= SkMatrix::kTranslate_Mask;
+    } else {
+        mTransform.set(SkMatrix::kMTransX, 0);
+        mTransform.set(SkMatrix::kMTransY, 0);
+        mType &= ~SkMatrix::kTranslate_Mask;
+    }
+}
+
+void Transform::transform(GLfixed* point, int x, int y) const
+{
+    SkPoint s;
+    mTransform.mapXY(SkIntToScalar(x), SkIntToScalar(y), &s);
+    point[0] = SkScalarToFixed(s.fX);
+    point[1] = SkScalarToFixed(s.fY);
+}
+
+Rect Transform::makeBounds(int w, int h) const
+{
+    Rect r;
+    SkRect d, s;
+    s.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
+    mTransform.mapRect(&d, s);
+    r.left   = SkScalarRound( d.fLeft );
+    r.top    = SkScalarRound( d.fTop );
+    r.right  = SkScalarRound( d.fRight );
+    r.bottom = SkScalarRound( d.fBottom );
+    return r;
+}
+
+Rect Transform::transform(const Rect& bounds) const
+{
+    Rect r;
+    SkRect d, s;
+    s.set(  SkIntToScalar( bounds.left ),
+            SkIntToScalar( bounds.top ),
+            SkIntToScalar( bounds.right ),
+            SkIntToScalar( bounds.bottom ));
+    mTransform.mapRect(&d, s);
+    r.left   = SkScalarRound( d.fLeft );
+    r.top    = SkScalarRound( d.fTop );
+    r.right  = SkScalarRound( d.fRight );
+    r.bottom = SkScalarRound( d.fBottom );
+    return r;
+}
+
+Region Transform::transform(const Region& reg) const
+{
+    Region out;
+    if (UNLIKELY(transformed())) {
+        if (LIKELY(preserveRects())) {
+            Rect r;
+            Region::iterator iterator(reg);
+            while (iterator.iterate(&r)) {
+                out.orSelf(transform(r));
+            }
+        } else {
+            out.set(transform(reg.bounds()));
+        }
+    } else {
+        out = reg.translate(tx(), ty());
+    }
+    return out;
+}
+
+int32_t Transform::getOrientation() const
+{
+    uint32_t flags = 0;
+    if (UNLIKELY(transformed())) {
+        SkScalar a = mTransform[SkMatrix::kMScaleX];
+        SkScalar b = mTransform[SkMatrix::kMSkewX];
+        SkScalar c = mTransform[SkMatrix::kMSkewY];
+        SkScalar d = mTransform[SkMatrix::kMScaleY];
+        if (b==0 && c==0 && a && d) {
+            if (a<0)    flags |= FLIP_H;
+            if (d<0)    flags |= FLIP_V;
+        } else if (b && c && a==0 && d==0) {
+            flags |= ROT_90;
+            if (b>0)    flags |= FLIP_H;
+            if (c<0)    flags |= FLIP_V;
+        } else {
+            flags = 0x80000000;
+        }
+    }
+    return flags;
+}
+
+bool Transform::preserveRects() const
+{
+    return mTransform.rectStaysRect();
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h
new file mode 100644
index 0000000..0b4835e
--- /dev/null
+++ b/libs/surfaceflinger/Transform.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_TRANSFORM_H
+#define ANDROID_TRANSFORM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/Point.h>
+#include <ui/Rect.h>
+
+#include <GLES/gl.h>
+
+#include <core/SkMatrix.h>
+
+namespace android {
+
+class Region;
+
+// ---------------------------------------------------------------------------
+
+class Transform
+{
+public:
+                    Transform();
+                    Transform(const Transform&  other);
+                    ~Transform();
+
+            enum orientation_flags {
+                ROT_0   = 0x00000000,
+                FLIP_H  = 0x00000001,
+                FLIP_V  = 0x00000002,
+                ROT_90  = 0x00000004,
+                ROT_180 = FLIP_H|FLIP_V,
+                ROT_270 = ROT_180|ROT_90,
+                ROT_INVALID = 0x80000000
+            };
+
+            bool    transformed() const;
+            int32_t getOrientation() const;
+            bool    preserveRects() const;
+            
+            int     tx() const;
+            int     ty() const;
+        
+            void    reset();
+            void    set(float xx, float xy, float yx, float yy);
+            void    set(int tx, int ty);
+
+            Rect    makeBounds(int w, int h) const;
+            void    transform(GLfixed* point, int x, int y) const;
+            Region  transform(const Region& reg) const;
+            Rect    transform(const Rect& bounds) const;
+
+            Transform operator * (const Transform& rhs) const;
+            float operator [] (int i) const;
+
+    inline uint32_t getType() const { return type(); }
+            
+    inline Transform(bool) : mType(0xFF) { };
+
+private:
+    uint8_t     type() const;
+
+private:
+            SkMatrix    mTransform;
+    mutable uint32_t    mType;      
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif /* ANDROID_TRANSFORM_H */
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
new file mode 100644
index 0000000..0ccd71f
--- /dev/null
+++ b/libs/surfaceflinger/VRamHeap.cpp
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/MemoryDealer.h>
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapPmem.h>
+#include <utils/MemoryHeapBase.h>
+
+#include "GPUHardware/GPUHardware.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+/*
+ * Amount of memory we reserve for surface, per client in PMEM
+ * (PMEM is used for 2D acceleration)
+ * 8 MB of address space per client should be enough.
+ */
+static const int PMEM_SIZE = int(8 * 1024 * 1024);
+
+int SurfaceHeapManager::global_pmem_heap = 0;
+
+// ---------------------------------------------------------------------------
+
+SurfaceHeapManager::SurfaceHeapManager(const sp<SurfaceFlinger>& flinger, 
+        size_t clientHeapSize)
+    : mFlinger(flinger), mClientHeapSize(clientHeapSize)
+{
+    SurfaceHeapManager::global_pmem_heap = 1;
+}
+
+SurfaceHeapManager::~SurfaceHeapManager()
+{
+}
+
+void SurfaceHeapManager::onFirstRef()
+{
+    if (global_pmem_heap) {
+        const char* device = "/dev/pmem";
+        mPMemHeap = new PMemHeap(device, PMEM_SIZE);
+        if (mPMemHeap->base() == MAP_FAILED) {
+            mPMemHeap.clear();
+            global_pmem_heap = 0;
+        }
+    }
+}
+
+sp<MemoryDealer> SurfaceHeapManager::createHeap(
+        uint32_t flags,
+        pid_t client_pid,
+        const sp<MemoryDealer>& defaultAllocator)
+{
+    sp<MemoryDealer> dealer; 
+
+    if (flags & ISurfaceComposer::eGPU) {
+        // don't grant GPU memory if GPU is disabled
+        char value[PROPERTY_VALUE_MAX];
+        property_get("debug.egl.hw", value, "1");
+        if (atoi(value) == 0) {
+            flags &= ~ISurfaceComposer::eGPU;
+        }
+    }
+
+    if (flags & ISurfaceComposer::eGPU) {
+        // FIXME: this is msm7201A specific, where gpu surfaces may not be secure
+        if (!(flags & ISurfaceComposer::eSecure)) {
+            // if GPU doesn't work, we try eHardware
+            flags |= ISurfaceComposer::eHardware;
+            // asked for GPU memory, try that first
+            dealer = mFlinger->getGPU()->request(client_pid);
+        }
+    }
+
+    if (dealer == NULL) {
+        if (defaultAllocator != NULL)
+            // if a default allocator is given, use that
+            dealer = defaultAllocator;
+    }
+    
+    if (dealer == NULL) {
+        // always try h/w accelerated memory first
+        if (global_pmem_heap) {
+            const sp<PMemHeap>& heap(mPMemHeap);
+            if (dealer == NULL && heap != NULL) {
+                dealer = new MemoryDealer( 
+                        heap->createClientHeap(),
+                        heap->getAllocator());
+            }
+        }
+    }
+
+    if (dealer == NULL) {
+        // return the ashmem allocator (software rendering)
+        dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
+    }
+    return dealer;
+}
+
+sp<SimpleBestFitAllocator> SurfaceHeapManager::getAllocator(int type) const 
+{
+    Mutex::Autolock _l(mLock);
+    sp<SimpleBestFitAllocator> allocator;
+
+    // this is only used for debugging
+    switch (type) {
+        case NATIVE_MEMORY_TYPE_PMEM:
+            if (mPMemHeap != 0) {
+                allocator = mPMemHeap->getAllocator();
+            }
+            break;
+    }
+    return allocator;
+}
+
+// ---------------------------------------------------------------------------
+
+PMemHeap::PMemHeap(const char* const device, size_t size, size_t reserved)
+    : MemoryHeapBase(device, size)
+{
+    //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
+    if (base() != MAP_FAILED) {
+        //LOGD("%s, %u bytes", device, virtualSize());
+        if (reserved == 0)
+            reserved = virtualSize();
+        mAllocator = new SimpleBestFitAllocator(reserved);
+    }
+}
+
+PMemHeap::~PMemHeap() {
+    //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
+}
+
+sp<MemoryHeapPmem> PMemHeap::createClientHeap() {
+    sp<MemoryHeapBase> parentHeap(this);
+    return new MemoryHeapPmem(parentHeap);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/surfaceflinger/VRamHeap.h b/libs/surfaceflinger/VRamHeap.h
new file mode 100644
index 0000000..9140167
--- /dev/null
+++ b/libs/surfaceflinger/VRamHeap.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_VRAM_HEAP_H
+#define ANDROID_VRAM_HEAP_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/MemoryDealer.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class PMemHeap;
+class MemoryHeapPmem;
+class SurfaceFlinger; 
+
+// ---------------------------------------------------------------------------
+
+class SurfaceHeapManager  : public RefBase
+{
+public:
+    SurfaceHeapManager(const sp<SurfaceFlinger>& flinger, size_t clientHeapSize);
+    virtual ~SurfaceHeapManager();
+    virtual void onFirstRef();
+    /* use ISurfaceComposer flags eGPU|eHArdware|eSecure */
+    sp<MemoryDealer> createHeap(uint32_t flags=0, pid_t client_pid = 0,
+            const sp<MemoryDealer>& defaultAllocator = 0);
+    
+    // used for debugging only...
+    sp<SimpleBestFitAllocator> getAllocator(int type) const;
+
+private:
+    sp<PMemHeap> getHeap(int type) const;
+
+    sp<SurfaceFlinger> mFlinger;
+    mutable Mutex   mLock;
+    size_t          mClientHeapSize;
+    sp<PMemHeap>    mPMemHeap;
+    static int global_pmem_heap;
+};
+
+// ---------------------------------------------------------------------------
+
+class PMemHeap : public MemoryHeapBase
+{
+public:
+                PMemHeap(const char* const vram,
+                        size_t size=0, size_t reserved=0);
+    virtual     ~PMemHeap();
+    
+    virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
+        return mAllocator; 
+    }
+    virtual sp<MemoryHeapPmem> createClientHeap();
+    
+private:
+    sp<SimpleBestFitAllocator>  mAllocator;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_VRAM_HEAP_H
diff --git a/libs/surfaceflinger/clz.cpp b/libs/surfaceflinger/clz.cpp
new file mode 100644
index 0000000..2456b86
--- /dev/null
+++ b/libs/surfaceflinger/clz.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 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 "clz.h"
+
+namespace android {
+
+int clz_impl(int32_t x)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    return __builtin_clz(x);
+#else
+    if (!x) return 32;
+    int e = 31;
+    if (x&0xFFFF0000)   { e -=16; x >>=16; }
+    if (x&0x0000FF00)   { e -= 8; x >>= 8; }
+    if (x&0x000000F0)   { e -= 4; x >>= 4; }
+    if (x&0x0000000C)   { e -= 2; x >>= 2; }
+    if (x&0x00000002)   { e -= 1; }
+    return e;
+#endif
+}
+
+}; // namespace android
diff --git a/libs/surfaceflinger/clz.h b/libs/surfaceflinger/clz.h
new file mode 100644
index 0000000..0ddf986
--- /dev/null
+++ b/libs/surfaceflinger/clz.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_SURFACE_FLINGER_CLZ_H
+
+#include <stdint.h>
+
+namespace android {
+
+int clz_impl(int32_t x);
+
+int inline clz(int32_t x)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    return __builtin_clz(x);
+#else
+    return clz_impl(x);
+#endif
+}
+
+
+}; // namespace android
+
+#endif /* ANDROID_SURFACE_FLINGER_CLZ_H */
diff --git a/libs/surfaceflinger/tests/Android.mk b/libs/surfaceflinger/tests/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/libs/surfaceflinger/tests/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/libs/surfaceflinger/tests/overlays/Android.mk b/libs/surfaceflinger/tests/overlays/Android.mk
new file mode 100644
index 0000000..dc47e45
--- /dev/null
+++ b/libs/surfaceflinger/tests/overlays/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	overlays.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libutils \
+    libui
+
+LOCAL_MODULE:= test-overlays
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libs/surfaceflinger/tests/overlays/overlays.cpp b/libs/surfaceflinger/tests/overlays/overlays.cpp
new file mode 100644
index 0000000..f3c046f
--- /dev/null
+++ b/libs/surfaceflinger/tests/overlays/overlays.cpp
@@ -0,0 +1,58 @@
+#include <utils/IPCThreadState.h>
+#include <utils/ProcessState.h>
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <ui/Surface.h>
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+#include <ui/SurfaceComposerClient.h>
+
+using namespace android;
+
+namespace android {
+class Test {
+public:
+    static const sp<ISurface>& getISurface(const sp<Surface>& s) {
+        return s->getISurface();
+    }
+};
+};
+
+int main(int argc, char** argv)
+{
+    // set up the thread-pool
+    sp<ProcessState> proc(ProcessState::self());
+    ProcessState::self()->startThreadPool();
+
+    // create a client to surfaceflinger
+    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
+    
+    // create pushbuffer surface
+    sp<Surface> surface = client->createSurface(getpid(), 0, 320, 240, 
+            PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);
+
+    // get to the isurface
+    sp<ISurface> isurface = Test::getISurface(surface);
+    printf("isurface = %p\n", isurface.get());
+    
+    // now request an overlay
+    sp<OverlayRef> ref = isurface->createOverlay(320, 240, PIXEL_FORMAT_RGB_565);
+    sp<Overlay> overlay = new Overlay(ref);
+    
+
+    /*
+     * here we can use the overlay API 
+     */
+    
+    overlay_buffer_t buffer; 
+    overlay->dequeueBuffer(&buffer);
+    printf("buffer = %p\n", buffer);
+    
+    void* address = overlay->getBufferAddress(buffer);
+    printf("address = %p\n", address);
+
+    overlay->queueBuffer(buffer);
+
+    return 0;
+}
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
new file mode 100644
index 0000000..f944357
--- /dev/null
+++ b/libs/ui/Android.mk
@@ -0,0 +1,41 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	Camera.cpp \
+	CameraParameters.cpp \
+	EGLDisplaySurface.cpp \
+	EGLNativeWindowSurface.cpp \
+	EventHub.cpp \
+	EventRecurrence.cpp \
+	KeyLayoutMap.cpp \
+	KeyCharacterMap.cpp \
+	ICamera.cpp \
+	ICameraClient.cpp \
+	ICameraService.cpp \
+	IOverlay.cpp \
+	ISurfaceComposer.cpp \
+	ISurface.cpp \
+	ISurfaceFlingerClient.cpp \
+	LayerState.cpp \
+	Overlay.cpp \
+	PixelFormat.cpp \
+	Point.cpp \
+	Rect.cpp \
+	Region.cpp \
+	Surface.cpp \
+	SurfaceComposerClient.cpp \
+	SurfaceFlingerSynchro.cpp \
+	Time.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcorecg \
+	libcutils \
+	libutils \
+	libpixelflinger \
+	libhardware \
+	libhardware_legacy
+
+LOCAL_MODULE:= libui
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
new file mode 100644
index 0000000..b3cbda1
--- /dev/null
+++ b/libs/ui/Camera.cpp
@@ -0,0 +1,408 @@
+/*
+**
+** Copyright (C) 2008, The Android Open Source Project
+** Copyright (C) 2008 HTC Inc.
+**
+** 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Camera"
+#include <utils/Log.h>
+#include <utils/IServiceManager.h>
+#include <utils/threads.h>
+#include <utils/IMemory.h>
+#include <ui/Surface.h>
+#include <ui/Camera.h>
+#include <ui/ICameraService.h>
+
+namespace android {
+
+// client singleton for camera service binder interface
+Mutex Camera::mLock;
+sp<ICameraService> Camera::mCameraService;
+sp<Camera::DeathNotifier> Camera::mDeathNotifier;
+
+// establish binder interface to camera service
+const sp<ICameraService>& Camera::getCameraService()
+{
+    Mutex::Autolock _l(mLock);
+    if (mCameraService.get() == 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16("media.camera"));
+            if (binder != 0)
+                break;
+            LOGW("CameraService not published, waiting...");
+            usleep(500000); // 0.5 s
+        } while(true);
+        if (mDeathNotifier == NULL) {
+            mDeathNotifier = new DeathNotifier();
+        }
+        binder->linkToDeath(mDeathNotifier);
+        mCameraService = interface_cast<ICameraService>(binder);
+    }
+    LOGE_IF(mCameraService==0, "no CameraService!?");
+    return mCameraService;
+}
+
+// ---------------------------------------------------------------------------
+
+Camera::Camera()
+{
+    init();
+}
+
+Camera::Camera(const sp<ICamera>& camera)
+{
+    init();
+    // connect this client to existing camera remote
+    if (camera->connect(this) == NO_ERROR) {
+        mStatus = NO_ERROR;
+        mCamera = camera;
+        camera->asBinder()->linkToDeath(this);
+    }
+}
+
+void Camera::init()
+{
+    mStatus = UNKNOWN_ERROR;
+    mShutterCallback = 0;
+    mShutterCallbackCookie = 0;
+    mRawCallback = 0;
+    mRawCallbackCookie = 0;
+    mJpegCallback = 0;
+    mJpegCallbackCookie = 0;
+    mPreviewCallback = 0;
+    mPreviewCallbackCookie = 0;
+    mRecordingCallback = 0;
+    mRecordingCallbackCookie = 0;
+    mErrorCallback = 0;
+    mErrorCallbackCookie = 0;
+    mAutoFocusCallback = 0;
+    mAutoFocusCallbackCookie = 0;
+}
+
+Camera::~Camera()
+{
+    disconnect();
+}
+
+sp<Camera> Camera::connect()
+{
+    LOGV("connect");
+    sp<Camera> c = new Camera();
+    const sp<ICameraService>& cs = getCameraService();
+    if (cs != 0) {
+        c->mCamera = cs->connect(c);
+    }
+    if (c->mCamera != 0) {
+        c->mCamera->asBinder()->linkToDeath(c);
+        c->mStatus = NO_ERROR;
+    } else {
+        c.clear();
+    }
+    return c;
+}
+
+void Camera::disconnect()
+{
+    LOGV("disconnect");
+    if (mCamera != 0) {
+        mErrorCallback = 0;
+        mCamera->disconnect();
+        mCamera = 0;
+    }
+}
+
+status_t Camera::reconnect()
+{
+    LOGV("reconnect");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->connect(this);
+}
+
+sp<ICamera> Camera::remote()
+{
+    return mCamera;
+}
+
+status_t Camera::lock()
+{
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->lock();
+}
+
+status_t Camera::unlock()
+{
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->unlock();
+}
+
+// pass the buffered ISurface to the camera service
+status_t Camera::setPreviewDisplay(const sp<Surface>& surface)
+{
+    LOGV("setPreviewDisplay");
+    if (surface == 0) {
+        LOGE("app passed NULL surface");
+        return NO_INIT;
+    }
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->setPreviewDisplay(surface->getISurface());
+}
+
+status_t Camera::setPreviewDisplay(const sp<ISurface>& surface)
+{
+    LOGV("setPreviewDisplay");
+    if (surface == 0) {
+        LOGE("app passed NULL surface");
+        return NO_INIT;
+    }
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->setPreviewDisplay(surface);
+}
+
+
+// start preview mode, must call setPreviewDisplay first
+status_t Camera::startPreview()
+{
+    LOGV("startPreview");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->startPreview();
+}
+
+// start recording mode, must call setPreviewDisplay first
+status_t Camera::startRecording()
+{
+    LOGV("startRecording");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->startRecording();
+}
+
+// stop preview mode
+void Camera::stopPreview()
+{
+    LOGV("stopPreview");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return;
+    c->stopPreview();
+}
+
+// stop recording mode
+void Camera::stopRecording()
+{
+    LOGV("stopRecording");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return;
+    c->stopRecording();
+}
+
+// release a recording frame
+void Camera::releaseRecordingFrame(const sp<IMemory>& mem)
+{
+    LOGV("releaseRecordingFrame");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return;
+    c->releaseRecordingFrame(mem);
+}
+
+// get preview state
+bool Camera::previewEnabled()
+{
+    LOGV("previewEnabled");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return false;
+    return c->previewEnabled();
+}
+
+// get recording state
+bool Camera::recordingEnabled()
+{
+    LOGV("recordingEnabled");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return false;
+    return c->recordingEnabled();
+}
+
+status_t Camera::autoFocus()
+{
+    LOGV("autoFocus");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->autoFocus();
+}
+
+// take a picture
+status_t Camera::takePicture()
+{
+    LOGV("takePicture");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->takePicture();
+}
+
+// set preview/capture parameters - key/value pairs
+status_t Camera::setParameters(const String8& params)
+{
+    LOGV("setParameters");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->setParameters(params);
+}
+
+// get preview/capture parameters - key/value pairs
+String8 Camera::getParameters() const
+{
+    LOGV("getParameters");
+    String8 params;
+    sp <ICamera> c = mCamera;
+    if (c != 0) params = mCamera->getParameters();
+    return params;
+}
+
+void Camera::setAutoFocusCallback(autofocus_callback cb, void *cookie)
+{
+    LOGV("setAutoFocusCallback");
+    mAutoFocusCallback = cb;
+    mAutoFocusCallbackCookie = cookie;
+}
+
+void Camera::setShutterCallback(shutter_callback cb, void *cookie)
+{
+    LOGV("setShutterCallback");
+    mShutterCallback = cb;
+    mShutterCallbackCookie = cookie;
+}
+
+void Camera::setRawCallback(frame_callback cb, void *cookie)
+{
+    LOGV("setRawCallback");
+    mRawCallback = cb;
+    mRawCallbackCookie = cookie;
+}
+
+void Camera::setJpegCallback(frame_callback cb, void *cookie)
+{
+    LOGV("setJpegCallback");
+    mJpegCallback = cb;
+    mJpegCallbackCookie = cookie;
+}
+
+void Camera::setPreviewCallback(frame_callback cb, void *cookie, int flag)
+{
+    LOGV("setPreviewCallback");
+    mPreviewCallback = cb;
+    mPreviewCallbackCookie = cookie;
+    sp <ICamera> c = mCamera;
+    if (c == 0) return;
+    mCamera->setPreviewCallbackFlag(flag);
+}
+
+void Camera::setRecordingCallback(frame_callback cb, void *cookie)
+{
+    LOGV("setRecordingCallback");
+    mRecordingCallback = cb;
+    mRecordingCallbackCookie = cookie;
+}
+
+void Camera::setErrorCallback(error_callback cb, void *cookie)
+{
+    LOGV("setErrorCallback");
+    mErrorCallback = cb;
+    mErrorCallbackCookie = cookie;
+}
+
+void Camera::autoFocusCallback(bool focused)
+{
+    LOGV("autoFocusCallback");
+    if (mAutoFocusCallback) {
+        mAutoFocusCallback(focused, mAutoFocusCallbackCookie);
+    }
+}
+
+void Camera::shutterCallback()
+{
+    LOGV("shutterCallback");
+    if (mShutterCallback) {
+        mShutterCallback(mShutterCallbackCookie);
+    }
+}
+
+void Camera::rawCallback(const sp<IMemory>& picture)
+{
+    LOGV("rawCallback");
+    if (mRawCallback) {
+        mRawCallback(picture, mRawCallbackCookie);
+    }
+}
+
+// callback from camera service when image is ready
+void Camera::jpegCallback(const sp<IMemory>& picture)
+{
+    LOGV("jpegCallback");
+    if (mJpegCallback) {
+        mJpegCallback(picture, mJpegCallbackCookie);
+    }
+}
+
+// callback from camera service when preview frame is ready
+void Camera::previewCallback(const sp<IMemory>& frame)
+{
+    LOGV("frameCallback");
+    if (mPreviewCallback) {
+        mPreviewCallback(frame, mPreviewCallbackCookie);
+    }
+}
+
+// callback from camera service when a recording frame is ready
+void Camera::recordingCallback(const sp<IMemory>& frame)
+{
+    LOGV("recordingCallback");
+    if (mRecordingCallback) {
+        mRecordingCallback(frame, mRecordingCallbackCookie);
+    }
+}
+
+// callback from camera service when an error occurs in preview or takePicture
+void Camera::errorCallback(status_t error)
+{
+    LOGV("errorCallback");
+    if (mErrorCallback) {
+        mErrorCallback(error, mErrorCallbackCookie);
+    }
+}
+
+void Camera::binderDied(const wp<IBinder>& who) {
+    LOGW("ICamera died");
+    if (mErrorCallback) {
+        mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie);
+    }
+}
+
+void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {
+    LOGV("binderDied");
+    Mutex::Autolock _l(Camera::mLock);
+    Camera::mCameraService.clear();
+    LOGW("Camera server died!");
+}
+
+}; // namespace android
+
diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp
new file mode 100644
index 0000000..6c25836
--- /dev/null
+++ b/libs/ui/CameraParameters.cpp
@@ -0,0 +1,273 @@
+/*
+**
+** Copyright 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.
+*/
+
+#define LOG_TAG "CameraParams"
+#include <utils/Log.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <ui/CameraParameters.h>
+
+namespace android {
+
+static const char* portrait = "portrait";
+static const char* landscape = "landscape";
+
+CameraParameters::CameraParameters()
+                : mMap()
+{
+}
+
+CameraParameters::~CameraParameters()
+{
+}
+
+String8 CameraParameters::flatten() const
+{
+    String8 flattened("");
+    size_t size = mMap.size();
+
+    for (size_t i = 0; i < size; i++) {
+        String8 k, v;
+        k = mMap.keyAt(i);
+        v = mMap.valueAt(i);
+
+        flattened += k;
+        flattened += "=";
+        flattened += v;
+        if (i != size-1)
+            flattened += ";";
+    }
+
+    return flattened;
+}
+
+void CameraParameters::unflatten(const String8 &params)
+{
+    const char *a = params.string();
+    const char *b;
+
+    mMap.clear();
+
+    for (;;) {
+        // Find the bounds of the key name.
+        b = strchr(a, '=');
+        if (b == 0)
+            break;
+
+        // Create the key string.
+        String8 k(a, (size_t)(b-a));
+
+        // Find the value.
+        a = b+1;
+        b = strchr(a, ';');
+        if (b == 0) {
+            // If there's no semicolon, this is the last item.
+            String8 v(a);
+            mMap.add(k, v);
+            break;
+        }
+
+        String8 v(a, (size_t)(b-a));
+        mMap.add(k, v);
+        a = b+1;
+    }
+}
+
+
+void CameraParameters::set(const char *key, const char *value)
+{
+    // XXX i think i can do this with strspn() 
+    if (strchr(key, '=') || strchr(key, ';')) {
+        //XXX LOGE("Key \"%s\"contains invalid character (= or ;)", key);
+        return;
+    }
+
+    if (strchr(value, '=') || strchr(key, ';')) {
+        //XXX LOGE("Value \"%s\"contains invalid character (= or ;)", value);
+        return;
+    }
+
+    mMap.replaceValueFor(String8(key), String8(value));
+}
+
+void CameraParameters::set(const char *key, int value)
+{
+    char str[16];
+    sprintf(str, "%d", value);
+    set(key, str);
+}
+
+const char *CameraParameters::get(const char *key) const
+{
+    String8 v = mMap.valueFor(String8(key));
+    if (v.length() == 0)
+        return 0;
+    return v.string();
+}
+
+int CameraParameters::getInt(const char *key) const
+{
+    const char *v = get(key);
+    if (v == 0)
+        return -1;
+    return strtol(v, 0, 0);
+}
+
+static int parse_size(const char *str, int &width, int &height)
+{
+    // Find the width.
+    char *end;
+    int w = (int)strtol(str, &end, 10);
+    // If an 'x' does not immediately follow, give up.
+    if (*end != 'x')
+        return -1;
+
+    // Find the height, immediately after the 'x'.
+    int h = (int)strtol(end+1, 0, 10);
+
+    width = w;
+    height = h;
+
+    return 0;
+}
+
+void CameraParameters::setPreviewSize(int width, int height)
+{
+    char str[32];
+    sprintf(str, "%dx%d", width, height);
+    set("preview-size", str);
+}
+
+void CameraParameters::getPreviewSize(int *width, int *height) const
+{
+    *width = -1;
+    *height = -1;
+
+    // Get the current string, if it doesn't exist, leave the -1x-1
+    const char *p = get("preview-size");
+    if (p == 0)
+        return;
+
+    int w, h;
+    if (parse_size(p, w, h) == 0) {
+        *width = w;
+        *height = h;
+    }
+}
+
+void CameraParameters::setPreviewFrameRate(int fps)
+{
+    set("preview-frame-rate", fps);
+}
+
+int CameraParameters::getPreviewFrameRate() const
+{
+    return getInt("preview-frame-rate");
+}
+
+void CameraParameters::setPreviewFormat(const char *format)
+{
+    set("preview-format", format);
+}
+
+int CameraParameters::getOrientation() const
+{
+    const char* orientation = get("orientation");
+    if (orientation && !strcmp(orientation, portrait))
+        return CAMERA_ORIENTATION_PORTRAIT;
+    return CAMERA_ORIENTATION_LANDSCAPE;
+}
+
+void CameraParameters::setOrientation(int orientation)
+{
+    if (orientation == CAMERA_ORIENTATION_PORTRAIT) {
+        set("preview-format", portrait);
+    } else {
+        set("preview-format", landscape);
+    }
+}
+
+const char *CameraParameters::getPreviewFormat() const
+{
+    return get("preview-format");
+}
+
+void CameraParameters::setPictureSize(int width, int height)
+{
+    char str[32];
+    sprintf(str, "%dx%d", width, height);
+    set("picture-size", str);
+}
+
+void CameraParameters::getPictureSize(int *width, int *height) const
+{
+    *width = -1;
+    *height = -1;
+
+    // Get the current string, if it doesn't exist, leave the -1x-1
+    const char *p = get("picture-size");
+    if (p == 0)
+        return;
+
+    int w, h;
+    if (parse_size(p, w, h) == 0) {
+        *width = w;
+        *height = h;
+    }
+}
+
+void CameraParameters::setPictureFormat(const char *format)
+{
+    set("picture-format", format);
+}
+
+const char *CameraParameters::getPictureFormat() const
+{
+    return get("picture-format");
+}
+
+void CameraParameters::dump() const
+{
+    LOGD("dump: mMap.size = %d", mMap.size());
+    for (size_t i = 0; i < mMap.size(); i++) {
+        String8 k, v;
+        k = mMap.keyAt(i);
+        v = mMap.valueAt(i);
+        LOGD("%s: %s\n", k.string(), v.string());
+    }
+}
+
+status_t CameraParameters::dump(int fd, const Vector<String16>& args) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, 255, "CameraParameters::dump: mMap.size = %d\n", mMap.size());
+    result.append(buffer);
+    for (size_t i = 0; i < mMap.size(); i++) {
+        String8 k, v;
+        k = mMap.keyAt(i);
+        v = mMap.valueAt(i);
+        snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string());
+        result.append(buffer);
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/libs/ui/EGLDisplaySurface.cpp b/libs/ui/EGLDisplaySurface.cpp
new file mode 100644
index 0000000..d06c98b
--- /dev/null
+++ b/libs/ui/EGLDisplaySurface.cpp
@@ -0,0 +1,519 @@
+/*
+ **
+ ** Copyright 2007 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.
+ */
+
+#define LOG_TAG "EGLDisplaySurface"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <cutils/properties.h>
+
+#include <hardware/copybit.h>
+
+#include <ui/SurfaceComposerClient.h>
+#include <ui/DisplayInfo.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/EGLDisplaySurface.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/msm_mdp.h>
+#endif
+
+#include <EGL/egl.h>
+
+#include <pixelflinger/format.h>
+
+
+// ----------------------------------------------------------------------------
+
+egl_native_window_t* android_createDisplaySurface()
+{
+    egl_native_window_t* s = new android::EGLDisplaySurface();
+    s->memory_type = NATIVE_MEMORY_TYPE_GPU;
+    return s;
+}
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+EGLDisplaySurface::EGLDisplaySurface()
+    : EGLNativeSurface<EGLDisplaySurface>()
+{
+    egl_native_window_t::version = sizeof(egl_native_window_t);
+    egl_native_window_t::ident = 0;
+    egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
+    egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
+    egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
+    egl_native_window_t::connect = 0;
+    egl_native_window_t::disconnect = 0;
+
+    mFb[0].data = 0;
+    mFb[1].data = 0;
+    mBlitEngine = 0;
+    egl_native_window_t::fd = mapFrameBuffer();
+    if (egl_native_window_t::fd >= 0) {
+        
+        hw_module_t const* module;
+        if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+            copybit_open(module, &mBlitEngine);
+        }
+        
+        const float in2mm = 25.4f;
+        float refreshRate = 1000000000000000LLU / (
+                float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres )
+                * ( mInfo.left_margin  + mInfo.right_margin + mInfo.xres )
+                * mInfo.pixclock);
+
+        const GGLSurface& buffer = mFb[1 - mIndex];
+        egl_native_window_t::width  = buffer.width;
+        egl_native_window_t::height = buffer.height;
+        egl_native_window_t::stride = buffer.stride;
+        egl_native_window_t::format = buffer.format;
+        egl_native_window_t::base   = intptr_t(mFb[0].data);
+        egl_native_window_t::offset =
+            intptr_t(buffer.data) - egl_native_window_t::base;
+        egl_native_window_t::flags  = 0;
+        egl_native_window_t::xdpi = (mInfo.xres * in2mm) / mInfo.width;
+        egl_native_window_t::ydpi = (mInfo.yres * in2mm) / mInfo.height;
+        egl_native_window_t::fps  = refreshRate;
+        egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_FB;
+        // no error, set the magic word
+        egl_native_window_t::magic = 0x600913;
+    }
+    mSwapCount = -1;
+    mPageFlipCount = 0;
+}
+
+EGLDisplaySurface::~EGLDisplaySurface()
+{
+    magic = 0;
+    copybit_close(mBlitEngine);
+    mBlitEngine = 0;
+    close(egl_native_window_t::fd);
+    munmap(mFb[0].data, mSize);
+    if (!(mFlags & PAGE_FLIP))
+        free((void*)mFb[1].data);
+}
+
+void EGLDisplaySurface::hook_incRef(NativeWindowType window) {
+    EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
+    that->incStrong(that);
+}
+void EGLDisplaySurface::hook_decRef(NativeWindowType window) {
+    EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
+    that->decStrong(that);
+}
+uint32_t EGLDisplaySurface::hook_swapBuffers(NativeWindowType window) {
+    EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
+    return that->swapBuffers();
+}
+
+void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
+{
+    mInfo.reserved[0] = 0x54445055; // "UPDT";
+    mInfo.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
+    mInfo.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
+}
+
+uint32_t EGLDisplaySurface::swapBuffers()
+{
+#define SHOW_FPS 0
+#if SHOW_FPS
+    nsecs_t now = systemTime();
+    if (mSwapCount == -1) {
+        mTime = now;
+        mSwapCount = 0;
+        mSleep = 0;
+    } else {
+        nsecs_t d = now-mTime;
+        if (d >= seconds(1)) {
+            double fps = (mSwapCount * double(seconds(1))) / double(d);
+            LOGD("%f fps, sleep=%d / frame",
+                    fps, (int)ns2us(mSleep / mSwapCount));
+            mSwapCount = 0;
+            mTime = now;
+            mSleep = 0;
+        } else {
+            mSwapCount++;
+        }
+    }
+#endif
+    /* If we can't do the page_flip, just copy the back buffer to the front */
+    if (!(mFlags & PAGE_FLIP)) {
+        memcpy(mFb[0].data, mFb[1].data, mInfo.xres*mInfo.yres*2);
+        return 0;
+    }
+
+    // do the actual flip
+    mIndex = 1 - mIndex;
+    mInfo.activate = FB_ACTIVATE_VBL;
+    mInfo.yoffset = mIndex ? mInfo.yres : 0;
+    if (ioctl(egl_native_window_t::fd, FBIOPUT_VSCREENINFO, &mInfo) == -1) {
+        LOGE("FBIOPUT_VSCREENINFO failed");
+        return 0;
+    }
+
+    /*
+     * this is a monstrous hack: Because the h/w accelerator is not able
+     * to render directly into the framebuffer, we need to copy its
+     * internal framebuffer out to the fb.
+     * oem[0] is used to access the fd of internal fb.
+     * All this is needed only in standalone mode, in SurfaceFlinger mode
+     * we control where the GPU renders.
+     * We do this only if we have copybit, since this hack is needed only
+     * with msm7k.
+     */
+    if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0] && mBlitEngine) {
+        copybit_device_t *copybit = mBlitEngine;
+        copybit_rect_t sdrect = { 0, 0,
+                egl_native_window_t::width, egl_native_window_t::height };
+        copybit_image_t dst = {
+                egl_native_window_t::width,
+                egl_native_window_t::height,
+                egl_native_window_t::format,
+                egl_native_window_t::offset,
+                (void*)egl_native_window_t::base,
+                egl_native_window_t::fd
+        };
+        copybit_image_t src = {
+                egl_native_window_t::width,
+                egl_native_window_t::height,
+                egl_native_window_t::format, // XXX: use proper format
+                egl_native_window_t::offset,
+                (void*)egl_native_window_t::base,  // XXX: use proper base
+                egl_native_window_t::oem[0]
+        };
+        region_iterator it(Region(Rect(
+                egl_native_window_t::width, egl_native_window_t::height)));
+        copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+        copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+        copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+        copybit->stretch(copybit, &dst, &src, &sdrect, &sdrect, &it);
+    }
+
+    // update the address of the buffer to draw to next
+    const GGLSurface& buffer = mFb[1 - mIndex];
+    egl_native_window_t::offset =
+        intptr_t(buffer.data) - egl_native_window_t::base;
+
+#if SHOW_FPS
+    mSleep += systemTime()-now;
+#endif
+
+    mPageFlipCount++;
+
+    // We don't support screen-size changes for now
+    return 0;
+}
+
+int32_t EGLDisplaySurface::getPageFlipCount() const
+{
+    return mPageFlipCount;
+}
+
+void EGLDisplaySurface::copyFrontToBack(const Region& copyback)
+{
+#if HAVE_ANDROID_OS
+    if (mBlitEngine) {
+        copybit_image_t dst = {
+                w:      egl_native_window_t::stride,
+                h:      egl_native_window_t::height,
+                format: egl_native_window_t::format,
+                offset: mFb[1-mIndex].data - mFb[0].data,
+                base:   (void*)egl_native_window_t::base,
+                fd:     egl_native_window_t::fd
+        };
+        copybit_image_t src = {
+                w:      egl_native_window_t::stride,
+                h:      egl_native_window_t::height,
+                format: egl_native_window_t::format,
+                offset: mFb[mIndex].data - mFb[0].data,
+                base:   (void*)egl_native_window_t::base,
+                fd:     egl_native_window_t::fd
+        };
+        region_iterator it(copyback);
+        mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
+    } else
+#endif
+    {
+        /* no extra copy needed since we copied back to front instead of
+         * flipping */
+        if (!(mFlags & PAGE_FLIP)) {
+            return;
+        }
+
+        Region::iterator iterator(copyback);
+        if (iterator) {
+            Rect r;
+            uint8_t* const screen_src = mFb[  mIndex].data;
+            uint8_t* const screen_dst = mFb[1-mIndex].data;
+            const size_t bpp = bytesPerPixel(egl_native_window_t::format);
+            const size_t bpr = egl_native_window_t::stride * bpp;
+            while (iterator.iterate(&r)) {
+                ssize_t h = r.bottom - r.top;
+                if (h) {
+                    size_t size = (r.right - r.left) * bpp;
+                    size_t o = (r.left + egl_native_window_t::stride * r.top) * bpp;
+                    uint8_t* s = screen_src + o;
+                    uint8_t* d = screen_dst + o;
+                    if (size == bpr) {
+                        size *= h;
+                        h = 1;
+                    }
+                    do {
+                        memcpy(d, s, size);
+                        d += bpr;
+                        s += bpr;
+                    } while (--h > 0);
+                }
+            }
+        }
+    }
+}
+
+void EGLDisplaySurface::copyFrontToImage(const copybit_image_t& dst)
+{
+#if HAVE_ANDROID_OS
+    if (mBlitEngine) {
+        copybit_image_t src = {
+                w:      egl_native_window_t::stride,
+                h:      egl_native_window_t::height,
+                format: egl_native_window_t::format,
+                offset: mFb[mIndex].data - mFb[0].data,
+                base:   (void*)egl_native_window_t::base,
+                fd:     egl_native_window_t::fd
+        };
+        region_iterator it(Region(Rect(
+                egl_native_window_t::width, egl_native_window_t::height)));
+        mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
+    } else
+#endif
+    {
+        uint8_t* const screen_src = mFb[  mIndex].data;
+        const size_t bpp = bytesPerPixel(egl_native_window_t::format);
+        const size_t bpr = egl_native_window_t::stride * bpp;
+        memcpy((char*)dst.base + dst.offset, screen_src,
+                bpr*egl_native_window_t::height);
+    }
+}
+
+void EGLDisplaySurface::copyBackToImage(const copybit_image_t& dst)
+{
+#if HAVE_ANDROID_OS
+    if (mBlitEngine) {
+        copybit_image_t src = {
+                w:      egl_native_window_t::stride,
+                h:      egl_native_window_t::height,
+                format: egl_native_window_t::format,
+                offset: mFb[1-mIndex].data - mFb[0].data,
+                base:   (void*)egl_native_window_t::base,
+                fd:     egl_native_window_t::fd
+        };
+        region_iterator it(Region(Rect(
+                egl_native_window_t::width, egl_native_window_t::height)));
+        mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
+    } else
+#endif
+    {
+        uint8_t* const screen_src = mFb[1-mIndex].data;
+        const size_t bpp = bytesPerPixel(egl_native_window_t::format);
+        const size_t bpr = egl_native_window_t::stride * bpp;
+        memcpy((char*)dst.base + dst.offset, screen_src,
+                bpr*egl_native_window_t::height);
+    }
+}
+
+
+status_t EGLDisplaySurface::mapFrameBuffer()
+{
+    char const * const device_template[] = {
+            "/dev/graphics/fb%u",
+            "/dev/fb%u",
+            0 };
+    int fd = -1;
+    int i=0;
+    char name[64];
+    while ((fd==-1) && device_template[i]) {
+        snprintf(name, 64, device_template[i], 0);
+        fd = open(name, O_RDWR, 0);
+        i++;
+    }
+    if (fd < 0)
+        return -errno;
+
+    struct fb_fix_screeninfo finfo;
+    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
+        return -errno;
+
+    struct fb_var_screeninfo info;
+    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
+        return -errno;
+
+    info.reserved[0] = 0;
+    info.reserved[1] = 0;
+    info.reserved[2] = 0;
+    info.xoffset = 0;
+    info.yoffset = 0;
+    info.yres_virtual = info.yres * 2;
+    info.bits_per_pixel = 16;
+    /* Explicitly request 5/6/5 */
+    info.red.offset = 11;
+    info.red.length = 5;
+    info.green.offset = 5;
+    info.green.length = 6;
+    info.blue.offset = 0;
+    info.blue.length = 5;
+    info.transp.offset = 0;
+    info.transp.length = 0;
+    info.activate = FB_ACTIVATE_NOW;
+
+    uint32_t flags = PAGE_FLIP;
+    if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
+        info.yres_virtual = info.yres;
+        flags &= ~PAGE_FLIP;
+        LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
+    }
+
+    if (info.yres_virtual < info.yres * 2) {
+        info.yres_virtual = info.yres;
+        flags &= ~PAGE_FLIP;
+        LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
+                info.yres_virtual, info.yres*2);
+    }
+
+    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
+        return -errno;
+
+    int refreshRate = 1000000000000000LLU /
+    (
+            uint64_t( info.upper_margin + info.lower_margin + info.yres )
+            * ( info.left_margin  + info.right_margin + info.xres )
+            * info.pixclock
+    );
+
+    if (refreshRate == 0) {
+        // bleagh, bad info from the driver
+        refreshRate = 60*1000;  // 60 Hz
+    }
+    if (int(info.width) <= 0 || int(info.height) <= 0) {
+        // the driver doesn't return that information
+        // default to 160 dpi
+        info.width  = ((info.xres * 25.4f)/160.0f + 0.5f);
+        info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
+    }
+
+    float xdpi = (info.xres * 25.4f) / info.width;
+    float ydpi = (info.yres * 25.4f) / info.height;
+    float fps  = refreshRate / 1000.0f;
+
+    LOGI(   "using (fd=%d)\n"
+            "id           = %s\n"
+            "xres         = %d px\n"
+            "yres         = %d px\n"
+            "xres_virtual = %d px\n"
+            "yres_virtual = %d px\n"
+            "bpp          = %d\n"
+            "r            = %2u:%u\n"
+            "g            = %2u:%u\n"
+            "b            = %2u:%u\n",
+            fd,
+            finfo.id,
+            info.xres,
+            info.yres,
+            info.xres_virtual,
+            info.yres_virtual,
+            info.bits_per_pixel,
+            info.red.offset, info.red.length,
+            info.green.offset, info.green.length,
+            info.blue.offset, info.blue.length
+    );
+
+    LOGI(   "width        = %d mm (%f dpi)\n"
+            "height       = %d mm (%f dpi)\n"
+            "refresh rate = %.2f Hz\n",
+            info.width,  xdpi,
+            info.height, ydpi,
+            fps
+    );
+
+
+    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
+        return -errno;
+
+    if (finfo.smem_len <= 0)
+        return -errno;
+
+    /*
+     * Open and map the display.
+     */
+
+    void* buffer  = (uint16_t*) mmap(
+            0, finfo.smem_len,
+            PROT_READ | PROT_WRITE,
+            MAP_SHARED,
+            fd, 0);
+
+    if (buffer == MAP_FAILED)
+        return -errno;
+
+    // at least for now, always clear the fb
+    memset(buffer, 0, finfo.smem_len);
+
+    uint8_t* offscreen[2];
+    offscreen[0] = (uint8_t*)buffer;
+    if (flags & PAGE_FLIP) {
+        offscreen[1] = (uint8_t*)buffer + finfo.line_length*info.yres;
+    } else {
+        offscreen[1] = (uint8_t*)malloc(finfo.smem_len);
+        if (offscreen[1] == 0) {
+            munmap(buffer, finfo.smem_len);
+            return NO_MEMORY;
+        }
+    }
+
+    mFlags = flags;
+    mInfo = info;
+    mFinfo = finfo;
+    mSize = finfo.smem_len;
+    mIndex = 0;
+    for (int i=0 ; i<2 ; i++) {
+        mFb[i].version = sizeof(GGLSurface);
+        mFb[i].width   = info.xres;
+        mFb[i].height  = info.yres;
+        mFb[i].stride  = finfo.line_length / (info.bits_per_pixel >> 3);
+        mFb[i].data    = (GGLubyte*)(offscreen[i]);
+        mFb[i].format  = GGL_PIXEL_FORMAT_RGB_565;
+    }
+    return fd;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/ui/EGLNativeWindowSurface.cpp b/libs/ui/EGLNativeWindowSurface.cpp
new file mode 100644
index 0000000..f1071cf
--- /dev/null
+++ b/libs/ui/EGLNativeWindowSurface.cpp
@@ -0,0 +1,161 @@
+/* 
+**
+** Copyright 2007 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.
+*/
+
+#define LOG_TAG "EGLNativeWindowSurface"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+
+#include <ui/SurfaceComposerClient.h>
+#include <ui/DisplayInfo.h>
+#include <ui/Rect.h>
+
+#include <EGL/egl.h>
+
+#include <pixelflinger/format.h>
+
+#include <ui/EGLNativeWindowSurface.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+EGLNativeWindowSurface::EGLNativeWindowSurface(const sp<Surface>& surface)
+    : EGLNativeSurface<EGLNativeWindowSurface>(),
+    mSurface(surface), mConnected(false)
+{
+    egl_native_window_t::magic = 0x600913;
+    egl_native_window_t::version = sizeof(egl_native_window_t);
+    egl_native_window_t::ident = 0;
+    egl_native_window_t::incRef = &EGLNativeWindowSurface::hook_incRef;
+    egl_native_window_t::decRef = &EGLNativeWindowSurface::hook_decRef;
+    egl_native_window_t::swapBuffers = &EGLNativeWindowSurface::hook_swapBuffers;
+    egl_native_window_t::connect = &EGLNativeWindowSurface::hook_connect;
+    egl_native_window_t::disconnect = &EGLNativeWindowSurface::hook_disconnect;
+    
+    DisplayInfo dinfo;
+    SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+    egl_native_window_t::xdpi = dinfo.xdpi;
+    egl_native_window_t::ydpi = dinfo.ydpi;
+    egl_native_window_t::fps  = dinfo.fps;
+    egl_native_window_t::flags= EGL_NATIVES_FLAG_DESTROY_BACKBUFFER;
+}
+
+EGLNativeWindowSurface::~EGLNativeWindowSurface()
+{
+    disconnect();
+    mSurface.clear();
+    magic = 0;
+}
+
+void EGLNativeWindowSurface::hook_incRef(NativeWindowType window)
+{
+    EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
+    that->incStrong(that);
+}
+
+void EGLNativeWindowSurface::hook_decRef(NativeWindowType window)
+{
+    EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
+    that->decStrong(that);
+}
+
+void EGLNativeWindowSurface::hook_connect(NativeWindowType window)
+{
+    EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
+    that->connect();
+}
+
+void EGLNativeWindowSurface::hook_disconnect(NativeWindowType window)
+{
+    EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
+    that->disconnect();
+}
+
+uint32_t EGLNativeWindowSurface::hook_swapBuffers(NativeWindowType window)
+{
+    EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
+    return that->swapBuffers();
+}
+
+void EGLNativeWindowSurface::setSwapRectangle(int l, int t, int w, int h)
+{
+    mSurface->setSwapRectangle(Rect(l, t, l+w, t+h));
+}
+
+uint32_t EGLNativeWindowSurface::swapBuffers()
+{
+    const int w = egl_native_window_t::width;
+    const int h = egl_native_window_t::height;
+    const sp<Surface>& surface(mSurface);
+    Surface::SurfaceInfo info;
+    surface->unlockAndPost();
+    surface->lock(&info);
+    // update the address of the buffer to draw to next
+    egl_native_window_t::base   = intptr_t(info.base);
+    egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
+    
+    // update size if it changed
+    if (w != int(info.w) || h != int(info.h)) {
+        egl_native_window_t::width  = info.w;
+        egl_native_window_t::height = info.h;
+        egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
+        egl_native_window_t::format = info.format;
+        return EGL_NATIVES_FLAG_SIZE_CHANGED;
+    }
+    return 0;
+}
+
+void EGLNativeWindowSurface::connect()
+{   
+    if (!mConnected) {
+        Surface::SurfaceInfo info;
+        mSurface->lock(&info);
+        mSurface->setSwapRectangle(Rect(info.w, info.h));
+        mConnected = true;
+
+        egl_native_window_t::width  = info.w;
+        egl_native_window_t::height = info.h;
+        egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
+        egl_native_window_t::format = info.format;
+        egl_native_window_t::base   = intptr_t(info.base);
+        egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
+        // FIXME: egl_native_window_t::memory_type used to be set from
+        // mSurface, but we wanted to break this dependency. We set it to
+        // GPU because the software rendered doesn't care, but the h/w
+        // accelerator needs it. Eventually, this value should go away
+        // completely, since memory will be managed by OpenGL.
+        egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_GPU; 
+        egl_native_window_t::fd = 0;
+    }
+}
+
+void EGLNativeWindowSurface::disconnect()
+{
+    if (mConnected) {
+        mSurface->unlock();
+        mConnected = false;
+    }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
new file mode 100644
index 0000000..3b29b09
--- /dev/null
+++ b/libs/ui/EventHub.cpp
@@ -0,0 +1,793 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+// Handle events, like key input and vsync.
+//
+// The goal is to provide an optimized solution for Linux, not an
+// implementation that works well across all platforms.  We expect
+// events to arrive on file descriptors, so that we can use a select()
+// select() call to sleep.
+//
+// We can't select() on anything but network sockets in Windows, so we
+// provide an alternative implementation of waitEvent for that platform.
+//
+#define LOG_TAG "EventHub"
+
+//#define LOG_NDEBUG 0
+
+#include <ui/EventHub.h>
+#include <hardware_legacy/power.h>
+
+#include <cutils/properties.h>
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <utils.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "KeyLayoutMap.h"
+
+#include <string.h>
+#include <stdint.h>
+#include <dirent.h>
+#ifdef HAVE_INOTIFY
+# include <sys/inotify.h>
+#endif
+#ifdef HAVE_ANDROID_OS
+# include <sys/limits.h>        /* not part of Linux */
+#endif
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+
+/* this macro is used to tell if "bit" is set in "array"
+ * it selects a byte from the array, and does a boolean AND
+ * operation with a byte that only has the relevant bit set.
+ * eg. to check for the 12th bit, we do (array[1] & 1<<4)
+ */
+#define test_bit(bit, array)    (array[bit/8] & (1<<(bit%8)))
+
+#define ID_MASK  0x0000ffff
+#define SEQ_MASK 0x7fff0000
+#define SEQ_SHIFT 16
+#define id_to_index(id)         ((id&ID_MASK)+1)
+
+namespace android {
+
+static const char *WAKE_LOCK_ID = "KeyEvents";
+static const char *device_path = "/dev/input";
+
+/* return the larger integer */
+static inline int max(int v1, int v2)
+{
+    return (v1 > v2) ? v1 : v2;
+}
+
+EventHub::device_t::device_t(int32_t _id, const char* _path)
+    : id(_id), path(_path), classes(0)
+    , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
+}
+
+EventHub::device_t::~device_t() {
+    delete [] keyBitmask;
+    delete layoutMap;
+}
+
+EventHub::EventHub(void)
+    : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0)
+    , mDevicesById(0), mNumDevicesById(0)
+    , mOpeningDevices(0), mClosingDevices(0)
+    , mDevices(0), mFDs(0), mFDCount(0)
+{
+    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+#ifdef EV_SW
+    memset(mSwitches, 0, sizeof(mSwitches));
+#endif
+}
+
+/*
+ * Clean up.
+ */
+EventHub::~EventHub(void)
+{
+    release_wake_lock(WAKE_LOCK_ID);
+    // we should free stuff here...
+}
+
+void EventHub::onFirstRef()
+{
+    mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
+}
+
+status_t EventHub::errorCheck() const
+{
+    return mError;
+}
+
+String8 EventHub::getDeviceName(int32_t deviceId) const
+{
+    AutoMutex _l(mLock);
+    device_t* device = getDevice(deviceId);
+    if (device == NULL) return String8();
+    return device->name;
+}
+
+uint32_t EventHub::getDeviceClasses(int32_t deviceId) const
+{
+    AutoMutex _l(mLock);
+    device_t* device = getDevice(deviceId);
+    if (device == NULL) return 0;
+    return device->classes;
+}
+
+int EventHub::getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue,
+        int* outMaxValue, int* outFlat, int* outFuzz) const
+{
+    AutoMutex _l(mLock);
+    device_t* device = getDevice(deviceId);
+    if (device == NULL) return -1;
+
+    struct input_absinfo info;
+
+    if(ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGABS(axis), &info)) {
+        LOGE("Error reading absolute controller %d for device %s fd %d\n",
+             axis, device->name.string(), mFDs[id_to_index(device->id)].fd);
+        return -1;
+    }
+    *outMinValue = info.minimum;
+    *outMaxValue = info.maximum;
+    *outFlat = info.flat;
+    *outFuzz = info.fuzz;
+    return 0;
+}
+
+int EventHub::getSwitchState(int sw) const
+{
+#ifdef EV_SW
+    if (sw >= 0 && sw <= SW_MAX) {
+        int32_t devid = mSwitches[sw];
+        if (devid != 0) {
+            return getSwitchState(devid, sw);
+        }
+    }
+#endif
+    return -1;
+}
+
+int EventHub::getSwitchState(int32_t deviceId, int sw) const
+{
+#ifdef EV_SW
+    AutoMutex _l(mLock);
+    device_t* device = getDevice(deviceId);
+    if (device == NULL) return -1;
+    
+    if (sw >= 0 && sw <= SW_MAX) {
+        uint8_t sw_bitmask[(SW_MAX+1)/8];
+        memset(sw_bitmask, 0, sizeof(sw_bitmask));
+        if (ioctl(mFDs[id_to_index(device->id)].fd,
+                   EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
+            return test_bit(sw, sw_bitmask) ? 1 : 0;
+        }
+    }
+#endif
+    
+    return -1;
+}
+
+int EventHub::getScancodeState(int code) const
+{
+    return getScancodeState(mFirstKeyboardId, code);
+}
+
+int EventHub::getScancodeState(int32_t deviceId, int code) const
+{
+    AutoMutex _l(mLock);
+    device_t* device = getDevice(deviceId);
+    if (device == NULL) return -1;
+    
+    if (code >= 0 && code <= KEY_MAX) {
+        uint8_t key_bitmask[(KEY_MAX+1)/8];
+        memset(key_bitmask, 0, sizeof(key_bitmask));
+        if (ioctl(mFDs[id_to_index(device->id)].fd,
+                   EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
+            return test_bit(code, key_bitmask) ? 1 : 0;
+        }
+    }
+    
+    return -1;
+}
+
+int EventHub::getKeycodeState(int code) const
+{
+    return getKeycodeState(mFirstKeyboardId, code);
+}
+
+int EventHub::getKeycodeState(int32_t deviceId, int code) const
+{
+    AutoMutex _l(mLock);
+    device_t* device = getDevice(deviceId);
+    if (device == NULL || device->layoutMap == NULL) return -1;
+    
+    Vector<int32_t> scanCodes;
+    device->layoutMap->findScancodes(code, &scanCodes);
+    
+    uint8_t key_bitmask[(KEY_MAX+1)/8];
+    memset(key_bitmask, 0, sizeof(key_bitmask));
+    if (ioctl(mFDs[id_to_index(device->id)].fd,
+               EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
+        #if 0
+        for (size_t i=0; i<=KEY_MAX; i++) {
+            LOGI("(Scan code %d: down=%d)", i, test_bit(i, key_bitmask));
+        }
+        #endif
+        const size_t N = scanCodes.size();
+        for (size_t i=0; i<N && i<=KEY_MAX; i++) {
+            int32_t sc = scanCodes.itemAt(i);
+            //LOGI("Code %d: down=%d", sc, test_bit(sc, key_bitmask));
+            if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, key_bitmask)) {
+                return 1;
+            }
+        }
+    }
+    
+    return 0;
+}
+
+EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
+{
+    if (deviceId == 0) deviceId = mFirstKeyboardId;
+    int32_t id = deviceId & ID_MASK;
+    if (id >= mNumDevicesById || id < 0) return NULL;
+    device_t* dev = mDevicesById[id].device;
+    if (dev->id == deviceId) {
+        return dev;
+    }
+    return NULL;
+}
+
+bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
+        int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
+        int32_t* outValue, nsecs_t* outWhen)
+{
+    *outDeviceId = 0;
+    *outType = 0;
+    *outScancode = 0;
+    *outKeycode = 0;
+    *outFlags = 0;
+    *outValue = 0;
+    *outWhen = 0;
+
+    status_t err;
+
+    fd_set readfds;
+    int maxFd = -1;
+    int cc;
+    int i;
+    int res;
+    int pollres;
+    struct input_event iev;
+
+    // Note that we only allow one caller to getEvent(), so don't need
+    // to do locking here...  only when adding/removing devices.
+    
+    while(1) {
+
+        // First, report any devices that had last been added/removed.
+        if (mClosingDevices != NULL) {
+            device_t* device = mClosingDevices;
+            LOGV("Reporting device closed: id=0x%x, name=%s\n",
+                 device->id, device->path.string());
+            mClosingDevices = device->next;
+            *outDeviceId = device->id;
+            if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
+            *outType = DEVICE_REMOVED;
+            delete device;
+            return true;
+        }
+        if (mOpeningDevices != NULL) {
+            device_t* device = mOpeningDevices;
+            LOGV("Reporting device opened: id=0x%x, name=%s\n",
+                 device->id, device->path.string());
+            mOpeningDevices = device->next;
+            *outDeviceId = device->id;
+            if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
+            *outType = DEVICE_ADDED;
+            return true;
+        }
+
+        release_wake_lock(WAKE_LOCK_ID);
+
+        pollres = poll(mFDs, mFDCount, -1);
+
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+
+        if (pollres <= 0) {
+            if (errno != EINTR) {
+                LOGW("select failed (errno=%d)\n", errno);
+                usleep(100000);
+            }
+            continue;
+        }
+
+        //printf("poll %d, returned %d\n", mFDCount, pollres);
+
+        // mFDs[0] is used for inotify, so process regular events starting at mFDs[1]
+        for(i = 1; i < mFDCount; i++) {
+            if(mFDs[i].revents) {
+                LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
+                if(mFDs[i].revents & POLLIN) {
+                    res = read(mFDs[i].fd, &iev, sizeof(iev));
+                    if (res == sizeof(iev)) {
+                        LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
+                             mDevices[i]->path.string(),
+                             (int) iev.time.tv_sec, (int) iev.time.tv_usec,
+                             iev.type, iev.code, iev.value);
+                        *outDeviceId = mDevices[i]->id;
+                        if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
+                        *outType = iev.type;
+                        *outScancode = iev.code;
+                        if (iev.type == EV_KEY) {
+                            err = mDevices[i]->layoutMap->map(iev.code, outKeycode, outFlags);
+                            LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d\n",
+                                iev.code, *outKeycode, *outFlags, err);
+                            if (err != 0) {
+                                *outKeycode = 0;
+                                *outFlags = 0;
+                            }
+                        } else {
+                            *outKeycode = iev.code;
+                        }
+                        *outValue = iev.value;
+                        *outWhen = s2ns(iev.time.tv_sec) + us2ns(iev.time.tv_usec);
+                        return true;
+                    } else {
+                        if (res<0) {
+                            LOGW("could not get event (errno=%d)", errno);
+                        } else {
+                            LOGE("could not get event (wrong size: %d)", res);
+                        }
+                        continue;
+                    }
+                }
+            }
+        }
+        
+        // read_notify() will modify mFDs and mFDCount, so this must be done after
+        // processing all other events.
+        if(mFDs[0].revents & POLLIN) {
+            read_notify(mFDs[0].fd);
+        }
+    }
+}
+
+/*
+ * Open the platform-specific input device.
+ */
+bool EventHub::openPlatformInput(void)
+{
+    /*
+     * Open platform-specific input device(s).
+     */
+    int res;
+
+    mFDCount = 1;
+    mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
+    mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
+    mFDs[0].events = POLLIN;
+    mDevices[0] = NULL;
+#ifdef HAVE_INOTIFY
+    mFDs[0].fd = inotify_init();
+    res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
+    if(res < 0) {
+        LOGE("could not add watch for %s, %s\n", device_path, strerror(errno));
+    }
+#else
+    /*
+     * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
+     * We allocate space for it and set it to something invalid.
+     */
+    mFDs[0].fd = -1;
+#endif
+
+    res = scan_dir(device_path);
+    if(res < 0) {
+        LOGE("scan dir failed for %s\n", device_path);
+        //open_device("/dev/input/event0");
+    }
+
+    return true;
+}
+
+/*
+ * Inspect the known devices to determine whether physical keys exist for the given
+ * framework-domain key codes.
+ */
+bool EventHub::hasKeys(size_t numCodes, int32_t* keyCodes, uint8_t* outFlags) {
+    for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
+        outFlags[codeIndex] = 0;
+
+        // check each available hardware device for support for this keycode
+        Vector<int32_t> scanCodes;
+        for (int n = 0; (n < mFDCount) && (outFlags[codeIndex] == 0); n++) {
+            if (mDevices[n]) {
+                status_t err = mDevices[n]->layoutMap->findScancodes(keyCodes[codeIndex], &scanCodes);
+                if (!err) {
+                    // check the possible scan codes identified by the layout map against the
+                    // map of codes actually emitted by the driver
+                    for (size_t sc = 0; sc < scanCodes.size(); sc++) {
+                        if (test_bit(scanCodes[sc], mDevices[n]->keyBitmask)) {
+                            outFlags[codeIndex] = 1;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+// ----------------------------------------------------------------------------
+
+int EventHub::open_device(const char *deviceName)
+{
+    int version;
+    int fd;
+    struct pollfd *new_mFDs;
+    device_t **new_devices;
+    char **new_device_names;
+    char name[80];
+    char location[80];
+    char idstr[80];
+    struct input_id id;
+
+    LOGV("Opening device: %s", deviceName);
+
+    AutoMutex _l(mLock);
+    
+    fd = open(deviceName, O_RDWR);
+    if(fd < 0) {
+        LOGE("could not open %s, %s\n", deviceName, strerror(errno));
+        return -1;
+    }
+
+    if(ioctl(fd, EVIOCGVERSION, &version)) {
+        LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno));
+        return -1;
+    }
+    if(ioctl(fd, EVIOCGID, &id)) {
+        LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno));
+        return -1;
+    }
+    name[sizeof(name) - 1] = '\0';
+    location[sizeof(location) - 1] = '\0';
+    idstr[sizeof(idstr) - 1] = '\0';
+    if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
+        //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
+        name[0] = '\0';
+    }
+    if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
+        //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
+        location[0] = '\0';
+    }
+    if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
+        //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno));
+        idstr[0] = '\0';
+    }
+
+    int devid = 0;
+    while (devid < mNumDevicesById) {
+        if (mDevicesById[devid].device == NULL) {
+            break;
+        }
+        devid++;
+    }
+    if (devid >= mNumDevicesById) {
+        device_ent* new_devids = (device_ent*)realloc(mDevicesById,
+                sizeof(mDevicesById[0]) * (devid + 1));
+        if (new_devids == NULL) {
+            LOGE("out of memory");
+            return -1;
+        }
+        mDevicesById = new_devids;
+        mNumDevicesById = devid+1;
+        mDevicesById[devid].device = NULL;
+        mDevicesById[devid].seq = 0;
+    }
+
+    mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;
+    if (mDevicesById[devid].seq == 0) {
+        mDevicesById[devid].seq = 1<<SEQ_SHIFT;
+    }
+
+    new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
+    new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
+    if (new_mFDs == NULL || new_devices == NULL) {
+        LOGE("out of memory");
+        return -1;
+    }
+    mFDs = new_mFDs;
+    mDevices = new_devices;
+
+#if 0
+    LOGI("add device %d: %s\n", mFDCount, deviceName);
+    LOGI("  bus:      %04x\n"
+         "  vendor    %04x\n"
+         "  product   %04x\n"
+         "  version   %04x\n",
+        id.bustype, id.vendor, id.product, id.version);
+    LOGI("  name:     \"%s\"\n", name);
+    LOGI("  location: \"%s\"\n"
+         "  id:       \"%s\"\n", location, idstr);
+    LOGI("  version:  %d.%d.%d\n",
+        version >> 16, (version >> 8) & 0xff, version & 0xff);
+#endif
+
+    device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName);
+    if (device == NULL) {
+        LOGE("out of memory");
+        return -1;
+    }
+
+    mFDs[mFDCount].fd = fd;
+    mFDs[mFDCount].events = POLLIN;
+
+    // figure out the kinds of events the device reports
+    uint8_t key_bitmask[(KEY_MAX+1)/8];
+    memset(key_bitmask, 0, sizeof(key_bitmask));
+    LOGV("Getting keys...");
+    if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
+        //LOGI("MAP\n");
+        //for (int i=0; i<((KEY_MAX+1)/8); i++) {
+        //    LOGI("%d: 0x%02x\n", i, key_bitmask[i]);
+        //}
+        for (int i=0; i<((BTN_MISC+7)/8); i++) {
+            if (key_bitmask[i] != 0) {
+                device->classes |= CLASS_KEYBOARD;
+                // 'Q' key support = cheap test of whether this is an alpha-capable kbd
+                if (test_bit(KEY_Q, key_bitmask)) {
+                    device->classes |= CLASS_ALPHAKEY;
+                }
+                break;
+            }
+        }
+        if ((device->classes & CLASS_KEYBOARD) != 0) {
+            device->keyBitmask = new uint8_t[(KEY_MAX+1)/8];
+            if (device->keyBitmask != NULL) {
+                memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
+            } else {
+                delete device;
+                LOGE("out of memory allocating key bitmask");
+                return -1;
+            }
+        }
+    }
+    if (test_bit(BTN_MOUSE, key_bitmask)) {
+        uint8_t rel_bitmask[(REL_MAX+1)/8];
+        memset(rel_bitmask, 0, sizeof(rel_bitmask));
+        LOGV("Getting relative controllers...");
+        if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0)
+        {
+            if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
+                device->classes |= CLASS_TRACKBALL;
+            }
+        }
+    }
+    if (test_bit(BTN_TOUCH, key_bitmask)) {
+        uint8_t abs_bitmask[(ABS_MAX+1)/8];
+        memset(abs_bitmask, 0, sizeof(abs_bitmask));
+        LOGV("Getting absolute controllers...");
+        if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0)
+        {
+            if (test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
+                device->classes |= CLASS_TOUCHSCREEN;
+            }
+        }
+    }
+
+#ifdef EV_SW
+    // figure out the switches this device reports
+    uint8_t sw_bitmask[(SW_MAX+1)/8];
+    memset(sw_bitmask, 0, sizeof(sw_bitmask));
+    if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
+        for (int i=0; i<EV_SW; i++) {
+            //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
+            if (test_bit(i, sw_bitmask)) {
+                if (mSwitches[i] == 0) {
+                    mSwitches[i] = device->id;
+                }
+            }
+        }
+    }
+#endif
+
+    LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
+         deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
+
+    if ((device->classes&CLASS_KEYBOARD) != 0) {
+        char devname[101];
+        char tmpfn[101];
+        char keylayoutFilename[300];
+
+        // a more descriptive name
+        ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);
+        devname[sizeof(devname)-1] = 0;
+        device->name = devname;
+
+        // replace all the spaces with underscores
+        strcpy(tmpfn, devname);
+        for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
+            *p = '_';
+
+        // find the .kl file we need for this device
+        const char* root = getenv("ANDROID_ROOT");
+        snprintf(keylayoutFilename, sizeof(keylayoutFilename),
+                 "%s/usr/keylayout/%s.kl", root, tmpfn);
+        bool defaultKeymap = false;
+        if (access(keylayoutFilename, R_OK)) {
+            snprintf(keylayoutFilename, sizeof(keylayoutFilename),
+                     "%s/usr/keylayout/%s", root, "qwerty.kl");
+            defaultKeymap = true;
+        }
+        device->layoutMap->load(keylayoutFilename);
+
+        // tell the world about the devname (the descriptive name)
+        int32_t publicID;
+        if (!mHaveFirstKeyboard && !defaultKeymap) {
+            publicID = 0;
+            // the built-in keyboard has a well-known device ID of 0,
+            // this device better not go away.
+            mHaveFirstKeyboard = true;
+            mFirstKeyboardId = device->id;
+        } else {
+            publicID = device->id;
+            // ensure mFirstKeyboardId is set to -something-.
+            if (mFirstKeyboardId == 0) {
+                mFirstKeyboardId = device->id;
+            }
+        }
+        char propName[100];
+        sprintf(propName, "hw.keyboards.%u.devname", publicID);
+        property_set(propName, devname);
+
+        LOGI("New keyboard: publicID=%d device->id=%d devname='%s' propName='%s' keylayout='%s'\n",
+                publicID, device->id, devname, propName, keylayoutFilename);
+    }
+
+    LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
+         deviceName, device, mFDCount, devid, device->classes);
+
+    mDevicesById[devid].device = device;
+    device->next = mOpeningDevices;
+    mOpeningDevices = device;
+    mDevices[mFDCount] = device;
+
+    mFDCount++;
+    return 0;
+}
+
+int EventHub::close_device(const char *deviceName)
+{
+    AutoMutex _l(mLock);
+    
+    int i;
+    for(i = 1; i < mFDCount; i++) {
+        if(strcmp(mDevices[i]->path.string(), deviceName) == 0) {
+            //LOGD("remove device %d: %s\n", i, deviceName);
+            device_t* device = mDevices[i];
+            int count = mFDCount - i - 1;
+            int index = (device->id&ID_MASK);
+            mDevicesById[index].device = NULL;
+            memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
+            memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
+
+#ifdef EV_SW
+            for (int j=0; j<EV_SW; j++) {
+                if (mSwitches[j] == device->id) {
+                    mSwitches[j] = 0;
+                }
+            }
+#endif
+            
+            device->next = mClosingDevices;
+            mClosingDevices = device;
+
+            mFDCount--;
+
+            uint32_t publicID;
+            if (device->id == mFirstKeyboardId) {
+                LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
+                        device->path.string(), mFirstKeyboardId);
+                mFirstKeyboardId = 0;
+                publicID = 0;
+            } else {
+                publicID = device->id;
+            }
+            // clear the property
+            char propName[100];
+            sprintf(propName, "hw.keyboards.%u.devname", publicID);
+            property_set(propName, NULL);
+            return 0;
+        }
+    }
+    LOGE("remote device: %s not found\n", deviceName);
+    return -1;
+}
+
+int EventHub::read_notify(int nfd)
+{
+#ifdef HAVE_INOTIFY
+    int res;
+    char devname[PATH_MAX];
+    char *filename;
+    char event_buf[512];
+    int event_size;
+    int event_pos = 0;
+    struct inotify_event *event;
+
+    res = read(nfd, event_buf, sizeof(event_buf));
+    if(res < (int)sizeof(*event)) {
+        if(errno == EINTR)
+            return 0;
+        LOGW("could not get event, %s\n", strerror(errno));
+        return 1;
+    }
+    //printf("got %d bytes of event information\n", res);
+
+    strcpy(devname, device_path);
+    filename = devname + strlen(devname);
+    *filename++ = '/';
+
+    while(res >= (int)sizeof(*event)) {
+        event = (struct inotify_event *)(event_buf + event_pos);
+        //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
+        if(event->len) {
+            strcpy(filename, event->name);
+            if(event->mask & IN_CREATE) {
+                open_device(devname);
+            }
+            else {
+                close_device(devname);
+            }
+        }
+        event_size = sizeof(*event) + event->len;
+        res -= event_size;
+        event_pos += event_size;
+    }
+#endif
+    return 0;
+}
+
+
+int EventHub::scan_dir(const char *dirname)
+{
+    char devname[PATH_MAX];
+    char *filename;
+    DIR *dir;
+    struct dirent *de;
+    dir = opendir(dirname);
+    if(dir == NULL)
+        return -1;
+    strcpy(devname, dirname);
+    filename = devname + strlen(devname);
+    *filename++ = '/';
+    while((de = readdir(dir))) {
+        if(de->d_name[0] == '.' &&
+           (de->d_name[1] == '\0' ||
+            (de->d_name[1] == '.' && de->d_name[2] == '\0')))
+            continue;
+        strcpy(filename, de->d_name);
+        open_device(devname);
+    }
+    closedir(dir);
+    return 0;
+}
+
+}; // namespace android
diff --git a/libs/ui/EventRecurrence.cpp b/libs/ui/EventRecurrence.cpp
new file mode 100644
index 0000000..b436b50
--- /dev/null
+++ b/libs/ui/EventRecurrence.cpp
@@ -0,0 +1,484 @@
+/*
+ *  Copyright 2006 The Android Open Source Project
+ */
+
+#include <pim/EventRecurrence.h>
+#include <utils/String8.h>
+#include <stdio.h>
+#include <limits.h>
+
+namespace android {
+
+#define FAIL_HERE() do { \
+            printf("Parsing failed at line %d\n", __LINE__); \
+            return UNKNOWN_ERROR; \
+        } while(0)
+
+EventRecurrence::EventRecurrence()
+    :freq((freq_t)0),
+     until(),
+     count(0),
+     interval(0),
+     bysecond(0),
+     bysecondCount(0),
+     byminute(0),
+     byminuteCount(0),
+     byhour(0),
+     byhourCount(0),
+     byday(0),
+     bydayNum(0),
+     bydayCount(0),
+     bymonthday(0),
+     bymonthdayCount(0),
+     byyearday(0),
+     byyeardayCount(0),
+     byweekno(0),
+     byweeknoCount(0),
+     bymonth(0),
+     bymonthCount(0),
+     bysetpos(0),
+     bysetposCount(0),
+     wkst(0)
+{
+}
+
+EventRecurrence::~EventRecurrence()
+{
+    delete[] bysecond;
+    delete[] byminute;
+    delete[] byhour;
+    delete[] byday;
+    delete[] bydayNum;
+    delete[] byyearday;
+    delete[] bymonthday;
+    delete[] byweekno;
+    delete[] bymonth;
+    delete[] bysetpos;
+}
+
+enum LHS {
+    NONE_LHS = 0,
+    FREQ,
+    UNTIL,
+    COUNT,
+    INTERVAL,
+    BYSECOND,
+    BYMINUTE,
+    BYHOUR,
+    BYDAY,
+    BYMONTHDAY,
+    BYYEARDAY,
+    BYWEEKNO,
+    BYMONTH,
+    BYSETPOS,
+    WKST
+};
+
+struct LHSProc
+{
+    const char16_t* text;
+    size_t textSize;
+    uint32_t value;
+};
+
+const char16_t FREQ_text[] = { 'F', 'R', 'E', 'Q' };
+const char16_t UNTIL_text[] = { 'U', 'N', 'T', 'I', 'L' };
+const char16_t COUNT_text[] = { 'C', 'O', 'U', 'N', 'T' };
+const char16_t INTERVAL_text[] = { 'I', 'N', 'T', 'E', 'R', 'V', 'A', 'L'};
+const char16_t BYSECOND_text[] = { 'B', 'Y', 'S', 'E', 'C', 'O', 'N', 'D' };
+const char16_t BYMINUTE_text[] = { 'B', 'Y', 'M', 'I', 'N', 'U', 'T', 'E' };
+const char16_t BYHOUR_text[] = { 'B', 'Y', 'H', 'O', 'U', 'R' };
+const char16_t BYDAY_text[] = { 'B', 'Y', 'D', 'A', 'Y' };
+const char16_t BYMONTHDAY_text[] = { 'B','Y','M','O','N','T','H','D','A','Y' };
+const char16_t BYYEARDAY_text[] = { 'B','Y','Y','E','A','R','D','A','Y' };
+const char16_t BYWEEKNO_text[] = { 'B', 'Y', 'W', 'E', 'E', 'K', 'N', 'O' };
+const char16_t BYMONTH_text[] = { 'B', 'Y', 'M', 'O', 'N', 'T', 'H' };
+const char16_t BYSETPOS_text[] = { 'B', 'Y', 'S', 'E', 'T', 'P', 'O', 'S' };
+const char16_t WKST_text[] = { 'W', 'K', 'S', 'T' };
+
+#define SIZ(x) (sizeof(x)/sizeof(x[0]))
+
+const LHSProc LHSPROC[] = {
+    { FREQ_text, SIZ(FREQ_text), FREQ },
+    { UNTIL_text, SIZ(UNTIL_text), UNTIL },
+    { COUNT_text, SIZ(COUNT_text), COUNT },
+    { INTERVAL_text, SIZ(INTERVAL_text), INTERVAL },
+    { BYSECOND_text, SIZ(BYSECOND_text), BYSECOND },
+    { BYMINUTE_text, SIZ(BYMINUTE_text), BYMINUTE },
+    { BYHOUR_text, SIZ(BYHOUR_text), BYHOUR },
+    { BYDAY_text, SIZ(BYDAY_text), BYDAY },
+    { BYMONTHDAY_text, SIZ(BYMONTHDAY_text), BYMONTHDAY },
+    { BYYEARDAY_text, SIZ(BYYEARDAY_text), BYYEARDAY },
+    { BYWEEKNO_text, SIZ(BYWEEKNO_text), BYWEEKNO },
+    { BYMONTH_text, SIZ(BYMONTH_text), BYMONTH },
+    { BYSETPOS_text, SIZ(BYSETPOS_text), BYSETPOS },
+    { WKST_text, SIZ(WKST_text), WKST },
+    { NULL, 0, NONE_LHS },
+};
+
+const char16_t SECONDLY_text[] = { 'S','E','C','O','N','D','L','Y' };
+const char16_t MINUTELY_text[] = { 'M','I','N','U','T','E','L','Y' };
+const char16_t HOURLY_text[] = { 'H','O','U','R','L','Y' };
+const char16_t DAILY_text[] = { 'D','A','I','L','Y' };
+const char16_t WEEKLY_text[] = { 'W','E','E','K','L','Y' };
+const char16_t MONTHLY_text[] = { 'M','O','N','T','H','L','Y' };
+const char16_t YEARLY_text[] = { 'Y','E','A','R','L','Y' };
+
+typedef LHSProc FreqProc;
+
+const FreqProc FREQPROC[] = {
+    { SECONDLY_text, SIZ(SECONDLY_text), EventRecurrence::SECONDLY },
+    { MINUTELY_text, SIZ(MINUTELY_text), EventRecurrence::MINUTELY },
+    { HOURLY_text, SIZ(HOURLY_text), EventRecurrence::HOURLY },
+    { DAILY_text, SIZ(DAILY_text), EventRecurrence::DAILY },
+    { WEEKLY_text, SIZ(WEEKLY_text), EventRecurrence::WEEKLY },
+    { MONTHLY_text, SIZ(MONTHLY_text), EventRecurrence::MONTHLY },
+    { YEARLY_text, SIZ(YEARLY_text), EventRecurrence::YEARLY },
+    { NULL, 0, NONE_LHS },
+};
+
+const char16_t SU_text[] = { 'S','U' };
+const char16_t MO_text[] = { 'M','O' };
+const char16_t TU_text[] = { 'T','U' };
+const char16_t WE_text[] = { 'W','E' };
+const char16_t TH_text[] = { 'T','H' };
+const char16_t FR_text[] = { 'F','R' };
+const char16_t SA_text[] = { 'S','A' };
+
+const FreqProc WEEKDAYPROC[] = {
+    { SU_text, SIZ(SU_text), EventRecurrence::SU },
+    { MO_text, SIZ(MO_text), EventRecurrence::MO },
+    { TU_text, SIZ(TU_text), EventRecurrence::TU },
+    { WE_text, SIZ(WE_text), EventRecurrence::WE },
+    { TH_text, SIZ(TH_text), EventRecurrence::TH },
+    { FR_text, SIZ(FR_text), EventRecurrence::FR },
+    { SA_text, SIZ(SA_text), EventRecurrence::SA },
+    { NULL, 0, NONE_LHS },
+};
+
+// returns the index into LHSPROC for the match or -1 if not found
+inline static int
+match_proc(const LHSProc* p, const char16_t* str, size_t len)
+{
+    int i = 0;
+    while (p->text != NULL) {
+        if (p->textSize == len) {
+            if (0 == memcmp(p->text, str, len*sizeof(char16_t))) {
+                return i;
+            }
+        }
+        p++;
+        i++;
+    }
+    return -1;
+}
+
+// rangeMin and rangeMax are inclusive
+static status_t
+parse_int(const char16_t* str, size_t len, int* out,
+            int rangeMin, int rangeMax, bool zeroOK)
+{
+    char16_t c;
+    size_t i=0;
+
+    if (len == 0) {
+        FAIL_HERE();
+    }
+    bool negative = false;
+    c = str[0];
+    if (c == '-' ) {
+        negative = true;
+        i++;
+    }
+    else if (c == '+') {
+        i++;
+    }
+    int n = 0;
+    for (; i<len; i++) {
+        c = str[i];
+        if (c < '0' || c > '9') {
+            FAIL_HERE();
+        }
+        int prev = n;
+        n *= 10;
+        // the spec doesn't address how big these numbers can be,
+        // so we're not going to worry about not being able to represent
+        // INT_MIN, and if we're going to wrap, we'll just clamp to
+        // INT_MAX instead
+        if (n < prev) {
+            n = INT_MAX;
+        } else {
+            n += c - '0';
+        }
+    }
+    if (negative) {
+        n = -n;
+    }
+    if (n < rangeMin || n > rangeMax) {
+        FAIL_HERE();
+    }
+    if (!zeroOK && n == 0) {
+        FAIL_HERE();
+    }
+    *out = n;
+    return NO_ERROR;
+}
+
+static status_t
+parse_int_list(const char16_t* str, size_t len, int* countOut, int** listOut,
+          int rangeMin, int rangeMax, bool zeroOK,
+          status_t (*func)(const char16_t*,size_t,int*,int,int,bool)=parse_int)
+{
+    status_t err;
+
+    if (len == 0) {
+        *countOut = 0;
+        *listOut = NULL;
+        return NO_ERROR;
+    }
+
+    // make one pass through looking for commas so we know how big to make our
+    // out array.
+    int count = 1;
+    for (size_t i=0; i<len; i++) {
+        if (str[i] == ',') {
+            count++;
+        }
+    }
+
+    int* list = new int[count];
+    const char16_t* p = str;
+    int commaIndex = 0;
+    size_t i;
+
+    for (i=0; i<len; i++) {
+        if (str[i] == ',') {
+            err = func(p, (str+i-p), list+commaIndex, rangeMin,
+                    rangeMax, zeroOK);
+            if (err != NO_ERROR) {
+                goto bail;
+            }
+            commaIndex++;
+            p = str+i+1;
+        }
+    }
+
+    err = func(p, (str+i-p), list+commaIndex, rangeMin, rangeMax, zeroOK);
+    if (err != NO_ERROR) {
+        goto bail;
+    }
+    commaIndex++;
+
+    *countOut = count;
+    *listOut = list;
+
+    return NO_ERROR;
+
+bail:
+    delete[] list;
+    FAIL_HERE();
+}
+
+// the numbers here are small, so we pack them both into one value, and then
+// split it out later.  it lets us reuse all the comma separated list code.
+static status_t
+parse_byday(const char16_t* s, size_t len, int* out,
+            int rangeMin, int rangeMax, bool zeroOK)
+{
+    status_t err;
+    int n = 0;
+    const char16_t* p = s;
+    size_t plen = len;
+
+    if (len > 0) {
+        char16_t c = s[0];
+        if (c == '-' || c == '+' || (c >= '0' && c <= '9')) {
+            if (len > 1) {
+                size_t nlen = 0;
+                c = s[nlen];
+                while (nlen < len
+                        && (c == '-' || c == '+' || (c >= '0' && c <= '9'))) {
+                    c = s[nlen];
+                    nlen++;
+                }
+                if (nlen > 0) {
+                    nlen--;
+                    err = parse_int(s, nlen, &n, rangeMin, rangeMax, zeroOK);
+                    if (err != NO_ERROR) {
+                        FAIL_HERE();
+                    }
+                    p += nlen;
+                    plen -= nlen;
+                }
+            }
+        }
+
+        int index = match_proc(WEEKDAYPROC, p, plen);
+        if (index >= 0) {
+            *out = (0xffff0000 & WEEKDAYPROC[index].value)
+                    | (0x0000ffff & n);
+            return NO_ERROR;
+        }
+    }
+    return UNKNOWN_ERROR;
+}
+
+static void
+postprocess_byday(int count, int* byday, int** bydayNum)
+{
+    int* bdn = new int[count];
+    *bydayNum = bdn;
+    for (int i=0; i<count; i++) {
+        uint32_t v = byday[i];
+        int16_t num = v & 0x0000ffff;
+        byday[i] = v & 0xffff0000;  
+        // will sign extend:
+        bdn[i] = num;
+    }
+}
+
+#define PARSE_INT_LIST_CHECKED(name, rangeMin, rangeMax, zeroOK) \
+    if (name##Count != 0 || NO_ERROR != parse_int_list(s, slen, \
+                         &name##Count, &name, rangeMin, rangeMax, zeroOK)) { \
+        FAIL_HERE(); \
+    }
+status_t
+EventRecurrence::parse(const String16& str)
+{
+    char16_t const* work = str.string();
+    size_t len = str.size();
+
+    int lhsIndex = NONE_LHS;
+    int index;
+    
+    size_t start = 0;
+    for (size_t i=0; i<len; i++) {
+        char16_t c = work[i];
+        if (c != ';' && i == len-1) {
+            c = ';';
+            i++;
+        }
+        if (c == ';' || c == '=') {
+            if (i != start) {
+                const char16_t* s = work+start;
+                const size_t slen = i-start;
+
+                String8 thestring(String16(s, slen));
+
+                switch (c)
+                {
+                    case '=':
+                        if (lhsIndex == NONE_LHS) {
+                            lhsIndex = match_proc(LHSPROC, s, slen);
+                            if (lhsIndex >= 0) {
+                                break;
+                            }
+                        }
+                        FAIL_HERE();
+                    case ';':
+                    {
+                        switch (LHSPROC[lhsIndex].value)
+                        {
+                            case FREQ:
+                                if (this->freq != 0) {
+                                    FAIL_HERE();
+                                }
+                                index = match_proc(FREQPROC, s, slen);
+                                if (index >= 0) {
+                                    this->freq = (freq_t)FREQPROC[index].value;
+                                }
+                                break;
+                            case UNTIL:
+                                // XXX should check that this is a valid time
+                                until.setTo(String16(s, slen));
+                                break;
+                            case COUNT:
+                                if (count != 0
+                                     || NO_ERROR != parse_int(s, slen,
+                                             &count, INT_MIN, INT_MAX, true)) {
+                                    FAIL_HERE();
+                                }
+                                break;
+                            case INTERVAL:
+                                if (interval != 0
+                                     || NO_ERROR != parse_int(s, slen,
+                                         &interval, INT_MIN, INT_MAX, false)) {
+                                    FAIL_HERE();
+                                }
+                                break;
+                            case BYSECOND:
+                                PARSE_INT_LIST_CHECKED(bysecond, 0, 59, true)
+                                break;
+                            case BYMINUTE:
+                                PARSE_INT_LIST_CHECKED(byminute, 0, 59, true)
+                                break;
+                            case BYHOUR:
+                                PARSE_INT_LIST_CHECKED(byhour, 0, 23, true)
+                                break;
+                            case BYDAY:
+                                if (bydayCount != 0 || NO_ERROR != 
+                                        parse_int_list(s, slen, &bydayCount,
+                                              &byday, -53, 53, false,
+                                              parse_byday)) {
+                                    FAIL_HERE();
+                                }
+                                postprocess_byday(bydayCount, byday, &bydayNum);
+                                break;
+                            case BYMONTHDAY:
+                                PARSE_INT_LIST_CHECKED(bymonthday, -31, 31,
+                                                        false)
+                                break;
+                            case BYYEARDAY:
+                                PARSE_INT_LIST_CHECKED(byyearday, -366, 366,
+                                                        false)
+                                break;
+                            case BYWEEKNO:
+                                PARSE_INT_LIST_CHECKED(byweekno, -53, 53,
+                                                        false)
+                                break;
+                            case BYMONTH:
+                                PARSE_INT_LIST_CHECKED(bymonth, 1, 12, false)
+                                break;
+                            case BYSETPOS:
+                                PARSE_INT_LIST_CHECKED(bysetpos,
+                                                        INT_MIN, INT_MAX, true)
+                                break;
+                            case WKST:
+                                if (this->wkst != 0) {
+                                    FAIL_HERE();
+                                }
+                                index = match_proc(WEEKDAYPROC, s, slen);
+                                if (index >= 0) {
+                                    this->wkst = (int)WEEKDAYPROC[index].value;
+                                }
+                                break;
+                            default:
+                                FAIL_HERE();
+                        }
+                        lhsIndex = NONE_LHS;
+                        break;
+                    }
+                }
+
+                start = i+1;
+            }
+        }
+    }
+
+    // enforce that there was a FREQ
+    if (freq == 0) {
+        FAIL_HERE();
+    }
+
+    // default wkst to MO if it wasn't specified
+    if (wkst == 0) {
+        wkst = MO;
+    }
+
+    return NO_ERROR;
+}
+
+
+}; // namespace android
+
+
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
new file mode 100644
index 0000000..ab0fef1
--- /dev/null
+++ b/libs/ui/ICamera.cpp
@@ -0,0 +1,346 @@
+/*
+**
+** Copyright 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ICamera"
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Parcel.h>
+#include <ui/ICamera.h>
+
+namespace android {
+
+enum {
+    DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+    SET_PREVIEW_DISPLAY,
+    SET_PREVIEW_CALLBACK_FLAG,
+    START_PREVIEW,
+    STOP_PREVIEW,
+    AUTO_FOCUS,
+    TAKE_PICTURE,
+    SET_PARAMETERS,
+    GET_PARAMETERS,
+    CONNECT,
+    LOCK,
+    UNLOCK,
+    PREVIEW_ENABLED,
+    START_RECORDING,
+    STOP_RECORDING,
+    RECORDING_ENABLED,
+    RELEASE_RECORDING_FRAME,
+};
+
+class BpCamera: public BpInterface<ICamera>
+{
+public:
+    BpCamera(const sp<IBinder>& impl)
+        : BpInterface<ICamera>(impl)
+    {
+    }
+
+    // disconnect from camera service
+    void disconnect()
+    {
+        LOGV("disconnect");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(DISCONNECT, data, &reply);
+    }
+
+    // pass the buffered ISurface to the camera service
+    status_t setPreviewDisplay(const sp<ISurface>& surface)
+    {
+        LOGV("setPreviewDisplay");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        data.writeStrongBinder(surface->asBinder());
+        remote()->transact(SET_PREVIEW_DISPLAY, data, &reply);
+        return reply.readInt32();
+    }
+
+    // set the preview callback flag to affect how the received frames from
+    // preview are handled. See Camera.h for details.
+    void setPreviewCallbackFlag(int flag)
+    {
+        LOGV("setPreviewCallbackFlag(%d)", flag);
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        data.writeInt32(flag);
+        remote()->transact(SET_PREVIEW_CALLBACK_FLAG, data, &reply);
+    }
+
+    // start preview mode, must call setPreviewDisplay first
+    status_t startPreview()
+    {
+        LOGV("startPreview");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(START_PREVIEW, data, &reply);
+        return reply.readInt32();
+    }
+
+    // start recording mode, must call setPreviewDisplay first
+    status_t startRecording()
+    {
+        LOGV("startRecording");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(START_RECORDING, data, &reply);
+        return reply.readInt32();
+    }
+
+    // stop preview mode
+    void stopPreview()
+    {
+        LOGV("stopPreview");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(STOP_PREVIEW, data, &reply);
+    }
+
+    // stop recording mode
+    void stopRecording()
+    {
+        LOGV("stopRecording");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(STOP_RECORDING, data, &reply);
+    }
+
+    void releaseRecordingFrame(const sp<IMemory>& mem)
+    {
+        LOGV("releaseRecordingFrame");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        data.writeStrongBinder(mem->asBinder());
+        remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
+    }
+
+    // check preview state
+    bool previewEnabled()
+    {
+        LOGV("previewEnabled");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(PREVIEW_ENABLED, data, &reply);
+        return reply.readInt32();
+    }
+
+    // check recording state
+    bool recordingEnabled()
+    {
+        LOGV("recordingEnabled");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(RECORDING_ENABLED, data, &reply);
+        return reply.readInt32();
+    }
+
+    // auto focus
+    status_t autoFocus()
+    {
+        LOGV("autoFocus");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(AUTO_FOCUS, data, &reply);
+        status_t ret = reply.readInt32();
+        return ret;
+    }
+
+    // take a picture - returns an IMemory (ref-counted mmap)
+    status_t takePicture()
+    {
+        LOGV("takePicture");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(TAKE_PICTURE, data, &reply);
+        status_t ret = reply.readInt32();
+        return ret;
+    }
+
+    // set preview/capture parameters - key/value pairs
+    status_t setParameters(const String8& params)
+    {
+        LOGV("setParameters");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        data.writeString8(params);
+        remote()->transact(SET_PARAMETERS, data, &reply);
+        return reply.readInt32();
+    }
+
+    // get preview/capture parameters - key/value pairs
+    String8 getParameters() const
+    {
+        LOGV("getParameters");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(GET_PARAMETERS, data, &reply);
+        return reply.readString8();
+    }
+    virtual status_t connect(const sp<ICameraClient>& cameraClient)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        data.writeStrongBinder(cameraClient->asBinder());
+        remote()->transact(CONNECT, data, &reply);
+        return reply.readInt32();
+    }
+    virtual status_t lock()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(LOCK, data, &reply);
+        return reply.readInt32();
+    }
+    virtual status_t unlock()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(UNLOCK, data, &reply);
+        return reply.readInt32();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnCamera::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case DISCONNECT: {
+            LOGV("DISCONNECT");
+            CHECK_INTERFACE(ICamera, data, reply);
+            disconnect();
+            return NO_ERROR;
+        } break;
+        case SET_PREVIEW_DISPLAY: {
+            LOGV("SET_PREVIEW_DISPLAY");
+            CHECK_INTERFACE(ICamera, data, reply);
+            sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+            reply->writeInt32(setPreviewDisplay(surface));
+            return NO_ERROR;
+        } break;
+        case SET_PREVIEW_CALLBACK_FLAG: {
+            LOGV("SET_PREVIEW_CALLBACK_TYPE");
+            CHECK_INTERFACE(ICamera, data, reply);
+            int callback_flag = data.readInt32();
+            setPreviewCallbackFlag(callback_flag);
+            return NO_ERROR;
+        } break;
+        case START_PREVIEW: {
+            LOGV("START_PREVIEW");
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(startPreview());
+            return NO_ERROR;
+        } break;
+        case START_RECORDING: {
+            LOGV("START_RECORDING");
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(startRecording());
+            return NO_ERROR;
+        } break;
+        case STOP_PREVIEW: {
+            LOGV("STOP_PREVIEW");
+            CHECK_INTERFACE(ICamera, data, reply);
+            stopPreview();
+            return NO_ERROR;
+        } break;
+        case STOP_RECORDING: {
+            LOGV("STOP_RECORDING");
+            CHECK_INTERFACE(ICamera, data, reply);
+            stopRecording();
+            return NO_ERROR;
+        } break;
+        case RELEASE_RECORDING_FRAME: {
+            LOGV("RELEASE_RECORDING_FRAME");
+            CHECK_INTERFACE(ICamera, data, reply);
+            sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder());
+            releaseRecordingFrame(mem);
+            return NO_ERROR;
+        } break;
+        case PREVIEW_ENABLED: {
+            LOGV("PREVIEW_ENABLED");
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(previewEnabled());
+            return NO_ERROR;
+        } break;
+        case RECORDING_ENABLED: {
+            LOGV("RECORDING_ENABLED");
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(recordingEnabled());
+            return NO_ERROR;
+        } break;
+        case AUTO_FOCUS: {
+            LOGV("AUTO_FOCUS");
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(autoFocus());
+            return NO_ERROR;
+        } break;
+        case TAKE_PICTURE: {
+            LOGV("TAKE_PICTURE");
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(takePicture());
+            return NO_ERROR;
+        } break;
+        case SET_PARAMETERS: {
+            LOGV("SET_PARAMETERS");
+            CHECK_INTERFACE(ICamera, data, reply);
+            String8 params(data.readString8());
+            reply->writeInt32(setParameters(params));
+            return NO_ERROR;
+         } break;
+        case GET_PARAMETERS: {
+            LOGV("GET_PARAMETERS");
+            CHECK_INTERFACE(ICamera, data, reply);
+             reply->writeString8(getParameters());
+            return NO_ERROR;
+         } break;
+        case CONNECT: {
+            CHECK_INTERFACE(ICamera, data, reply);
+            sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
+            reply->writeInt32(connect(cameraClient));
+            return NO_ERROR;
+        } break;
+        case LOCK: {
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(lock());
+            return NO_ERROR;
+        } break;
+        case UNLOCK: {
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(unlock());
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
new file mode 100644
index 0000000..4bec9d2
--- /dev/null
+++ b/libs/ui/ICameraClient.cpp
@@ -0,0 +1,185 @@
+/*
+**
+** Copyright 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ICameraClient"
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <ui/ICameraClient.h>
+
+namespace android {
+
+enum {
+    SHUTTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
+    RAW_CALLBACK,
+    JPEG_CALLBACK,
+    PREVIEW_CALLBACK,
+    ERROR_CALLBACK,
+    AUTOFOCUS_CALLBACK,
+    RECORDING_CALLBACK,
+};
+
+class BpCameraClient: public BpInterface<ICameraClient>
+{
+public:
+    BpCameraClient(const sp<IBinder>& impl)
+        : BpInterface<ICameraClient>(impl)
+    {
+    }
+
+    // callback to let the app know the shutter has closed, ideal for playing the shutter sound
+    void shutterCallback()
+    {
+        LOGV("shutterCallback");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+        remote()->transact(SHUTTER_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    // callback from camera service to app with picture data
+    void rawCallback(const sp<IMemory>& picture)
+    {
+        LOGV("rawCallback");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+        data.writeStrongBinder(picture->asBinder());
+        remote()->transact(RAW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    // callback from camera service to app with picture data
+    void jpegCallback(const sp<IMemory>& picture)
+    {
+        LOGV("jpegCallback");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+        data.writeStrongBinder(picture->asBinder());
+        remote()->transact(JPEG_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    // callback from camera service to app with preview frame data
+    void previewCallback(const sp<IMemory>& frame)
+    {
+        LOGV("previewCallback");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+        data.writeStrongBinder(frame->asBinder());
+        remote()->transact(PREVIEW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    // callback from camera service to app with recording frame data
+    void recordingCallback(const sp<IMemory>& frame)
+    {
+        LOGV("recordingCallback");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+        data.writeStrongBinder(frame->asBinder());
+        remote()->transact(RECORDING_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    // callback from camera service to app to report error
+    void errorCallback(status_t error)
+    {
+        LOGV("errorCallback");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+        data.writeInt32(error);
+        remote()->transact(ERROR_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    // callback from camera service to app to report autofocus completion
+    void autoFocusCallback(bool focused)
+    {
+        LOGV("autoFocusCallback");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+        data.writeInt32(focused);
+        remote()->transact(AUTOFOCUS_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnCameraClient::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case SHUTTER_CALLBACK: {
+            LOGV("SHUTTER_CALLBACK");
+            CHECK_INTERFACE(ICameraClient, data, reply);
+            shutterCallback();
+            return NO_ERROR;
+        } break;
+        case RAW_CALLBACK: {
+            LOGV("RAW_CALLBACK");
+            CHECK_INTERFACE(ICameraClient, data, reply);
+            sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder());
+            rawCallback(picture);
+            return NO_ERROR;
+        } break;
+        case JPEG_CALLBACK: {
+            LOGV("JPEG_CALLBACK");
+            CHECK_INTERFACE(ICameraClient, data, reply);
+            sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder());
+            jpegCallback(picture);
+            return NO_ERROR;
+        } break;
+        case PREVIEW_CALLBACK: {
+            LOGV("PREVIEW_CALLBACK");
+            CHECK_INTERFACE(ICameraClient, data, reply);
+            sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
+            previewCallback(frame);
+            return NO_ERROR;
+        } break;
+        case RECORDING_CALLBACK: {
+            LOGV("RECORDING_CALLBACK");
+            CHECK_INTERFACE(ICameraClient, data, reply);
+            sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
+            recordingCallback(frame);
+            return NO_ERROR;
+        } break;
+        case ERROR_CALLBACK: {
+            LOGV("ERROR_CALLBACK");
+            CHECK_INTERFACE(ICameraClient, data, reply);
+            status_t error = data.readInt32();
+            errorCallback(error);
+            return NO_ERROR;
+        } break;
+        case AUTOFOCUS_CALLBACK: {
+            LOGV("AUTOFOCUS_CALLBACK");
+            CHECK_INTERFACE(ICameraClient, data, reply);
+            bool focused = (bool)data.readInt32();
+            autoFocusCallback(focused);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/libs/ui/ICameraService.cpp b/libs/ui/ICameraService.cpp
new file mode 100644
index 0000000..e5687fe
--- /dev/null
+++ b/libs/ui/ICameraService.cpp
@@ -0,0 +1,77 @@
+/*
+**
+** Copyright 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 <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+
+#include <ui/ICameraService.h>
+
+namespace android {
+
+class BpCameraService: public BpInterface<ICameraService>
+{
+public:
+    BpCameraService(const sp<IBinder>& impl)
+        : BpInterface<ICameraService>(impl)
+    {
+    }
+
+    // connect to camera service
+    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+        data.writeStrongBinder(cameraClient->asBinder());
+        remote()->transact(BnCameraService::CONNECT, data, &reply);
+        return interface_cast<ICamera>(reply.readStrongBinder());
+    }
+};
+
+IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnCameraService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case CONNECT: {
+            CHECK_INTERFACE(ICameraService, data, reply);
+            sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
+            sp<ICamera> camera = connect(cameraClient);
+            reply->writeStrongBinder(camera->asBinder());
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/libs/ui/IOverlay.cpp b/libs/ui/IOverlay.cpp
new file mode 100644
index 0000000..fed47c2
--- /dev/null
+++ b/libs/ui/IOverlay.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 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 <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+#include <utils/IInterface.h>
+
+#include <ui/IOverlay.h>
+
+namespace android {
+
+enum {
+    DESTROY = IBinder::FIRST_CALL_TRANSACTION, // one-way transaction
+};
+
+class BpOverlay : public BpInterface<IOverlay>
+{
+public:
+    BpOverlay(const sp<IBinder>& impl)
+        : BpInterface<IOverlay>(impl)
+    {
+    }
+
+    virtual void destroy()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOverlay::getInterfaceDescriptor());
+        remote()->transact(DESTROY, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(Overlay, "android.ui.IOverlay");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnOverlay::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case DESTROY: {
+            CHECK_INTERFACE(IOverlay, data, reply);
+            destroy();
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
new file mode 100644
index 0000000..d5e9f81
--- /dev/null
+++ b/libs/ui/ISurface.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 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 <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+#include <utils/IMemory.h>
+
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+
+
+namespace android {
+
+ISurface::BufferHeap::BufferHeap() 
+    : w(0), h(0), hor_stride(0), ver_stride(0), format(0),
+    transform(0), flags(0) 
+{     
+}
+
+ISurface::BufferHeap::BufferHeap(uint32_t w, uint32_t h,
+        int32_t hor_stride, int32_t ver_stride,
+        PixelFormat format, const sp<IMemoryHeap>& heap)
+    : w(w), h(h), hor_stride(hor_stride), ver_stride(ver_stride),
+      format(format), transform(0), flags(0), heap(heap) 
+{
+}
+
+ISurface::BufferHeap::BufferHeap(uint32_t w, uint32_t h,
+        int32_t hor_stride, int32_t ver_stride,
+        PixelFormat format, uint32_t transform, uint32_t flags,
+        const sp<IMemoryHeap>& heap)
+        : w(w), h(h), hor_stride(hor_stride), ver_stride(ver_stride),
+          format(format), transform(transform), flags(flags), heap(heap) 
+{
+}
+
+
+ISurface::BufferHeap::~BufferHeap() 
+{     
+}
+
+class BpSurface : public BpInterface<ISurface>
+{
+public:
+    BpSurface(const sp<IBinder>& impl)
+        : BpInterface<ISurface>(impl)
+    {
+    }
+
+    virtual status_t registerBuffers(const BufferHeap& buffers)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+        data.writeInt32(buffers.w);
+        data.writeInt32(buffers.h);
+        data.writeInt32(buffers.hor_stride);
+        data.writeInt32(buffers.ver_stride);
+        data.writeInt32(buffers.format);
+        data.writeInt32(buffers.transform);
+        data.writeInt32(buffers.flags);
+        data.writeStrongBinder(buffers.heap->asBinder());
+        remote()->transact(REGISTER_BUFFERS, data, &reply);
+        status_t result = reply.readInt32();
+        return result;
+    }
+
+    virtual void postBuffer(ssize_t offset)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+        data.writeInt32(offset);
+        remote()->transact(POST_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual void unregisterBuffers()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+        remote()->transact(UNREGISTER_BUFFERS, data, &reply);
+    }
+
+    virtual sp<OverlayRef> createOverlay(
+             uint32_t w, uint32_t h, int32_t format)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+        data.writeInt32(w);
+        data.writeInt32(h);
+        data.writeInt32(format);
+        remote()->transact(CREATE_OVERLAY, data, &reply);
+        return OverlayRef::readFromParcel(reply);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(Surface, "android.ui.ISurface");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnSurface::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case REGISTER_BUFFERS: {
+            CHECK_INTERFACE(ISurface, data, reply);
+            BufferHeap buffer;
+            buffer.w = data.readInt32();
+            buffer.h = data.readInt32();
+            buffer.hor_stride = data.readInt32();
+            buffer.ver_stride= data.readInt32();
+            buffer.format = data.readInt32();
+            buffer.transform = data.readInt32();
+            buffer.flags = data.readInt32();
+            buffer.heap = interface_cast<IMemoryHeap>(data.readStrongBinder());
+            status_t err = registerBuffers(buffer);
+            reply->writeInt32(err);
+            return NO_ERROR;
+        } break;
+        case UNREGISTER_BUFFERS: {
+            CHECK_INTERFACE(ISurface, data, reply);
+            unregisterBuffers();
+            return NO_ERROR;
+        } break;
+        case POST_BUFFER: {
+            CHECK_INTERFACE(ISurface, data, reply);
+            ssize_t offset = data.readInt32();
+            postBuffer(offset);
+            return NO_ERROR;
+        } break;
+        case CREATE_OVERLAY: {
+            CHECK_INTERFACE(ISurface, data, reply);
+            int w = data.readInt32();
+            int h = data.readInt32();
+            int f = data.readInt32();
+            sp<OverlayRef> o = createOverlay(w, h, f);
+            return OverlayRef::writeToParcel(reply, o);
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
diff --git a/libs/ui/ISurfaceComposer.cpp b/libs/ui/ISurfaceComposer.cpp
new file mode 100644
index 0000000..0fea6f9
--- /dev/null
+++ b/libs/ui/ISurfaceComposer.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+// tag as surfaceflinger
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+#include <utils/IMemory.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+
+#include <ui/ISurfaceComposer.h>
+#include <ui/DisplayInfo.h>
+
+// ---------------------------------------------------------------------------
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
+{
+public:
+    BpSurfaceComposer(const sp<IBinder>& impl)
+        : BpInterface<ISurfaceComposer>(impl)
+    {
+    }
+
+    virtual sp<ISurfaceFlingerClient> createConnection()
+    {
+        uint32_t n;
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply);
+        return interface_cast<ISurfaceFlingerClient>(reply.readStrongBinder());
+    }
+
+    virtual sp<IMemory> getCblk() const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::GET_CBLK, data, &reply);
+        return interface_cast<IMemory>(reply.readStrongBinder());
+    }
+
+    virtual void openGlobalTransaction()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::OPEN_GLOBAL_TRANSACTION, data, &reply);
+    }
+
+    virtual void closeGlobalTransaction()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::CLOSE_GLOBAL_TRANSACTION, data, &reply);
+    }
+
+    virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeInt32(dpy);
+        data.writeInt32(flags);
+        remote()->transact(BnSurfaceComposer::FREEZE_DISPLAY, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeInt32(dpy);
+        data.writeInt32(flags);
+        remote()->transact(BnSurfaceComposer::UNFREEZE_DISPLAY, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual int setOrientation(DisplayID dpy, int orientation)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeInt32(dpy);
+        data.writeInt32(orientation);
+        remote()->transact(BnSurfaceComposer::SET_ORIENTATION, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual void bootFinished()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
+    }
+
+    virtual status_t requestGPU(
+            const sp<IGPUCallback>& callback, gpu_info_t* gpu)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeStrongBinder(callback->asBinder());
+        remote()->transact(BnSurfaceComposer::REQUEST_GPU, data, &reply);
+        gpu->regs = interface_cast<IMemory>(reply.readStrongBinder());
+        gpu->count = reply.readInt32();
+
+        // FIXME: for now, we don't dynamically allocate the regions array
+        size_t maxCount = sizeof(gpu->regions)/sizeof(*gpu->regions);
+        if (gpu->count > maxCount)
+            return BAD_VALUE;
+
+        for (size_t i=0 ; i<gpu->count ; i++) {
+            gpu->regions[i].region = interface_cast<IMemory>(reply.readStrongBinder());
+            gpu->regions[i].reserved = reply.readInt32();
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t revokeGPU()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::REVOKE_GPU, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual void signal() const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnSurfaceComposer::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    status_t err = BnInterface<ISurfaceComposer>::onTransact(code, data, reply, flags);
+    if (err == NO_ERROR)
+        return err;
+
+    CHECK_INTERFACE(ISurfaceComposer, data, reply);
+
+    switch(code) {
+        case CREATE_CONNECTION: {
+            sp<IBinder> b = createConnection()->asBinder();
+            reply->writeStrongBinder(b);
+        } break;
+        case OPEN_GLOBAL_TRANSACTION: {
+            openGlobalTransaction();
+        } break;
+        case CLOSE_GLOBAL_TRANSACTION: {
+            closeGlobalTransaction();
+        } break;
+        case SET_ORIENTATION: {
+            DisplayID dpy = data.readInt32();
+            int orientation = data.readInt32();
+            reply->writeInt32( setOrientation(dpy, orientation) );
+        } break;
+        case FREEZE_DISPLAY: {
+            DisplayID dpy = data.readInt32();
+            uint32_t flags = data.readInt32();
+            reply->writeInt32( freezeDisplay(dpy, flags) );
+        } break;
+        case UNFREEZE_DISPLAY: {
+            DisplayID dpy = data.readInt32();
+            uint32_t flags = data.readInt32();
+            reply->writeInt32( unfreezeDisplay(dpy, flags) );
+        } break;
+        case BOOT_FINISHED: {
+            bootFinished();
+        } break;
+        case REVOKE_GPU: {
+            reply->writeInt32( revokeGPU() );
+        } break;
+        case SIGNAL: {
+            signal();
+        } break;
+        case GET_CBLK: {
+            sp<IBinder> b = getCblk()->asBinder();
+            reply->writeStrongBinder(b);
+        } break;
+        case REQUEST_GPU: {
+            // TODO: this should be protected by a permission
+            gpu_info_t info;
+            sp<IGPUCallback> callback
+                = interface_cast<IGPUCallback>(data.readStrongBinder());
+            status_t res = requestGPU(callback, &info);
+
+            // FIXME: for now, we don't dynamically allocate the regions array
+            size_t maxCount = sizeof(info.regions)/sizeof(*info.regions);
+            if (info.count > maxCount)
+                return BAD_VALUE;
+
+            reply->writeStrongBinder(info.regs->asBinder());
+            reply->writeInt32(info.count);
+            for (size_t i=0 ; i<info.count ; i++) {
+                reply->writeStrongBinder(info.regions[i].region->asBinder());
+                reply->writeInt32(info.regions[i].reserved);
+            }
+            reply->writeInt32(res);
+        } break;
+        default:
+            return UNKNOWN_TRANSACTION;
+    }
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+enum {
+    // Note: BOOT_FINISHED must remain this value, it is called by ActivityManagerService.
+    GPU_LOST = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpGPUCallback : public BpInterface<IGPUCallback>
+{
+public:
+    BpGPUCallback(const sp<IBinder>& impl)
+        : BpInterface<IGPUCallback>(impl)
+    {
+    }
+
+    virtual void gpuLost()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGPUCallback::getInterfaceDescriptor());
+        remote()->transact(GPU_LOST, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(GPUCallback, "android.ui.IGPUCallback");
+
+status_t BnGPUCallback::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case GPU_LOST: {
+            CHECK_INTERFACE(IGPUCallback, data, reply);
+            gpuLost();
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+};
diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp
new file mode 100644
index 0000000..dd6a798
--- /dev/null
+++ b/libs/ui/ISurfaceFlingerClient.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+// tag as surfaceflinger
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+#include <utils/IMemory.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+
+#include <ui/ISurface.h>
+#include <ui/ISurfaceFlingerClient.h>
+#include <ui/Point.h>
+#include <ui/Rect.h>
+
+#include <private/ui/LayerState.h>
+
+// ---------------------------------------------------------------------------
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+enum {
+    GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
+    CREATE_SURFACE,
+    DESTROY_SURFACE,
+    SET_STATE
+};
+
+class BpSurfaceFlingerClient : public BpInterface<ISurfaceFlingerClient>
+{
+public:
+    BpSurfaceFlingerClient(const sp<IBinder>& impl)
+        : BpInterface<ISurfaceFlingerClient>(impl)
+    {
+    }
+
+    virtual void getControlBlocks(sp<IMemory>* ctl) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
+        remote()->transact(GET_CBLK, data, &reply);
+        *ctl  = interface_cast<IMemory>(reply.readStrongBinder());
+    }
+
+    virtual sp<ISurface> createSurface( surface_data_t* params,
+                                        int pid,
+                                        DisplayID display,
+                                        uint32_t w,
+                                        uint32_t h,
+                                        PixelFormat format,
+                                        uint32_t flags)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        data.writeInt32(display);
+        data.writeInt32(w);
+        data.writeInt32(h);
+        data.writeInt32(format);
+        data.writeInt32(flags);
+        remote()->transact(CREATE_SURFACE, data, &reply);
+        params->readFromParcel(reply);
+        return interface_cast<ISurface>(reply.readStrongBinder());
+    }
+                                    
+    virtual status_t destroySurface(SurfaceID sid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
+        data.writeInt32(sid);
+        remote()->transact(DESTROY_SURFACE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t setState(int32_t count, const layer_state_t* states)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
+        data.writeInt32(count);
+        for (int i=0 ; i<count ; i++)
+            states[i].write(data);
+        remote()->transact(SET_STATE, data, &reply);
+        return reply.readInt32();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(SurfaceFlingerClient, "android.ui.ISurfaceFlingerClient");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnSurfaceFlingerClient::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    // codes that don't require permission check
+
+    switch(code) {
+        case GET_CBLK: {
+            CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
+            sp<IMemory> ctl;
+            getControlBlocks(&ctl);
+            reply->writeStrongBinder(ctl->asBinder());
+            return NO_ERROR;
+        } break;
+    }
+
+    // these must be checked
+     
+     IPCThreadState* ipc = IPCThreadState::self();
+     const int pid = ipc->getCallingPid();
+     const int self_pid    = getpid();
+     if (UNLIKELY(pid != self_pid)) {
+         // we're called from a different process, do the real check
+         if (!checkCallingPermission(
+                 String16("android.permission.ACCESS_SURFACE_FLINGER")))
+         {
+             const int uid = ipc->getCallingUid();
+             LOGE("Permission Denial: "
+                     "can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
+             return PERMISSION_DENIED;
+         }
+     }
+   
+     switch(code) {
+        case CREATE_SURFACE: {
+            CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
+            surface_data_t params;
+            int32_t pid = data.readInt32();
+            DisplayID display = data.readInt32();
+            uint32_t w = data.readInt32();
+            uint32_t h = data.readInt32();
+            PixelFormat format = data.readInt32();
+            uint32_t flags = data.readInt32();
+            sp<ISurface> s = createSurface(&params, pid, display, w, h, format, flags);
+            params.writeToParcel(reply);
+            reply->writeStrongBinder(s->asBinder());
+            return NO_ERROR;
+        } break;
+        case DESTROY_SURFACE: {
+            CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
+            reply->writeInt32( destroySurface( data.readInt32() ) );
+            return NO_ERROR;
+        } break;
+        case SET_STATE: {
+            CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
+            int32_t count = data.readInt32();
+            layer_state_t* states = new layer_state_t[count];
+            for (int i=0 ; i<count ; i++)
+                states[i].read(data);
+            status_t err = setState(count, states);
+            delete [] states;
+            reply->writeInt32(err);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------
+
+status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& parcel)
+{
+    token = parcel.readInt32();
+    identity  = parcel.readInt32();
+    heap[0] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
+    heap[1] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
+    return NO_ERROR;
+}
+
+status_t ISurfaceFlingerClient::surface_data_t::writeToParcel(Parcel* parcel) const
+{
+    parcel->writeInt32(token);
+    parcel->writeInt32(identity);
+    parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
+    parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
+    return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp
new file mode 100644
index 0000000..e891181
--- /dev/null
+++ b/libs/ui/KeyCharacterMap.cpp
@@ -0,0 +1,263 @@
+#define LOG_TAG "KeyCharacterMap"
+
+#include <ui/KeyCharacterMap.h>
+#include <cutils/properties.h>
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <string.h>
+
+struct Header
+{
+    char magic[8];
+    unsigned int endian;
+    unsigned int version;
+    unsigned int keycount;
+    unsigned char kbdtype;
+    char padding[11];
+};
+
+KeyCharacterMap::KeyCharacterMap()
+{
+}
+
+KeyCharacterMap::~KeyCharacterMap()
+{
+    free(m_keys);
+}
+
+unsigned short
+KeyCharacterMap::get(int keycode, int meta)
+{
+    Key* k = find_key(keycode);
+    if (k != NULL) {
+        return k->data[meta & META_MASK];
+    }
+    return 0;
+}
+
+unsigned short
+KeyCharacterMap::getNumber(int keycode)
+{
+    Key* k = find_key(keycode);
+    if (k != NULL) {
+        return k->number;
+    }
+    return 0;
+}
+
+unsigned short
+KeyCharacterMap::getMatch(int keycode, const unsigned short* chars,
+                          int charsize, uint32_t modifiers)
+{
+    Key* k = find_key(keycode);
+    modifiers &= 3; // ignore the SYM key because we don't have keymap entries for it
+    if (k != NULL) {
+        const uint16_t* data = k->data;
+        for (int j=0; j<charsize; j++) {
+            uint16_t c = chars[j];
+            for (int i=0; i<(META_MASK + 1); i++) {
+                if ((modifiers == 0) || ((modifiers & i) != 0)) {
+                    if (c == data[i]) {
+                        return c;
+                    }
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+unsigned short
+KeyCharacterMap::getDisplayLabel(int keycode)
+{
+    Key* k = find_key(keycode);
+    if (k != NULL) {
+        return k->display_label;
+    }
+    return 0;
+}
+
+bool
+KeyCharacterMap::getKeyData(int keycode, unsigned short *displayLabel,
+                            unsigned short *number, unsigned short* results)
+{
+    Key* k = find_key(keycode);
+    if (k != NULL) {
+        memcpy(results, k->data, sizeof(short)*(META_MASK + 1));
+        *number = k->number;
+        *displayLabel = k->display_label;
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool
+KeyCharacterMap::find_char(uint16_t c, uint32_t* key, uint32_t* mods)
+{
+    uint32_t N = m_keyCount;
+    for (int j=0; j<(META_MASK + 1); j++) {
+        Key const* keys = m_keys;
+        for (uint32_t i=0; i<N; i++) {
+            if (keys->data[j] == c) {
+                *key = keys->keycode;
+                *mods = j;
+                return true;
+            }
+            keys++;
+        }
+    }
+    return false;
+}
+
+bool
+KeyCharacterMap::getEvents(uint16_t* chars, size_t len,
+                           Vector<int32_t>* keys, Vector<uint32_t>* modifiers)
+{
+    for (size_t i=0; i<len; i++) {
+        uint32_t k, mods;
+        if (find_char(chars[i], &k, &mods)) {
+            keys->add(k);
+            modifiers->add(mods);
+        } else {
+            return false;
+        }
+    }
+    return true;
+}
+
+KeyCharacterMap::Key*
+KeyCharacterMap::find_key(int keycode)
+{
+    Key* keys = m_keys;
+    int low = 0;
+    int high = m_keyCount - 1;
+    int mid;
+    int n;
+    while (low <= high) {
+        mid = (low + high) / 2;
+        n = keys[mid].keycode;
+        if (keycode < n) {
+            high = mid - 1;
+        } else if (keycode > n) {
+            low = mid + 1;
+        } else {
+            return keys + mid;
+        }
+    }
+    return NULL;
+}
+
+KeyCharacterMap*
+KeyCharacterMap::load(int id)
+{
+    KeyCharacterMap* rv = NULL;
+    char path[PATH_MAX];
+    char propName[100];
+    char dev[PROPERTY_VALUE_MAX];
+    char tmpfn[PROPERTY_VALUE_MAX];
+    int err;
+    const char* root = getenv("ANDROID_ROOT");
+
+    sprintf(propName, "hw.keyboards.%u.devname", id);
+    err = property_get(propName, dev, "");
+    if (err > 0) {
+        // replace all the spaces with underscores
+        strcpy(tmpfn, dev);
+        for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
+            *p = '_';
+        snprintf(path, sizeof(path), "%s/usr/keychars/%s.kcm.bin", root, tmpfn);
+        //LOGD("load: dev='%s' path='%s'\n", dev, path);
+        rv = try_file(path);
+        if (rv != NULL) {
+            return rv;
+        }
+        LOGW("Error loading keycharmap file '%s'. %s='%s'", path, propName, dev);
+    } else {
+        LOGW("No keyboard for id %d", id);
+    }
+
+    snprintf(path, sizeof(path), "%s/usr/keychars/qwerty.kcm.bin", root);
+    rv = try_file(path);
+    if (rv == NULL) {
+        LOGE("Can't find any keycharmaps (also tried %s)", path);
+        return NULL;
+    }
+    LOGW("Using default keymap: %s", path);
+
+    return rv;
+}
+
+KeyCharacterMap*
+KeyCharacterMap::try_file(const char* filename)
+{
+    KeyCharacterMap* rv = NULL;
+    Key* keys;
+    int fd;
+    off_t filesize;
+    Header header;
+    int err;
+    
+    fd = open(filename, O_RDONLY);
+    if (fd == -1) {
+        LOGW("Can't open keycharmap file");
+        return NULL;
+    }
+
+    filesize = lseek(fd, 0, SEEK_END);
+    lseek(fd, 0, SEEK_SET);
+
+    // validate the header
+    if (filesize <= (off_t)sizeof(header)) {
+        LOGW("Bad keycharmap - filesize=%d\n", (int)filesize);
+        goto cleanup1;
+    }
+
+    err = read(fd, &header, sizeof(header));
+    if (err == -1) {
+        LOGW("Error reading keycharmap file");
+        goto cleanup1;
+    }
+
+    if (0 != memcmp(header.magic, "keychar", 8)) {
+        LOGW("Bad keycharmap magic token");
+        goto cleanup1;
+    }
+    if (header.endian != 0x12345678) {
+        LOGW("Bad keycharmap endians");
+        goto cleanup1;
+    }
+    if ((header.version & 0xff) != 2) {
+        LOGW("Only support keycharmap version 2 (got 0x%08x)", header.version);
+        goto cleanup1;
+    }
+    if (filesize < (off_t)(sizeof(Header)+(sizeof(Key)*header.keycount))) {
+        LOGW("Bad keycharmap file size\n");
+        goto cleanup1;
+    }
+
+    // read the key data
+    keys = (Key*)malloc(sizeof(Key)*header.keycount);
+    err = read(fd, keys, sizeof(Key)*header.keycount);
+    if (err == -1) {
+        LOGW("Error reading keycharmap file");
+        free(keys);
+        goto cleanup1;
+    }
+
+    // return the object
+    rv = new KeyCharacterMap;
+    rv->m_keyCount = header.keycount;
+    rv->m_keys = keys;
+    rv->m_type = header.kbdtype;
+
+cleanup1:
+    close(fd);
+
+    return rv;
+}
diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp
new file mode 100644
index 0000000..15ae54c
--- /dev/null
+++ b/libs/ui/KeyLayoutMap.cpp
@@ -0,0 +1,235 @@
+#define LOG_TAG "KeyLayoutMap"
+
+#include "KeyLayoutMap.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <utils/String8.h>
+#include <stdlib.h>
+#include <ui/KeycodeLabels.h>
+#include <utils/Log.h>
+
+namespace android {
+
+KeyLayoutMap::KeyLayoutMap()
+    :m_status(NO_INIT),
+     m_keys()
+{
+}
+
+KeyLayoutMap::~KeyLayoutMap()
+{
+}
+
+static String8
+next_token(char const** p, int *line)
+{
+    bool begun = false;
+    const char* begin = *p;
+    const char* end = *p;
+    while (true) {
+        if (*end == '\n') {
+            (*line)++;
+        }
+        switch (*end)
+        {
+            case '#':
+                if (begun) {
+                    *p = end;
+                    return String8(begin, end-begin);
+                } else {
+                    do {
+                        begin++;
+                        end++;
+                    } while (*begin != '\0' && *begin != '\n');
+                }
+            case '\0':
+            case ' ':
+            case '\n':
+            case '\r':
+            case '\t':
+                if (begun || (*end == '\0')) {
+                    *p = end;
+                    return String8(begin, end-begin);
+                } else {
+                    begin++;
+                    end++;
+                    break;
+                }
+            default:
+                end++;
+                begun = true;
+        }
+    }
+}
+
+static int32_t
+token_to_value(const char *literal, const KeycodeLabel *list)
+{
+    while (list->literal) {
+        if (0 == strcmp(literal, list->literal)) {
+            return list->value;
+        }
+        list++;
+    }
+    return list->value;
+}
+
+status_t
+KeyLayoutMap::load(const char* filename)
+{
+    int fd = open(filename, O_RDONLY);
+    if (fd < 0) {
+        LOGE("error opening file=%s err=%s\n", filename, strerror(errno));
+        m_status = errno;
+        return errno;
+    }
+
+    off_t len = lseek(fd, 0, SEEK_END);
+    off_t errlen = lseek(fd, 0, SEEK_SET);
+    if (len < 0 || errlen < 0) {
+        close(fd);
+        LOGE("error seeking file=%s err=%s\n", filename, strerror(errno));
+        m_status = errno;
+        return errno;
+    }
+
+    char* buf = (char*)malloc(len+1);
+    if (read(fd, buf, len) != len) {
+        LOGE("error reading file=%s err=%s\n", filename, strerror(errno));
+        m_status = errno != 0 ? errno : ((int)NOT_ENOUGH_DATA);
+        return errno != 0 ? errno : ((int)NOT_ENOUGH_DATA);
+    }
+    errno = 0;
+    buf[len] = '\0';
+
+    int32_t scancode = -1;
+    int32_t keycode = -1;
+    uint32_t flags = 0;
+    uint32_t tmp;
+    char* end;
+    status_t err = NO_ERROR;
+    int line = 1;
+    char const* p = buf;
+    enum { BEGIN, SCANCODE, KEYCODE, FLAG } state = BEGIN;
+    while (true) {
+        String8 token = next_token(&p, &line);
+        if (*p == '\0') {
+            break;
+        }
+        switch (state)
+        {
+            case BEGIN:
+                if (token == "key") {
+                    state = SCANCODE;
+                } else {
+                    LOGE("%s:%d: expected key, got '%s'\n", filename, line,
+                            token.string());
+                    err = BAD_VALUE;
+                    goto done;
+                }
+                break;
+            case SCANCODE:
+                scancode = strtol(token.string(), &end, 0);
+                if (*end != '\0') {
+                    LOGE("%s:%d: expected scancode (a number), got '%s'\n",
+                            filename, line, token.string());
+                    goto done;
+                }
+                //LOGI("%s:%d: got scancode %d\n", filename, line, scancode );
+                state = KEYCODE;
+                break;
+            case KEYCODE:
+                keycode = token_to_value(token.string(), KEYCODES);
+                //LOGI("%s:%d: got keycode %d for %s\n", filename, line, keycode, token.string() );
+                if (keycode == 0) {
+                    LOGE("%s:%d: expected keycode, got '%s'\n",
+                            filename, line, token.string());
+                    goto done;
+                }
+                state = FLAG;
+                break;
+            case FLAG:
+                if (token == "key") {
+                    if (scancode != -1) {
+                        //LOGI("got key decl scancode=%d keycode=%d"
+                        //       " flags=0x%08x\n", scancode, keycode, flags);
+                        Key k = { keycode, flags };
+                        m_keys.add(scancode, k);
+                        state = SCANCODE;
+                        scancode = -1;
+                        keycode = -1;
+                        flags = 0;
+                        break;
+                    }
+                }
+                tmp = token_to_value(token.string(), FLAGS);
+                //LOGI("%s:%d: got flags %x for %s\n", filename, line, tmp, token.string() );
+                if (tmp == 0) {
+                    LOGE("%s:%d: expected flag, got '%s'\n",
+                            filename, line, token.string());
+                    goto done;
+                }
+                flags |= tmp;
+                break;
+        }
+    }
+    if (state == FLAG && scancode != -1 ) {
+        //LOGI("got key decl scancode=%d keycode=%d"
+        //       " flags=0x%08x\n", scancode, keycode, flags);
+        Key k = { keycode, flags };
+        m_keys.add(scancode, k);
+    }
+
+done:
+    free(buf);
+    close(fd);
+
+    m_status = err;
+    return err;
+}
+
+status_t
+KeyLayoutMap::map(int32_t scancode, int32_t *keycode, uint32_t *flags) const
+{
+    if (m_status != NO_ERROR) {
+        return m_status;
+    }
+
+    ssize_t index = m_keys.indexOfKey(scancode);
+    if (index < 0) {
+        //LOGW("couldn't map scancode=%d\n", scancode);
+        return NAME_NOT_FOUND;
+    }
+
+    const Key& k = m_keys.valueAt(index);
+
+    *keycode = k.keycode;
+    *flags = k.flags;
+
+    //LOGD("mapped scancode=%d to keycode=%d flags=0x%08x\n", scancode,
+    //        keycode, flags);
+
+    return NO_ERROR;
+}
+
+status_t
+KeyLayoutMap::findScancodes(int32_t keycode, Vector<int32_t>* outScancodes) const
+{
+    if (m_status != NO_ERROR) {
+        return m_status;
+    }
+    
+    const size_t N = m_keys.size();
+    for (size_t i=0; i<N; i++) {
+        if (m_keys.valueAt(i).keycode == keycode) {
+            outScancodes->add(m_keys.keyAt(i));
+        }
+    }
+    
+    return NO_ERROR;
+}
+
+};
diff --git a/libs/ui/KeyLayoutMap.h b/libs/ui/KeyLayoutMap.h
new file mode 100644
index 0000000..43f84ce
--- /dev/null
+++ b/libs/ui/KeyLayoutMap.h
@@ -0,0 +1,31 @@
+#ifndef KEYLAYOUTMAP_H
+#define KEYLAYOUTMAP_H
+
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+class KeyLayoutMap
+{
+public:
+    KeyLayoutMap();
+    ~KeyLayoutMap();
+
+    status_t load(const char* filename);
+
+    status_t map(int32_t scancode, int32_t *keycode, uint32_t *flags) const;
+    status_t findScancodes(int32_t keycode, Vector<int32_t>* outScancodes) const;
+
+private:
+    struct Key {
+        int32_t keycode;
+        uint32_t flags;
+    };
+
+    status_t m_status;
+    KeyedVector<int32_t,Key> m_keys;
+};
+
+};
+
+#endif // KEYLAYOUTMAP_H
diff --git a/libs/ui/LayerState.cpp b/libs/ui/LayerState.cpp
new file mode 100644
index 0000000..0b6374b
--- /dev/null
+++ b/libs/ui/LayerState.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 <utils/Errors.h>
+#include <utils/Parcel.h>
+#include <private/ui/LayerState.h>
+
+namespace android {
+
+status_t layer_state_t::write(Parcel& output) const
+{
+    size_t size = sizeof(layer_state_t);
+
+    //output.writeStrongBinder(surface->asBinder());
+    //size -= sizeof(surface);
+
+    transparentRegion.write(output);
+    size -= sizeof(transparentRegion);
+    
+    output.write(this, size);
+    
+    return NO_ERROR;
+}
+
+status_t layer_state_t::read(const Parcel& input)
+{
+    size_t size = sizeof(layer_state_t);
+
+    //surface = interface_cast<ISurface>(input.readStrongBinder());
+    //size -= sizeof(surface);
+
+    transparentRegion.read(input);
+    size -= sizeof(transparentRegion);
+
+    input.read(this, size);
+    
+    return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/libs/ui/MODULE_LICENSE_APACHE2 b/libs/ui/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/ui/MODULE_LICENSE_APACHE2
diff --git a/libs/ui/NOTICE b/libs/ui/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libs/ui/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/libs/ui/Overlay.cpp b/libs/ui/Overlay.cpp
new file mode 100644
index 0000000..b236edc
--- /dev/null
+++ b/libs/ui/Overlay.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007 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 <utils/IMemory.h>
+#include <utils/Parcel.h>
+#include <utils/Errors.h>
+#include <utils/MemoryHeapBase.h>
+
+#include <ui/IOverlay.h>
+#include <ui/Overlay.h>
+
+#include <hardware/overlay.h>
+
+namespace android {
+
+Overlay::Overlay(const sp<OverlayRef>& overlayRef)
+    : mOverlayRef(overlayRef), mOverlayData(0), mStatus(NO_INIT)
+{
+    mOverlayData = NULL;
+    hw_module_t const* module;
+    if (overlayRef != 0) {
+        if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
+            if (overlay_data_open(module, &mOverlayData) == NO_ERROR) {
+                mStatus = mOverlayData->initialize(mOverlayData,
+                        overlayRef->mOverlayHandle);
+            }
+        }
+    }
+}
+
+Overlay::~Overlay() {
+    if (mOverlayData) {
+        overlay_data_close(mOverlayData);
+    }
+}
+
+status_t Overlay::dequeueBuffer(overlay_buffer_t* buffer)
+{
+    if (mStatus != NO_ERROR) return mStatus;
+    return  mOverlayData->dequeueBuffer(mOverlayData, buffer);
+}
+
+status_t Overlay::queueBuffer(overlay_buffer_t buffer)
+{
+    if (mStatus != NO_ERROR) return mStatus;
+    return mOverlayData->queueBuffer(mOverlayData, buffer);
+}
+
+int32_t Overlay::getBufferCount() const
+{
+    if (mStatus != NO_ERROR) return mStatus;
+    return mOverlayData->getBufferCount(mOverlayData);
+}
+
+void* Overlay::getBufferAddress(overlay_buffer_t buffer)
+{
+    if (mStatus != NO_ERROR) return NULL;
+    return mOverlayData->getBufferAddress(mOverlayData, buffer);
+}
+
+void Overlay::destroy() {  
+    if (mStatus != NO_ERROR) return;
+    mOverlayRef->mOverlayChannel->destroy();
+}
+
+status_t Overlay::getStatus() const {
+    return mStatus;
+}
+
+overlay_handle_t Overlay::getHandleRef() const {
+    if (mStatus != NO_ERROR) return NULL;
+    return mOverlayRef->mOverlayHandle;
+}
+
+uint32_t Overlay::getWidth() const {
+    if (mStatus != NO_ERROR) return 0;
+    return mOverlayRef->mWidth;
+}
+
+uint32_t Overlay::getHeight() const {
+    if (mStatus != NO_ERROR) return 0;
+    return mOverlayRef->mHeight;
+}
+
+int32_t Overlay::getFormat() const {
+    if (mStatus != NO_ERROR) return -1;
+    return mOverlayRef->mFormat;
+}
+
+int32_t Overlay::getWidthStride() const {
+    if (mStatus != NO_ERROR) return 0;
+    return mOverlayRef->mWidthStride;
+}
+
+int32_t Overlay::getHeightStride() const {
+    if (mStatus != NO_ERROR) return 0;
+    return mOverlayRef->mHeightStride;
+}
+// ----------------------------------------------------------------------------
+
+OverlayRef::OverlayRef() 
+ : mOverlayHandle(0),
+    mWidth(0), mHeight(0), mFormat(0), mWidthStride(0), mHeightStride(0),
+    mOwnHandle(true)
+{    
+}
+
+OverlayRef::OverlayRef(overlay_handle_t handle, const sp<IOverlay>& channel,
+         uint32_t w, uint32_t h, int32_t f, uint32_t ws, uint32_t hs)
+    : mOverlayHandle(handle), mOverlayChannel(channel),
+    mWidth(w), mHeight(h), mFormat(f), mWidthStride(ws), mHeightStride(hs),
+    mOwnHandle(false)
+{
+}
+
+OverlayRef::~OverlayRef()
+{
+    if (mOwnHandle) {
+        /* FIXME: handles should be promoted to "real" API and be handled by 
+         * the framework */
+        for (int i=0 ; i<mOverlayHandle->numFds ; i++) {
+            close(mOverlayHandle->data[i]);
+        }
+        free((void*)mOverlayHandle);
+    }
+}
+
+sp<OverlayRef> OverlayRef::readFromParcel(const Parcel& data) {
+    sp<OverlayRef> result;
+    sp<IOverlay> overlay = IOverlay::asInterface(data.readStrongBinder());
+    if (overlay != NULL) {
+        uint32_t w = data.readInt32();
+        uint32_t h = data.readInt32();
+        uint32_t f = data.readInt32();
+        uint32_t ws = data.readInt32();
+        uint32_t hs = data.readInt32();
+        native_handle* handle = data.readNativeHandle(NULL, NULL);
+
+        result = new OverlayRef();
+        result->mOverlayHandle = handle;
+        result->mOverlayChannel = overlay;
+        result->mWidth = w;
+        result->mHeight = h;
+        result->mFormat = f;
+        result->mWidthStride = ws;
+        result->mHeightStride = hs;
+    }
+    return result;
+}
+
+status_t OverlayRef::writeToParcel(Parcel* reply, const sp<OverlayRef>& o) {
+    if (o != NULL) {
+        reply->writeStrongBinder(o->mOverlayChannel->asBinder());
+        reply->writeInt32(o->mWidth);
+        reply->writeInt32(o->mHeight);
+        reply->writeInt32(o->mFormat);
+        reply->writeInt32(o->mWidthStride);
+        reply->writeInt32(o->mHeightStride);
+        reply->writeNativeHandle(*(o->mOverlayHandle));
+    } else {
+        reply->writeStrongBinder(NULL);
+    }
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
new file mode 100644
index 0000000..b65ed97
--- /dev/null
+++ b/libs/ui/PixelFormat.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 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 <ui/PixelFormat.h>
+#include <pixelflinger/format.h>
+
+namespace android {
+
+size_t PixelFormatInfo::getScanlineSize(unsigned int width) const
+{
+    size_t size;
+    if ((components >= 6) && (components <= 8)) {
+        // YCbCr formats are differents.
+        size = (width * bitsPerPixel)>>3;
+    } else {
+        size = width * bytesPerPixel;
+    }
+    return size;
+}
+
+ssize_t bytesPerPixel(PixelFormat format)
+{
+    PixelFormatInfo info;
+    status_t err = getPixelFormatInfo(format, &info);
+    return (err < 0) ? err : info.bytesPerPixel;
+}
+
+ssize_t bitsPerPixel(PixelFormat format)
+{
+    PixelFormatInfo info;
+    status_t err = getPixelFormatInfo(format, &info);
+    return (err < 0) ? err : info.bitsPerPixel;
+}
+
+status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info)
+{
+    if (format < 0)
+        return BAD_VALUE;
+
+    if (info->version != sizeof(PixelFormatInfo))
+        return INVALID_OPERATION;
+
+    size_t numEntries;
+    const GGLFormat *i = gglGetPixelFormatTable(&numEntries) + format;
+    bool valid = uint32_t(format) < numEntries;
+    if (!valid) {
+        return BAD_INDEX;
+    }
+    
+    #define COMPONENT(name) \ 
+        case GGL_##name: info->components = PixelFormatInfo::name; break;
+    
+    switch (i->components) {
+        COMPONENT(ALPHA)
+        COMPONENT(RGB)
+        COMPONENT(RGBA)
+        COMPONENT(LUMINANCE)
+        COMPONENT(LUMINANCE_ALPHA)
+        COMPONENT(Y_CB_CR_SP)
+        COMPONENT(Y_CB_CR_P)
+        COMPONENT(Y_CB_CR_I)
+        default:
+            return BAD_INDEX;
+    }
+    
+    #undef COMPONENT
+    
+    info->format = format;
+    info->bytesPerPixel = i->size;
+    info->bitsPerPixel  = i->bitsPerPixel;
+    info->h_alpha       = i->ah;
+    info->l_alpha       = i->al;
+    info->h_red         = i->rh;
+    info->l_red         = i->rl;
+    info->h_green       = i->gh;
+    info->l_green       = i->gl;
+    info->h_blue        = i->bh;
+    info->l_blue        = i->bl;
+
+    return NO_ERROR;
+}
+
+}; // namespace android
+
diff --git a/libs/ui/Point.cpp b/libs/ui/Point.cpp
new file mode 100644
index 0000000..438d49f
--- /dev/null
+++ b/libs/ui/Point.cpp
@@ -0,0 +1,11 @@
+/*
+ *  Point.cpp
+ *  Android
+ *
+ *  Created on 11/16/2006.
+ *  Copyright 2005 The Android Open Source Project
+ *
+ */
+
+#include <ui/Point.h>
+
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
new file mode 100644
index 0000000..99e68bb
--- /dev/null
+++ b/libs/ui/Rect.cpp
@@ -0,0 +1,86 @@
+/*
+ *  Rect.cpp
+ *  Android
+ *
+ *  Created on 10/14/05.
+ *  Copyright 2005 The Android Open Source Project
+ *
+ */
+
+#include <ui/Rect.h>
+
+namespace android {
+
+inline int min(int a, int b) {
+    return (a<b) ? a : b;
+}
+
+inline int max(int a, int b) {
+    return (a>b) ? a : b;
+}
+
+void Rect::makeInvalid() {
+    left = 0;
+    top = 0;
+    right = -1;
+    bottom = -1;
+}
+
+bool Rect::operator < (const Rect& rhs) const
+{
+    if (top<rhs.top) {
+        return true;
+    } else if (top == rhs.top) {
+        if (left < rhs.left) {
+            return true;
+        } else if (left == rhs.left) {
+            if (bottom<rhs.bottom) {
+                return true;
+            } else if (bottom == rhs.bottom) {
+                if (right<rhs.right) {
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+Rect& Rect::offsetTo(int x, int y)
+{
+    right -= left - x;
+    bottom -= top - y;
+    left = x;
+    top = y;
+    return *this;
+}
+
+Rect& Rect::offsetBy(int x, int y)
+{
+    left += x;
+    top  += y;
+    right+= x;
+    bottom+=y;
+    return *this;
+}
+
+Rect Rect::operator + (const Point& rhs) const
+{
+    return Rect(left+rhs.x, top+rhs.y, right+rhs.x, bottom+rhs.y); 
+}
+
+Rect Rect::operator - (const Point& rhs) const
+{
+    return Rect(left-rhs.x, top-rhs.y, right-rhs.x, bottom-rhs.y); 
+}
+
+bool Rect::intersect(const Rect& with, Rect* result) const
+{
+    result->left    = max(left, with.left);
+    result->top     = max(top, with.top);
+    result->right   = min(right, with.right);
+    result->bottom  = min(bottom, with.bottom);
+    return !(result->isEmpty());
+}
+
+}; // namespace android
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
new file mode 100644
index 0000000..26e694a
--- /dev/null
+++ b/libs/ui/Region.cpp
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "Region"
+
+#include <stdio.h>
+#include <utils/Atomic.h>
+#include <utils/Debug.h>
+#include <utils/String8.h>
+#include <ui/Region.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+Region::Region()
+{
+}
+
+Region::Region(const Region& rhs)
+    : mRegion(rhs.mRegion)
+{
+}
+
+Region::Region(const SkRegion& rhs)
+    : mRegion(rhs)
+{
+}
+
+Region::~Region()
+{
+}
+
+Region::Region(const Rect& rhs)
+{
+    set(rhs);
+}
+
+Region::Region(const Parcel& parcel)
+{
+    read(parcel);
+}
+
+Region::Region(const void* buffer)
+{
+    read(buffer);
+}
+
+Region& Region::operator = (const Region& rhs)
+{
+    mRegion = rhs.mRegion;
+    return *this;
+}
+
+const SkRegion& Region::toSkRegion() const
+{
+    return mRegion;
+}
+
+Rect Region::bounds() const
+{
+    const SkIRect& b(mRegion.getBounds());
+    return Rect(b.fLeft, b.fTop, b.fRight, b.fBottom);
+}
+
+void Region::clear()
+{
+    mRegion.setEmpty();
+}
+
+void Region::set(const Rect& r)
+{
+    SkIRect ir;
+    ir.set(r.left, r.top, r.right, r.bottom);
+    mRegion.setRect(ir);
+}
+
+// ----------------------------------------------------------------------------
+
+Region& Region::orSelf(const Rect& r)
+{
+    SkIRect ir;
+    ir.set(r.left, r.top, r.right, r.bottom);
+    mRegion.op(ir, SkRegion::kUnion_Op);
+    return *this;
+}
+
+Region& Region::andSelf(const Rect& r)
+{
+    SkIRect ir;
+    ir.set(r.left, r.top, r.right, r.bottom);
+    mRegion.op(ir, SkRegion::kIntersect_Op);
+    return *this;
+}
+
+// ----------------------------------------------------------------------------
+
+Region& Region::orSelf(const Region& rhs) {
+    mRegion.op(rhs.mRegion, SkRegion::kUnion_Op);
+    return *this;
+}
+
+Region& Region::andSelf(const Region& rhs) {
+    mRegion.op(rhs.mRegion, SkRegion::kIntersect_Op);
+    return *this;
+}
+
+Region& Region::subtractSelf(const Region& rhs) {
+    mRegion.op(rhs.mRegion, SkRegion::kDifference_Op);
+    return *this;
+}
+
+Region& Region::translateSelf(int x, int y) {
+    if (x|y) mRegion.translate(x, y);
+    return *this;
+}
+
+Region Region::merge(const Region& rhs) const {
+    Region result;
+    result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kUnion_Op);
+    return result;
+}
+
+Region Region::intersect(const Region& rhs) const {
+    Region result;
+    result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kIntersect_Op);
+    return result;
+}
+
+Region Region::subtract(const Region& rhs) const {
+    Region result;
+    result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kDifference_Op);
+    return result;
+}
+
+Region Region::translate(int x, int y) const {
+    Region result;
+    mRegion.translate(x, y, &result.mRegion);
+    return result;
+}
+
+// ----------------------------------------------------------------------------
+
+Region& Region::orSelf(const Region& rhs, int dx, int dy) {
+    SkRegion r(rhs.mRegion);
+    r.translate(dx, dy);
+    mRegion.op(r, SkRegion::kUnion_Op);
+    return *this;
+}
+
+Region& Region::andSelf(const Region& rhs, int dx, int dy) {
+    SkRegion r(rhs.mRegion);
+    r.translate(dx, dy);
+    mRegion.op(r, SkRegion::kIntersect_Op);
+    return *this;
+}
+
+Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
+    SkRegion r(rhs.mRegion);
+    r.translate(dx, dy);
+    mRegion.op(r, SkRegion::kDifference_Op);
+    return *this;
+}
+
+Region Region::merge(const Region& rhs, int dx, int dy) const {
+    Region result;
+    SkRegion r(rhs.mRegion);
+    r.translate(dx, dy);
+    result.mRegion.op(mRegion, r, SkRegion::kUnion_Op);
+    return result;
+}
+
+Region Region::intersect(const Region& rhs, int dx, int dy) const {
+    Region result;
+    SkRegion r(rhs.mRegion);
+    r.translate(dx, dy);
+    result.mRegion.op(mRegion, r, SkRegion::kIntersect_Op);
+    return result;
+}
+
+Region Region::subtract(const Region& rhs, int dx, int dy) const {
+    Region result;
+    SkRegion r(rhs.mRegion);
+    r.translate(dx, dy);
+    result.mRegion.op(mRegion, r, SkRegion::kDifference_Op);
+    return result;
+}
+
+// ----------------------------------------------------------------------------
+
+Region::iterator::iterator(const Region& r)
+    : mIt(r.mRegion)
+{
+}
+
+int Region::iterator::iterate(Rect* rect)
+{
+    if (mIt.done())
+        return 0;
+    const SkIRect& r(mIt.rect());
+    rect->left  = r.fLeft;
+    rect->top   = r.fTop;
+    rect->right = r.fRight;
+    rect->bottom= r.fBottom;
+    mIt.next();
+    return 1;
+}
+
+// ----------------------------------------------------------------------------
+
+// we write a 4byte size ahead of the actual region, so we know how much we'll need for reading
+
+status_t Region::write(Parcel& parcel) const
+{
+    int32_t size = mRegion.flatten(NULL);
+    parcel.writeInt32(size);
+    mRegion.flatten(parcel.writeInplace(size));
+    return NO_ERROR;
+}
+
+status_t Region::read(const Parcel& parcel)
+{
+    size_t size = parcel.readInt32();
+    mRegion.unflatten(parcel.readInplace(size));
+    return NO_ERROR;
+}
+
+ssize_t Region::write(void* buffer, size_t size) const
+{
+    size_t sizeNeeded = mRegion.flatten(NULL);
+    if (sizeNeeded > size) return NO_MEMORY;
+    return mRegion.flatten(buffer);
+}
+
+ssize_t Region::read(const void* buffer)
+{
+    return mRegion.unflatten(buffer);
+}
+
+ssize_t Region::writeEmpty(void* buffer, size_t size)
+{
+    if (size < 4) return NO_MEMORY;
+    // this needs to stay in sync with SkRegion
+    *static_cast<int32_t*>(buffer) = -1;
+    return 4;
+}
+
+bool Region::isEmpty(void* buffer)
+{
+    // this needs to stay in sync with SkRegion
+    return *static_cast<int32_t*>(buffer) == -1;
+}
+
+size_t Region::rects(Vector<Rect>& rectList) const
+{
+    rectList.clear();
+    if (!isEmpty()) {
+        SkRegion::Iterator iterator(mRegion);
+        while( !iterator.done() ) {
+            const SkIRect& ir(iterator.rect());
+            rectList.push(Rect(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom));
+            iterator.next();
+        }
+    }
+    return rectList.size();
+}
+
+void Region::dump(String8& out, const char* what, uint32_t flags) const
+{
+    (void)flags;
+    Vector<Rect> r;
+    rects(r);
+    
+    size_t SIZE = 256;
+    char buffer[SIZE];
+    
+    snprintf(buffer, SIZE, "  Region %s (this=%p, count=%d)\n", what, this, r.size());
+    out.append(buffer);
+    for (size_t i=0 ; i<r.size() ; i++) {
+        snprintf(buffer, SIZE, "    [%3d, %3d, %3d, %3d]\n",
+            r[i].left, r[i].top,r[i].right,r[i].bottom);
+        out.append(buffer);
+    }
+}
+
+void Region::dump(const char* what, uint32_t flags) const
+{
+    (void)flags;
+    Vector<Rect> r;
+    rects(r);
+    LOGD("  Region %s (this=%p, count=%d)\n", what, this, r.size());
+    for (size_t i=0 ; i<r.size() ; i++) {
+        LOGD("    [%3d, %3d, %3d, %3d]\n",
+            r[i].left, r[i].top,r[i].right,r[i].bottom);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
new file mode 100644
index 0000000..4ea9ae2
--- /dev/null
+++ b/libs/ui/Surface.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "Surface"
+
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IMemory.h>
+#include <utils/Log.h>
+
+#include <ui/ISurface.h>
+#include <ui/Surface.h>
+#include <ui/SurfaceComposerClient.h>
+#include <ui/Rect.h>
+
+#include <private/ui/SharedState.h>
+#include <private/ui/LayerState.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+Surface::Surface(const sp<SurfaceComposerClient>& client, 
+        const sp<ISurface>& surface,
+        const ISurfaceFlingerClient::surface_data_t& data,
+        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
+        bool owner)
+    : mClient(client), mSurface(surface),
+      mToken(data.token), mIdentity(data.identity),
+      mFormat(format), mFlags(flags), mOwner(owner)
+{
+    mSwapRectangle.makeInvalid();
+    mSurfaceHeapBase[0] = 0;
+    mSurfaceHeapBase[1] = 0;
+    mHeap[0] = data.heap[0]; 
+    mHeap[1] = data.heap[1];
+}
+
+Surface::Surface(Surface const* rhs)
+    : mOwner(false)
+{
+    mToken   = rhs->mToken;
+    mIdentity= rhs->mIdentity;
+    mClient  = rhs->mClient;
+    mSurface = rhs->mSurface;
+    mHeap[0] = rhs->mHeap[0];
+    mHeap[1] = rhs->mHeap[1];
+    mFormat  = rhs->mFormat;
+    mFlags   = rhs->mFlags;
+    mSurfaceHeapBase[0] = rhs->mSurfaceHeapBase[0];
+    mSurfaceHeapBase[1] = rhs->mSurfaceHeapBase[1];
+    mSwapRectangle.makeInvalid();
+}
+
+Surface::~Surface()
+{
+    if (mOwner && mToken>=0 && mClient!=0) {
+        mClient->destroySurface(mToken);
+    }
+    mClient.clear();
+    mSurface.clear();
+    mHeap[0].clear();
+    mHeap[1].clear();
+    IPCThreadState::self()->flushCommands();
+}
+
+sp<Surface> Surface::dup() const
+{
+    Surface const * r = this;
+    if (this && mOwner) {
+        // the only reason we need to do this is because of Java's garbage
+        // collector: because we're creating a copy of the Surface
+        // instead of a reference, we can garantee that when our last
+        // reference goes away, the real surface will be deleted.
+        // Without this hack (the code is correct too), we'd have to
+        // wait for a GC for the surface to go away.
+        r = new Surface(this);        
+    }
+    return const_cast<Surface*>(r);
+}
+
+status_t Surface::nextBuffer(SurfaceInfo* info) {
+    return mClient->nextBuffer(this, info);
+}
+
+status_t Surface::lock(SurfaceInfo* info, bool blocking) {
+    return Surface::lock(info, NULL, blocking);
+}
+
+status_t Surface::lock(SurfaceInfo* info, Region* dirty, bool blocking) {
+    if (heapBase(0) == 0) return INVALID_OPERATION;
+    if (heapBase(1) == 0) return INVALID_OPERATION;
+    return mClient->lockSurface(this, info, dirty, blocking);
+}
+
+status_t Surface::unlockAndPost() {
+    if (heapBase(0) == 0) return INVALID_OPERATION;
+    if (heapBase(1) == 0) return INVALID_OPERATION;
+    return mClient->unlockAndPostSurface(this);
+}
+
+status_t Surface::unlock() {
+    if (heapBase(0) == 0) return INVALID_OPERATION;
+    if (heapBase(1) == 0) return INVALID_OPERATION;
+    return mClient->unlockSurface(this);
+}
+
+status_t Surface::setLayer(int32_t layer) {
+    return mClient->setLayer(this, layer);
+}
+status_t Surface::setPosition(int32_t x, int32_t y) {
+    return mClient->setPosition(this, x, y);
+}
+status_t Surface::setSize(uint32_t w, uint32_t h) {
+    return mClient->setSize(this, w, h);
+}
+status_t Surface::hide() {
+    return mClient->hide(this);
+}
+status_t Surface::show(int32_t layer) {
+    return mClient->show(this, layer);
+}
+status_t Surface::freeze() {
+    return mClient->freeze(this);
+}
+status_t Surface::unfreeze() {
+    return mClient->unfreeze(this);
+}
+status_t Surface::setFlags(uint32_t flags, uint32_t mask) {
+    return mClient->setFlags(this, flags, mask);
+}
+status_t Surface::setTransparentRegionHint(const Region& transparent) {
+    return mClient->setTransparentRegionHint(this, transparent);
+}
+status_t Surface::setAlpha(float alpha) {
+    return mClient->setAlpha(this, alpha);
+}
+status_t Surface::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+    return mClient->setMatrix(this, dsdx, dtdx, dsdy, dtdy);
+}
+status_t Surface::setFreezeTint(uint32_t tint) {
+    return mClient->setFreezeTint(this, tint);
+}
+
+Region Surface::dirtyRegion() const  {
+    return mDirtyRegion; 
+}
+void Surface::setDirtyRegion(const Region& region) const {
+    mDirtyRegion = region;
+}
+const Rect& Surface::swapRectangle() const {
+    return mSwapRectangle;
+}
+void Surface::setSwapRectangle(const Rect& r) {
+    mSwapRectangle = r;
+}
+
+sp<Surface> Surface::readFromParcel(Parcel* parcel)
+{
+    sp<SurfaceComposerClient> client;
+    ISurfaceFlingerClient::surface_data_t data;
+    sp<IBinder> clientBinder= parcel->readStrongBinder();
+    sp<ISurface> surface    = interface_cast<ISurface>(parcel->readStrongBinder());
+    data.heap[0]            = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
+    data.heap[1]            = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
+    data.token              = parcel->readInt32();
+    data.identity           = parcel->readInt32();
+    PixelFormat format      = parcel->readInt32();
+    uint32_t flags          = parcel->readInt32();
+
+    if (clientBinder != NULL)
+        client = SurfaceComposerClient::clientForConnection(clientBinder);
+
+    return new Surface(client, surface, data, 0, 0, format, flags, false);
+}
+
+status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel)
+{
+    uint32_t flags=0;
+    uint32_t format=0;
+    SurfaceID token = -1;
+    uint32_t identity = 0;
+    sp<SurfaceComposerClient> client;
+    sp<ISurface> sur;
+    sp<IMemoryHeap> heap[2];
+    if (surface->isValid()) {
+        token = surface->mToken;
+        identity = surface->mIdentity;
+        client = surface->mClient;
+        sur = surface->mSurface;
+        heap[0] = surface->mHeap[0];
+        heap[1] = surface->mHeap[1];
+        format = surface->mFormat;
+        flags = surface->mFlags;
+    }
+    parcel->writeStrongBinder(client!=0  ? client->connection() : NULL);
+    parcel->writeStrongBinder(sur!=0     ? sur->asBinder()      : NULL);
+    parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder()  : NULL);
+    parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder()  : NULL);
+    parcel->writeInt32(token);
+    parcel->writeInt32(identity);
+    parcel->writeInt32(format);
+    parcel->writeInt32(flags);
+    return NO_ERROR;
+}
+
+bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs) 
+{
+    if (lhs == 0 || rhs == 0)
+        return false;
+    return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
+}
+
+void* Surface::heapBase(int i) const 
+{
+    void* heapBase = mSurfaceHeapBase[i];
+    // map lazily so it doesn't get mapped in clients that don't need it
+    if (heapBase == 0) {
+        const sp<IMemoryHeap>& heap(mHeap[i]);
+        if (heap != 0) {
+            heapBase = static_cast<uint8_t*>(heap->base());
+            if (heapBase == MAP_FAILED) {
+                heapBase = NULL;
+                LOGE("Couldn't map Surface's heap (binder=%p, heap=%p)",
+                        heap->asBinder().get(), heap.get());
+            }
+            mSurfaceHeapBase[i] = heapBase;
+        }
+    }
+    return heapBase;
+}
+
+}; // namespace android
+
diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/ui/SurfaceComposerClient.cpp
new file mode 100644
index 0000000..9354a7a
--- /dev/null
+++ b/libs/ui/SurfaceComposerClient.cpp
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceComposerClient"
+
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <cutils/memory.h>
+
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+#include <utils/IMemory.h>
+#include <utils/Log.h>
+
+#include <ui/ISurfaceComposer.h>
+#include <ui/ISurfaceFlingerClient.h>
+#include <ui/ISurface.h>
+#include <ui/SurfaceComposerClient.h>
+#include <ui/DisplayInfo.h>
+#include <ui/Rect.h>
+#include <ui/Point.h>
+
+#include <private/ui/SharedState.h>
+#include <private/ui/LayerState.h>
+#include <private/ui/SurfaceFlingerSynchro.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include <utils/BpBinder.h>
+
+#define VERBOSE(...)	((void)0)
+//#define VERBOSE			LOGD
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+// Must not be holding SurfaceComposerClient::mLock when acquiring gLock here.
+static Mutex                                                gLock;
+static sp<ISurfaceComposer>                                 gSurfaceManager;
+static DefaultKeyedVector< sp<IBinder>, sp<SurfaceComposerClient> > gActiveConnections;
+static SortedVector<sp<SurfaceComposerClient> >             gOpenTransactions;
+static sp<IMemory>                                          gServerCblkMemory;
+static volatile surface_flinger_cblk_t*                     gServerCblk;
+
+const sp<ISurfaceComposer>& _get_surface_manager()
+{
+    if (gSurfaceManager != 0) {
+        return gSurfaceManager;
+    }
+
+    sp<IBinder> binder;
+    sp<IServiceManager> sm = defaultServiceManager();
+    do {
+        binder = sm->getService(String16("SurfaceFlinger"));
+        if (binder == 0) {
+            LOGW("SurfaceFlinger not published, waiting...");
+            usleep(500000); // 0.5 s
+        }
+    } while(binder == 0);
+    sp<ISurfaceComposer> sc(interface_cast<ISurfaceComposer>(binder));
+
+    Mutex::Autolock _l(gLock);
+    if (gSurfaceManager == 0) {
+        gSurfaceManager = sc;
+    }
+    return gSurfaceManager;
+}
+
+static volatile surface_flinger_cblk_t const * get_cblk()
+{
+    if (gServerCblk == 0) {
+        const sp<ISurfaceComposer>& sm(_get_surface_manager());
+        Mutex::Autolock _l(gLock);
+        if (gServerCblk == 0) {
+            gServerCblkMemory = sm->getCblk();
+            LOGE_IF(gServerCblkMemory==0, "Can't get server control block");
+            gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->pointer();
+            LOGE_IF(gServerCblk==0, "Can't get server control block address");
+        }
+    }
+    return gServerCblk;
+}
+
+// ---------------------------------------------------------------------------
+
+static void copyBlt(const GGLSurface& dst,
+        const GGLSurface& src, const Region& reg)
+{
+    Region::iterator iterator(reg);
+    if (iterator) {
+        // NOTE: dst and src must be the same format
+        Rect r;
+        const size_t bpp = bytesPerPixel(src.format);
+        const size_t dbpr = dst.stride * bpp;
+        const size_t sbpr = src.stride * bpp;
+        while (iterator.iterate(&r)) {
+            ssize_t h = r.bottom - r.top;
+            if (h) {
+                size_t size = (r.right - r.left) * bpp;
+                uint8_t* s = src.data + (r.left + src.stride * r.top) * bpp;
+                uint8_t* d = dst.data + (r.left + dst.stride * r.top) * bpp;
+                if (dbpr==sbpr && size==sbpr) {
+                    size *= h;
+                    h = 1;
+                }
+                do {
+                    memcpy(d, s, size);
+                    d += dbpr;
+                    s += sbpr;
+                } while (--h > 0);
+            }
+        }
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+surface_flinger_cblk_t::surface_flinger_cblk_t()
+{
+}
+
+// ---------------------------------------------------------------------------
+
+per_client_cblk_t::per_client_cblk_t()
+{
+}
+
+// these functions are used by the clients
+inline status_t per_client_cblk_t::validate(size_t i) const {
+    if (uint32_t(i) >= NUM_LAYERS_MAX)
+        return BAD_INDEX;
+    if (layers[i].swapState & eInvalidSurface)
+        return NO_MEMORY;
+    return NO_ERROR;
+}
+
+int32_t per_client_cblk_t::lock_layer(size_t i, uint32_t flags)
+{
+    int32_t index;
+    uint32_t state;
+    int timeout = 0;
+    status_t result;
+    layer_cblk_t * const layer = layers + i;
+    const bool blocking = flags & BLOCKING;
+    const bool inspect  = flags & INSPECT;
+
+    do {
+        state = layer->swapState;
+
+        if (UNLIKELY((state&(eFlipRequested|eNextFlipPending)) == eNextFlipPending)) {
+            LOGE("eNextFlipPending set but eFlipRequested not set, "
+                 "layer=%d (lcblk=%p), state=%08x",
+                 int(i), layer, int(state));
+            return INVALID_OPERATION;
+        }
+
+        if (UNLIKELY(state&eLocked)) {
+            LOGE("eLocked set when entering lock_layer(), "
+                 "layer=%d (lcblk=%p), state=%08x",
+                 int(i), layer, int(state));
+            return WOULD_BLOCK;
+        }
+
+
+	    if (state & (eFlipRequested | eNextFlipPending | eResizeRequested
+                        | eInvalidSurface))
+        {
+	        int32_t resizeIndex;
+	        Mutex::Autolock _l(lock);
+	            // might block for a very short amount of time
+	            // will never cause the server to block (trylock())
+
+	        goto start_loop_here;
+
+	        // We block the client if:
+	        // eNextFlipPending:  we've used both buffers already, so we need to
+	        //                    wait for one to become availlable.
+	        // eResizeRequested:  the buffer we're going to acquire is being
+	        //                    resized. Block until it is done.
+	        // eFlipRequested && eBusy: the buffer we're going to acquire is
+	        //                    currently in use by the server.
+	        // eInvalidSurface:   this is a special case, we don't block in this
+	        //                    case, we just return an error.
+
+	        while((state & (eNextFlipPending|eInvalidSurface)) ||
+	              (state & ((resizeIndex) ? eResizeBuffer1 : eResizeBuffer0)) ||
+	              ((state & (eFlipRequested|eBusy)) == (eFlipRequested|eBusy)) )
+	        {
+	            if (state & eInvalidSurface)
+	                return NO_MEMORY;
+
+	            if (!blocking)
+	                return WOULD_BLOCK;
+
+                timeout = 0;
+                result = cv.waitRelative(lock, seconds(1));
+	            if (__builtin_expect(result!=NO_ERROR, false)) {
+                    const int newState = layer->swapState;
+                    LOGW(   "lock_layer timed out (is the CPU pegged?) "
+                            "layer=%d, lcblk=%p, state=%08x (was %08x)",
+                            int(i), layer, newState, int(state));
+                    timeout = newState != int(state);
+                }
+
+	        start_loop_here:
+	            state = layer->swapState;
+	            resizeIndex = (state&eIndex) ^ ((state&eFlipRequested)>>1);
+	        }
+
+            LOGW_IF(timeout,
+                    "lock_layer() timed out but didn't appear to need "
+                    "to be locked and we recovered "
+                    "(layer=%d, lcblk=%p, state=%08x)",
+                    int(i), layer, int(state));
+	    }
+
+	    // eFlipRequested is not set and cannot be set by another thread: it's
+	    // safe to use the first buffer without synchronization.
+
+        // Choose the index depending on eFlipRequested.
+        // When it's set, choose the 'other' buffer.
+        index = (state&eIndex) ^ ((state&eFlipRequested)>>1);
+
+	    // make sure this buffer is valid
+	    if (layer->surface[index].bits_offset < 0) {
+	        return status_t(layer->surface[index].bits_offset);
+	    }
+
+        if (inspect) {
+            // we just want to inspect this layer. don't lock it.
+            goto done;
+        }
+
+	    // last thing before we're done, we need to atomically lock the state
+    } while (android_atomic_cmpxchg(state, state|eLocked, &(layer->swapState)));
+
+    VERBOSE("locked layer=%d (lcblk=%p), buffer=%d, state=0x%08x",
+         int(i), layer, int(index), int(state));
+
+    // store the index of the locked buffer (for client use only)
+    layer->flags &= ~eBufferIndex;
+    layer->flags |= ((index << eBufferIndexShift) & eBufferIndex);
+
+done:
+    return index;
+}
+
+uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i)
+{
+    // atomically set eFlipRequested and clear eLocked and optionnaly
+    // set eNextFlipPending if eFlipRequested was already set
+
+    layer_cblk_t * const layer = layers + i;
+    int32_t oldvalue, newvalue;
+    do {
+        oldvalue = layer->swapState;
+            // get current value
+
+        newvalue = oldvalue & ~eLocked;
+            // clear eLocked
+
+        newvalue |= eFlipRequested;
+            // set eFlipRequested
+
+        if (oldvalue & eFlipRequested)
+            newvalue |= eNextFlipPending;
+            // if eFlipRequested was alread set, set eNextFlipPending
+
+    } while (android_atomic_cmpxchg(oldvalue, newvalue, &(layer->swapState)));
+
+    VERBOSE("request pageflip for layer=%d, buffer=%d, state=0x%08x",
+            int(i), int((layer->flags & eBufferIndex) >> eBufferIndexShift),
+            int(newvalue));
+
+    // from this point, the server can kick in at anytime and use the first
+    // buffer, so we cannot use it anymore, and we must use the 'other'
+    // buffer instead (or wait if it is not availlable yet, see lock_layer).
+
+    return newvalue;
+}
+
+void per_client_cblk_t::unlock_layer(size_t i)
+{
+    layer_cblk_t * const layer = layers + i;
+    android_atomic_and(~eLocked, &layer->swapState);
+}
+
+// ---------------------------------------------------------------------------
+
+static inline int compare_type( const layer_state_t& lhs,
+                                const layer_state_t& rhs) {
+    if (lhs.surface < rhs.surface)  return -1;
+    if (lhs.surface > rhs.surface)  return 1;
+    return 0;
+}
+
+SurfaceComposerClient::SurfaceComposerClient()
+{
+    const sp<ISurfaceComposer>& sm(_get_surface_manager());
+    if (sm == 0) {
+        _init(0, 0);
+        return;
+    }
+
+    _init(sm, sm->createConnection());
+
+    if (mClient != 0) {
+        Mutex::Autolock _l(gLock);
+        VERBOSE("Adding client %p to map", this);
+        gActiveConnections.add(mClient->asBinder(), this);
+    }
+}
+
+SurfaceComposerClient::SurfaceComposerClient(
+        const sp<ISurfaceComposer>& sm, const sp<IBinder>& conn)
+{
+    _init(sm, interface_cast<ISurfaceFlingerClient>(conn));
+}
+
+void SurfaceComposerClient::_init(
+        const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn)
+{
+    VERBOSE("Creating client %p, conn %p", this, conn.get());
+
+    mSignalServer = 0;
+    mPrebuiltLayerState = 0;
+    mTransactionOpen = 0;
+    mStatus = NO_ERROR;
+    mControl = 0;
+
+    mClient = conn;
+    if (mClient == 0) {
+        mStatus = NO_INIT;
+        return;
+    }
+
+    mClient->getControlBlocks(&mControlMemory);
+    mSignalServer = new SurfaceFlingerSynchro(sm);
+    mControl = static_cast<per_client_cblk_t *>(mControlMemory->pointer());
+}
+
+SurfaceComposerClient::~SurfaceComposerClient()
+{
+    VERBOSE("Destroying client %p, conn %p", this, mClient.get());
+    dispose();
+}
+
+status_t SurfaceComposerClient::initCheck() const
+{
+    return mStatus;
+}
+
+status_t SurfaceComposerClient::validateSurface(
+        per_client_cblk_t const* cblk, Surface const * surface)
+{
+    SurfaceID index = surface->ID();
+    if (cblk == 0) {
+        LOGE("cblk is null (surface id=%d, identity=%u)",
+                index, surface->getIdentity());
+        return NO_INIT;
+    }
+
+    status_t err = cblk->validate(index);
+    if (err != NO_ERROR) {
+        LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
+                index, surface->getIdentity(), err, strerror(-err));
+        return err;
+    }
+
+    if (surface->getIdentity() != uint32_t(cblk->layers[index].identity)) {
+        LOGE("using an invalid surface id=%d, identity=%u should be %d",
+                index, surface->getIdentity(), cblk->layers[index].identity);
+        return NO_INIT;
+    }
+
+    return NO_ERROR;
+}
+
+sp<IBinder> SurfaceComposerClient::connection() const
+{
+    return (mClient != 0) ? mClient->asBinder() : 0;
+}
+
+sp<SurfaceComposerClient>
+SurfaceComposerClient::clientForConnection(const sp<IBinder>& conn)
+{
+    sp<SurfaceComposerClient> client;
+
+    { // scope for lock
+        Mutex::Autolock _l(gLock);
+        client = gActiveConnections.valueFor(conn);
+    }
+
+    if (client == 0) {
+        // Need to make a new client.
+        const sp<ISurfaceComposer>& sm(_get_surface_manager());
+        client = new SurfaceComposerClient(sm, conn);
+        if (client != 0 && client->initCheck() == NO_ERROR) {
+            Mutex::Autolock _l(gLock);
+            gActiveConnections.add(conn, client);
+            //LOGD("we have %d connections", gActiveConnections.size());
+        } else {
+            client.clear();
+        }
+    }
+
+    return client;
+}
+
+void SurfaceComposerClient::dispose()
+{
+    // this can be called more than once.
+
+    sp<IMemory>                 controlMemory;
+    sp<ISurfaceFlingerClient>   client;
+    sp<IMemoryHeap>             surfaceHeap;
+
+    {
+        Mutex::Autolock _lg(gLock);
+        Mutex::Autolock _lm(mLock);
+
+        delete mSignalServer;
+        mSignalServer = 0;
+
+        if (mClient != 0) {
+            client = mClient;
+            mClient.clear();
+
+            ssize_t i = gActiveConnections.indexOfKey(client->asBinder());
+            if (i >= 0 && gActiveConnections.valueAt(i) == this) {
+                VERBOSE("Removing client %p from map at %d", this, int(i));
+                gActiveConnections.removeItemsAt(i);
+            }
+        }
+
+        delete mPrebuiltLayerState;
+        mPrebuiltLayerState = 0;
+        controlMemory = mControlMemory;
+        surfaceHeap = mSurfaceHeap;
+        mControlMemory.clear();
+        mSurfaceHeap.clear();
+        mControl = 0;
+        mStatus = NO_INIT;
+    }
+}
+
+status_t SurfaceComposerClient::getDisplayInfo(
+        DisplayID dpy, DisplayInfo* info)
+{
+    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+        return BAD_VALUE;
+
+    volatile surface_flinger_cblk_t const * cblk = get_cblk();
+    volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+
+    info->w              = dcblk->w;
+    info->h              = dcblk->h;
+    info->orientation    = dcblk->orientation;
+    info->xdpi           = dcblk->xdpi;
+    info->ydpi           = dcblk->ydpi;
+    info->fps            = dcblk->fps;
+    info->density        = dcblk->density;
+    return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo));
+}
+
+ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
+{
+    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+        return BAD_VALUE;
+    volatile surface_flinger_cblk_t const * cblk = get_cblk();
+    volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+    return dcblk->w;
+}
+
+ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
+{
+    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+        return BAD_VALUE;
+    volatile surface_flinger_cblk_t const * cblk = get_cblk();
+    volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+    return dcblk->h;
+}
+
+ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
+{
+    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+        return BAD_VALUE;
+    volatile surface_flinger_cblk_t const * cblk = get_cblk();
+    volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+    return dcblk->orientation;
+}
+
+ssize_t SurfaceComposerClient::getNumberOfDisplays()
+{
+    volatile surface_flinger_cblk_t const * cblk = get_cblk();
+    uint32_t connected = cblk->connected;
+    int n = 0;
+    while (connected) {
+        if (connected&1) n++;
+        connected >>= 1;
+    }
+    return n;
+}
+
+sp<Surface> SurfaceComposerClient::createSurface(
+        int pid,
+        DisplayID display,
+        uint32_t w,
+        uint32_t h,
+        PixelFormat format,
+        uint32_t flags)
+{
+    sp<Surface> result;
+    if (mStatus == NO_ERROR) {
+        ISurfaceFlingerClient::surface_data_t data;
+        sp<ISurface> surface = mClient->createSurface(&data, pid,
+                display, w, h, format, flags);
+        if (surface != 0) {
+            if (uint32_t(data.token) < NUM_LAYERS_MAX) {
+                result = new Surface(this, surface, data, w, h, format, flags);
+            }
+        }
+    }
+    return result;
+}
+
+status_t SurfaceComposerClient::destroySurface(SurfaceID sid)
+{
+    if (mStatus != NO_ERROR)
+        return mStatus;
+
+    // it's okay to destroy a surface while a transaction is open,
+    // (transactions really are a client-side concept)
+    // however, this indicates probably a misuse of the API or a bug
+    // in the client code.
+    LOGW_IF(mTransactionOpen,
+         "Destroying surface while a transaction is open. "
+         "Client %p: destroying surface %d, mTransactionOpen=%d",
+         this, sid, mTransactionOpen);
+
+    status_t err = mClient->destroySurface(sid);
+    return err;
+}
+
+status_t SurfaceComposerClient::nextBuffer(Surface* surface,
+                        Surface::SurfaceInfo* info)
+{
+    SurfaceID index = surface->ID();
+    per_client_cblk_t* const cblk = mControl;
+    status_t err = validateSurface(cblk, surface);
+    if (err != NO_ERROR)
+        return err;
+
+    int32_t backIdx = surface->mBackbufferIndex;
+    layer_cblk_t* const lcblk = &(cblk->layers[index]);
+    const surface_info_t* const front = lcblk->surface + (1-backIdx);
+        info->w      = front->w;
+        info->h      = front->h;
+        info->format = front->format;
+        info->base   = surface->heapBase(1-backIdx);
+        info->bits   = reinterpret_cast<void*>(intptr_t(info->base) + front->bits_offset);
+        info->bpr    = front->bpr;
+
+    return 0;
+}
+
+status_t SurfaceComposerClient::lockSurface(
+        Surface* surface,
+        Surface::SurfaceInfo* other,
+        Region* dirty,
+        bool blocking)
+{
+    Mutex::Autolock _l(surface->getLock());
+
+    SurfaceID index = surface->ID();
+    per_client_cblk_t* const cblk = mControl;
+    status_t err = validateSurface(cblk, surface);
+    if (err != NO_ERROR)
+        return err;
+
+    int32_t backIdx = cblk->lock_layer(size_t(index),
+            per_client_cblk_t::BLOCKING);
+    if (backIdx >= 0) {
+        surface->mBackbufferIndex = backIdx;
+        layer_cblk_t* const lcblk = &(cblk->layers[index]);
+        const surface_info_t* const back = lcblk->surface + backIdx;
+        const surface_info_t* const front = lcblk->surface + (1-backIdx);
+            other->w      = back->w;
+            other->h      = back->h;
+            other->format = back->format;
+            other->base   = surface->heapBase(backIdx);
+            other->bits   = reinterpret_cast<void*>(intptr_t(other->base) + back->bits_offset);
+            other->bpr    = back->bpr;
+
+        const Rect bounds(other->w, other->h);
+        Region newDirtyRegion;
+
+        if (back->flags & surface_info_t::eBufferDirty) {
+            /* it is safe to write *back here, because we're guaranteed
+             * SurfaceFlinger is not touching it (since it just granted
+             * access to us) */
+            const_cast<surface_info_t*>(back)->flags &=
+                    ~surface_info_t::eBufferDirty;
+
+            // content is meaningless in this case and the whole surface
+            // needs to be redrawn.
+
+            newDirtyRegion.set(bounds);
+            if (dirty) {
+                *dirty = newDirtyRegion;
+            }
+
+            //if (bytesPerPixel(other->format) == 4) {
+            //    android_memset32(
+            //        (uint32_t*)other->bits, 0xFF00FF00, other->h * other->bpr);
+            //} else {
+            //    android_memset16( // fill with green
+            //        (uint16_t*)other->bits, 0x7E0, other->h * other->bpr);
+            //}
+        }
+        else
+        {
+            if (dirty) {
+                dirty->andSelf(Region(bounds));
+                newDirtyRegion = *dirty;
+            } else {
+                newDirtyRegion.set(bounds);
+            }
+
+            Region copyback;
+            if (!(lcblk->flags & eNoCopyBack)) {
+                const Region previousDirtyRegion(surface->dirtyRegion());
+                copyback = previousDirtyRegion.subtract(newDirtyRegion);
+            }
+
+            if (!copyback.isEmpty()) {
+                // copy front to back
+                GGLSurface cb;
+                    cb.version = sizeof(GGLSurface);
+                    cb.width = back->w;
+                    cb.height = back->h;
+                    cb.stride = back->stride;
+                    cb.data = (GGLubyte*)surface->heapBase(backIdx);
+                    cb.data += back->bits_offset;
+                    cb.format = back->format;
+
+                GGLSurface t;
+                    t.version = sizeof(GGLSurface);
+                    t.width = front->w;
+                    t.height = front->h;
+                    t.stride = front->stride;
+                    t.data = (GGLubyte*)surface->heapBase(1-backIdx);
+                    t.data += front->bits_offset;
+                    t.format = front->format;
+
+                //const Region copyback(lcblk->region + 1-backIdx);
+                copyBlt(cb, t, copyback);
+            }
+        }
+
+        // update dirty region
+        surface->setDirtyRegion(newDirtyRegion);
+    }
+    return (backIdx < 0) ? status_t(backIdx) : status_t(NO_ERROR);
+}
+
+void SurfaceComposerClient::_signal_server()
+{
+    mSignalServer->signal();
+}
+
+void SurfaceComposerClient::_send_dirty_region(
+        layer_cblk_t* lcblk, const Region& dirty)
+{
+    const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift;
+    flat_region_t* flat_region = lcblk->region + index;
+    status_t err = dirty.write(flat_region, sizeof(flat_region_t));
+    if (err < NO_ERROR) {
+        // region doesn't fit, use the bounds
+        const Region reg(dirty.bounds());
+        reg.write(flat_region, sizeof(flat_region_t));
+    }
+}
+
+status_t SurfaceComposerClient::unlockAndPostSurface(Surface* surface)
+{
+    Mutex::Autolock _l(surface->getLock());
+
+    SurfaceID index = surface->ID();
+    per_client_cblk_t* const cblk = mControl;
+    status_t err = validateSurface(cblk, surface);
+    if (err != NO_ERROR)
+        return err;
+
+    Region dirty(surface->dirtyRegion());
+    const Rect& swapRect(surface->swapRectangle());
+    if (swapRect.isValid()) {
+        dirty.set(swapRect);
+    }
+
+    // transmit the dirty region
+    layer_cblk_t* const lcblk = &(cblk->layers[index]);
+    _send_dirty_region(lcblk, dirty);
+    uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
+    if (!(newstate & eNextFlipPending))
+        _signal_server();
+    return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::unlockSurface(Surface* surface)
+{
+    Mutex::Autolock _l(surface->getLock());
+
+    SurfaceID index = surface->ID();
+    per_client_cblk_t* const cblk = mControl;
+    status_t err = validateSurface(cblk, surface);
+    if (err != NO_ERROR)
+        return err;
+
+    layer_cblk_t* const lcblk = &(cblk->layers[index]);
+    cblk->unlock_layer(size_t(index));
+    return NO_ERROR;
+}
+
+void SurfaceComposerClient::openGlobalTransaction()
+{
+    Mutex::Autolock _l(gLock);
+
+    if (gOpenTransactions.size()) {
+        LOGE("openGlobalTransaction() called more than once. skipping.");
+        return;
+    }
+
+    const size_t N = gActiveConnections.size();
+    VERBOSE("openGlobalTransaction (%ld clients)", N);
+    for (size_t i=0; i<N; i++) {
+        sp<SurfaceComposerClient> client(gActiveConnections.valueAt(i));
+        if (gOpenTransactions.indexOf(client) < 0) {
+            if (client->openTransaction() == NO_ERROR) {
+                if (gOpenTransactions.add(client) < 0) {
+                    // Ooops!
+                    LOGE(   "Unable to add a SurfaceComposerClient "
+                            "to the global transaction set (out of memory?)");
+                    client->closeTransaction();
+                    // let it go, it'll fail later when the user
+                    // tries to do something with the transaction
+                }
+            } else {
+                LOGE("openTransaction on client %p failed", client.get());
+                // let it go, it'll fail later when the user
+                // tries to do something with the transaction
+            }
+        }
+    }
+}
+
+void SurfaceComposerClient::closeGlobalTransaction()
+{
+    gLock.lock();
+        SortedVector< sp<SurfaceComposerClient> > clients(gOpenTransactions);
+        gOpenTransactions.clear();
+    gLock.unlock();
+
+    const size_t N = clients.size();
+    VERBOSE("closeGlobalTransaction (%ld clients)", N);
+    if (N == 1) {
+        clients[0]->closeTransaction();
+    } else {
+        const sp<ISurfaceComposer>& sm(_get_surface_manager());
+        sm->openGlobalTransaction();
+        for (size_t i=0; i<N; i++) {
+            clients[i]->closeTransaction();
+        }
+        sm->closeGlobalTransaction();
+    }
+}
+
+status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
+{
+    const sp<ISurfaceComposer>& sm(_get_surface_manager());
+    return sm->freezeDisplay(dpy, flags);
+}
+
+status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags)
+{
+    const sp<ISurfaceComposer>& sm(_get_surface_manager());
+    return sm->unfreezeDisplay(dpy, flags);
+}
+
+int SurfaceComposerClient::setOrientation(DisplayID dpy, int orientation)
+{
+    const sp<ISurfaceComposer>& sm(_get_surface_manager());
+    return sm->setOrientation(dpy, orientation);
+}
+
+status_t SurfaceComposerClient::openTransaction()
+{
+    if (mStatus != NO_ERROR)
+        return mStatus;
+    Mutex::Autolock _l(mLock);
+    VERBOSE(   "openTransaction (client %p, mTransactionOpen=%d)",
+            this, mTransactionOpen);
+    mTransactionOpen++;
+    if (mPrebuiltLayerState == 0) {
+        mPrebuiltLayerState = new layer_state_t;
+    }
+    return NO_ERROR;
+}
+
+
+status_t SurfaceComposerClient::closeTransaction()
+{
+    if (mStatus != NO_ERROR)
+        return mStatus;
+
+    Mutex::Autolock _l(mLock);
+
+    VERBOSE(   "closeTransaction (client %p, mTransactionOpen=%d)",
+            this, mTransactionOpen);
+
+    if (mTransactionOpen <= 0) {
+        LOGE(   "closeTransaction (client %p, mTransactionOpen=%d) "
+                "called more times than openTransaction()",
+                this, mTransactionOpen);
+        return INVALID_OPERATION;
+    }
+
+    if (mTransactionOpen >= 2) {
+        mTransactionOpen--;
+        return NO_ERROR;
+    }
+
+    mTransactionOpen = 0;
+    const ssize_t count = mStates.size();
+    if (count) {
+        mClient->setState(count, mStates.array());
+        mStates.clear();
+    }
+    return NO_ERROR;
+}
+
+layer_state_t* SurfaceComposerClient::_get_state_l(const sp<Surface>& surface)
+{
+    SurfaceID index = surface->ID();
+    per_client_cblk_t* const cblk = mControl;
+    status_t err = validateSurface(cblk, surface.get());
+    if (err != NO_ERROR)
+        return 0;
+
+    // API usage error, do nothing.
+    if (mTransactionOpen<=0) {
+        LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d",
+                this, int(index), mTransactionOpen);
+        return 0;
+    }
+
+    // use mPrebuiltLayerState just to find out if we already have it
+    layer_state_t& dummy = *mPrebuiltLayerState;
+    dummy.surface = index;
+    ssize_t i = mStates.indexOf(dummy);
+    if (i < 0) {
+        // we don't have it, add an initialized layer_state to our list
+        i = mStates.add(dummy);
+    }
+    return mStates.editArray() + i;
+}
+
+layer_state_t* SurfaceComposerClient::_lockLayerState(const sp<Surface>& surface)
+{
+    layer_state_t* s;
+    mLock.lock();
+    s = _get_state_l(surface);
+    if (!s) mLock.unlock();
+    return s;
+}
+
+void SurfaceComposerClient::_unlockLayerState()
+{
+    mLock.unlock();
+}
+
+status_t SurfaceComposerClient::setPosition(Surface* surface, int32_t x, int32_t y)
+{
+    layer_state_t* s = _lockLayerState(surface);
+    if (!s) return BAD_INDEX;
+    s->what |= ISurfaceComposer::ePositionChanged;
+    s->x = x;
+    s->y = y;
+    _unlockLayerState();
+    return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setSize(Surface* surface, uint32_t w, uint32_t h)
+{
+    layer_state_t* s = _lockLayerState(surface);
+    if (!s) return BAD_INDEX;
+    s->what |= ISurfaceComposer::eSizeChanged;
+    s->w = w;
+    s->h = h;
+    _unlockLayerState();
+    return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setLayer(Surface* surface, int32_t z)
+{
+    layer_state_t* s = _lockLayerState(surface);
+    if (!s) return BAD_INDEX;
+    s->what |= ISurfaceComposer::eLayerChanged;
+    s->z = z;
+    _unlockLayerState();
+    return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::hide(Surface* surface)
+{
+    return setFlags(surface, ISurfaceComposer::eLayerHidden,
+            ISurfaceComposer::eLayerHidden);
+}
+
+status_t SurfaceComposerClient::show(Surface* surface, int32_t)
+{
+    return setFlags(surface, 0, ISurfaceComposer::eLayerHidden);
+}
+
+status_t SurfaceComposerClient::freeze(Surface* surface)
+{
+    return setFlags(surface, ISurfaceComposer::eLayerFrozen,
+            ISurfaceComposer::eLayerFrozen);
+}
+
+status_t SurfaceComposerClient::unfreeze(Surface* surface)
+{
+    return setFlags(surface, 0, ISurfaceComposer::eLayerFrozen);
+}
+
+status_t SurfaceComposerClient::setFlags(Surface* surface,
+        uint32_t flags, uint32_t mask)
+{
+    layer_state_t* s = _lockLayerState(surface);
+    if (!s) return BAD_INDEX;
+    s->what |= ISurfaceComposer::eVisibilityChanged;
+    s->flags &= ~mask;
+    s->flags |= (flags & mask);
+    s->mask |= mask;
+    _unlockLayerState();
+    return NO_ERROR;
+}
+
+
+status_t SurfaceComposerClient::setTransparentRegionHint(
+        Surface* surface, const Region& transparentRegion)
+{
+    layer_state_t* s = _lockLayerState(surface);
+    if (!s) return BAD_INDEX;
+    s->what |= ISurfaceComposer::eTransparentRegionChanged;
+    s->transparentRegion = transparentRegion;
+    _unlockLayerState();
+    return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setAlpha(Surface* surface, float alpha)
+{
+    layer_state_t* s = _lockLayerState(surface);
+    if (!s) return BAD_INDEX;
+    s->what |= ISurfaceComposer::eAlphaChanged;
+    s->alpha = alpha;
+    _unlockLayerState();
+    return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setMatrix(
+        Surface* surface,
+        float dsdx, float dtdx,
+        float dsdy, float dtdy )
+{
+    layer_state_t* s = _lockLayerState(surface);
+    if (!s) return BAD_INDEX;
+    s->what |= ISurfaceComposer::eMatrixChanged;
+    layer_state_t::matrix22_t matrix;
+    matrix.dsdx = dsdx;
+    matrix.dtdx = dtdx;
+    matrix.dsdy = dsdy;
+    matrix.dtdy = dtdy;
+    s->matrix = matrix;
+    _unlockLayerState();
+    return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setFreezeTint(Surface* surface, uint32_t tint)
+{
+    layer_state_t* s = _lockLayerState(surface);
+    if (!s) return BAD_INDEX;
+    s->what |= ISurfaceComposer::eFreezeTintChanged;
+    s->tint = tint;
+    _unlockLayerState();
+    return NO_ERROR;
+}
+
+}; // namespace android
+
diff --git a/libs/ui/SurfaceFlingerSynchro.cpp b/libs/ui/SurfaceFlingerSynchro.cpp
new file mode 100644
index 0000000..5cd9755
--- /dev/null
+++ b/libs/ui/SurfaceFlingerSynchro.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlingerSynchro"
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <utils/IPCThreadState.h>
+#include <utils/Log.h>
+
+#include <private/ui/SurfaceFlingerSynchro.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+SurfaceFlingerSynchro::Barrier::Barrier()
+    : state(CLOSED) { 
+}
+
+SurfaceFlingerSynchro::Barrier::~Barrier() { 
+}
+
+void SurfaceFlingerSynchro::Barrier::open() {
+    asm volatile ("":::"memory");
+    Mutex::Autolock _l(lock);
+    state = OPENED;
+    cv.broadcast();
+}
+
+void SurfaceFlingerSynchro::Barrier::close() {
+    Mutex::Autolock _l(lock);
+    state = CLOSED;
+}
+
+void SurfaceFlingerSynchro::Barrier::waitAndClose() 
+{
+    Mutex::Autolock _l(lock);
+    while (state == CLOSED) {
+        // we're about to wait, flush the binder command buffer
+        IPCThreadState::self()->flushCommands();
+        cv.wait(lock);
+    }
+    state = CLOSED;
+}
+
+status_t SurfaceFlingerSynchro::Barrier::waitAndClose(nsecs_t timeout) 
+{
+    Mutex::Autolock _l(lock);
+    while (state == CLOSED) {
+        // we're about to wait, flush the binder command buffer
+        IPCThreadState::self()->flushCommands();
+        int err = cv.waitRelative(lock, timeout);
+        if (err != 0)
+            return err;
+    }
+    state = CLOSED;
+    return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+SurfaceFlingerSynchro::SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger)
+    : mSurfaceComposer(flinger)
+{
+}
+
+SurfaceFlingerSynchro::SurfaceFlingerSynchro()
+{
+}
+
+SurfaceFlingerSynchro::~SurfaceFlingerSynchro()
+{
+}
+
+status_t SurfaceFlingerSynchro::signal()
+{
+    mSurfaceComposer->signal();
+    return NO_ERROR;
+}
+
+status_t SurfaceFlingerSynchro::wait()
+{
+    mBarrier.waitAndClose();
+    return NO_ERROR;
+}
+
+status_t SurfaceFlingerSynchro::wait(nsecs_t timeout)
+{
+    if (timeout == 0)
+        return SurfaceFlingerSynchro::wait();
+    return mBarrier.waitAndClose(timeout);
+}
+
+void SurfaceFlingerSynchro::open()
+{
+    mBarrier.open();
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/libs/ui/Time.cpp b/libs/ui/Time.cpp
new file mode 100644
index 0000000..b553913
--- /dev/null
+++ b/libs/ui/Time.cpp
@@ -0,0 +1,199 @@
+#include <utils/TimeUtils.h>
+#include <stdio.h>
+#include <cutils/tztime.h>
+
+namespace android {
+
+static void
+dump(const Time& t)
+{
+    #ifdef HAVE_TM_GMTOFF
+        long tm_gmtoff = t.t.tm_gmtoff;
+    #else
+        long tm_gmtoff = 0;
+    #endif
+    printf("%04d-%02d-%02d %02d:%02d:%02d (%d,%ld,%d,%d)\n",
+            t.t.tm_year+1900, t.t.tm_mon+1, t.t.tm_mday,
+            t.t.tm_hour, t.t.tm_min, t.t.tm_sec,
+            t.t.tm_isdst, tm_gmtoff, t.t.tm_wday, t.t.tm_yday);
+}
+
+Time::Time()
+{
+    t.tm_sec = 0;
+    t.tm_min = 0;
+    t.tm_hour = 0;
+    t.tm_mday = 0;
+    t.tm_mon = 0;
+    t.tm_year = 0;
+    t.tm_wday = 0;
+    t.tm_yday = 0;
+    t.tm_isdst = -1; // we don't know, so let the C library determine
+    #ifdef HAVE_TM_GMTOFF
+        t.tm_gmtoff = 0;
+    #endif
+}
+
+
+#define COMPARE_FIELD(field) do { \
+        int diff = a.t.field - b.t.field; \
+        if (diff != 0) return diff; \
+    } while(0)
+
+int
+Time::compare(Time& a, Time& b)
+{
+    if (0 == strcmp(a.timezone, b.timezone)) {
+        // if the timezones are the same, we can easily compare the two
+        // times.  Otherwise, convert to milliseconds and compare that.
+        // This requires that object be normalized.
+        COMPARE_FIELD(tm_year);
+        COMPARE_FIELD(tm_mon);
+        COMPARE_FIELD(tm_mday);
+        COMPARE_FIELD(tm_hour);
+        COMPARE_FIELD(tm_min);
+        COMPARE_FIELD(tm_sec);
+        return 0;
+    } else {
+        int64_t am = a.toMillis(false /* use isDst */);
+        int64_t bm = b.toMillis(false /* use isDst */);
+        int64_t diff = am-bm;
+        return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0);
+    }
+}
+
+static const int DAYS_PER_MONTH[] = {
+                        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+                    };
+
+static inline int days_this_month(int year, int month)
+{
+    int n = DAYS_PER_MONTH[month];
+    if (n != 28) {
+        return n;
+    } else {
+        int y = year;
+        return ((y%4)==0&&((y%100)!=0||(y%400)==0)) ? 29 : 28;
+    }
+}
+
+void 
+Time::switchTimezone(const char* timezone)
+{
+    time_t seconds = mktime_tz(&(this->t), this->timezone);
+    localtime_tz(&seconds, &(this->t), timezone);
+}
+
+String8 
+Time::format(const char *format, const struct strftime_locale *locale) const
+{
+    char buf[257];
+    int n = strftime_tz(buf, 257, format, &(this->t), locale);
+    if (n > 0) {
+        return String8(buf);
+    } else {
+        return String8();
+    }
+}
+
+static inline short
+tochar(int n)
+{
+    return (n >= 0 && n <= 9) ? ('0'+n) : ' ';
+}
+
+static inline short
+next_char(int *m, int k)
+{
+    int n = *m / k;
+    *m = *m % k;
+    return tochar(n);
+}
+
+void
+Time::format2445(short* buf, bool hasTime) const
+{
+    int n;
+
+    n = t.tm_year+1900;
+    buf[0] = next_char(&n, 1000);
+    buf[1] = next_char(&n, 100);
+    buf[2] = next_char(&n, 10);
+    buf[3] = tochar(n);
+
+    n = t.tm_mon+1;
+    buf[4] = next_char(&n, 10);
+    buf[5] = tochar(n);
+
+    n = t.tm_mday;
+    buf[6] = next_char(&n, 10);
+    buf[7] = tochar(n);
+
+    if (hasTime) {
+      buf[8] = 'T';
+
+      n = t.tm_hour;
+      buf[9] = next_char(&n, 10);
+      buf[10] = tochar(n);
+      
+      n = t.tm_min;
+      buf[11] = next_char(&n, 10);
+      buf[12] = tochar(n);
+      
+      n = t.tm_sec;
+      buf[13] = next_char(&n, 10);
+      buf[14] = tochar(n);
+      bool inUtc = strcmp("UTC", timezone) == 0;
+      if (inUtc) {
+          buf[15] = 'Z';
+      }
+    }
+}
+
+String8 
+Time::toString() const
+{
+    String8 str;
+    char* s = str.lockBuffer(150);
+    #ifdef HAVE_TM_GMTOFF
+        long tm_gmtoff = t.tm_gmtoff;
+    #else
+        long tm_gmtoff = 0;
+    #endif
+    sprintf(s, "%04d%02d%02dT%02d%02d%02d%s(%d,%d,%ld,%d,%d)", 
+            t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min,
+            t.tm_sec, timezone, t.tm_wday, t.tm_yday, tm_gmtoff, t.tm_isdst,
+            (int)(((Time*)this)->toMillis(false /* use isDst */)/1000));
+    str.unlockBuffer();
+    return str;
+}
+
+void 
+Time::setToNow()
+{
+    time_t seconds;
+    time(&seconds);
+    localtime_tz(&seconds, &(this->t), this->timezone);
+}
+
+int64_t 
+Time::toMillis(bool ignoreDst)
+{
+    if (ignoreDst) {
+        this->t.tm_isdst = -1;
+    }
+    int64_t r = mktime_tz(&(this->t), this->timezone);
+    if (r == -1)
+        return -1;
+    return r * 1000;
+}
+
+void 
+Time::set(int64_t millis)
+{
+    time_t seconds = millis / 1000;
+    localtime_tz(&seconds, &(this->t), this->timezone);
+}
+
+}; // namespace android
+
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
new file mode 100644
index 0000000..cdb8ca2
--- /dev/null
+++ b/libs/utils/Android.mk
@@ -0,0 +1,156 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+# libutils is a little unique: It's built twice, once for the host
+# and once for the device.
+
+commonSources:= \
+	Asset.cpp \
+	AssetDir.cpp \
+	AssetManager.cpp \
+	BufferedTextOutput.cpp \
+	CallStack.cpp \
+	Debug.cpp \
+	FileMap.cpp \
+	RefBase.cpp \
+	ResourceTypes.cpp \
+	SharedBuffer.cpp \
+	Static.cpp \
+	StopWatch.cpp \
+	String8.cpp \
+	String16.cpp \
+	SystemClock.cpp \
+	TextOutput.cpp \
+	Threads.cpp \
+	TimerProbe.cpp \
+	Timers.cpp \
+	VectorImpl.cpp \
+    ZipFileCRO.cpp \
+	ZipFileRO.cpp \
+	ZipUtils.cpp \
+	misc.cpp \
+	ported.cpp \
+	LogSocket.cpp
+
+#
+# The cpp files listed here do not belong in the device
+# build.  Consult with the swetland before even thinking about
+# putting them in commonSources.
+#
+# They're used by the simulator runtime and by host-side tools like
+# aapt and the simulator front-end.
+#
+hostSources:= \
+	InetAddress.cpp \
+	Pipe.cpp \
+	Socket.cpp \
+	ZipEntry.cpp \
+	ZipFile.cpp
+
+# For the host
+# =====================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= $(commonSources) $(hostSources)
+
+ifeq ($(HOST_OS),linux)
+# Use the futex based mutex and condition variable
+# implementation from android-arm because it's shared mem safe
+	LOCAL_SRC_FILES += \
+		futex_synchro.c \
+		executablepath_linux.cpp
+endif
+ifeq ($(HOST_OS),darwin)
+	LOCAL_SRC_FILES += \
+		executablepath_darwin.cpp
+endif
+
+LOCAL_MODULE:= libutils
+
+LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)
+LOCAL_C_INCLUDES += external/zlib
+
+ifeq ($(HOST_OS),windows)
+ifeq ($(strip $(USE_CYGWIN),),)
+# Under MinGW, ctype.h doesn't need multi-byte support
+LOCAL_CFLAGS += -DMB_CUR_MAX=1
+endif
+endif
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+
+# we have the common sources, plus some device-specific stuff
+LOCAL_SRC_FILES:= \
+	$(commonSources) \
+	Binder.cpp \
+	BpBinder.cpp \
+	IInterface.cpp \
+	IMemory.cpp \
+	IPCThreadState.cpp \
+	MemoryDealer.cpp \
+    MemoryBase.cpp \
+    MemoryHeapBase.cpp \
+    MemoryHeapPmem.cpp \
+	Parcel.cpp \
+	ProcessState.cpp \
+	IPermissionController.cpp \
+	IServiceManager.cpp \
+	Unicode.cpp
+
+ifeq ($(TARGET_SIMULATOR),true)
+LOCAL_SRC_FILES += $(hostSources)
+endif
+
+ifeq ($(TARGET_OS),linux)
+# Use the futex based mutex and condition variable
+# implementation from android-arm because it's shared mem safe
+LOCAL_SRC_FILES += futex_synchro.c
+LOCAL_LDLIBS += -lrt -ldl
+endif
+
+LOCAL_C_INCLUDES += \
+		external/zlib \
+		external/icu4c/common
+LOCAL_LDLIBS += -lpthread
+
+LOCAL_SHARED_LIBRARIES := \
+	libz \
+	liblog \
+	libcutils
+
+ifneq ($(TARGET_SIMULATOR),true)
+ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86)
+# This is needed on x86 to bring in dl_iterate_phdr for CallStack.cpp
+LOCAL_SHARED_LIBRARIES += \
+	libdl
+endif # linux-x86
+endif # sim
+
+LOCAL_MODULE:= libutils
+
+#LOCAL_CFLAGS+=
+#LOCAL_LDFLAGS:=
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/libs/utils/Asset.cpp b/libs/utils/Asset.cpp
new file mode 100644
index 0000000..91203dd
--- /dev/null
+++ b/libs/utils/Asset.cpp
@@ -0,0 +1,813 @@
+/*
+ * 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.
+ */
+
+//
+// Provide access to a read-only asset.
+//
+
+#define LOG_TAG "asset"
+//#define NDEBUG 0
+
+#include <utils/Asset.h>
+#include <utils/Atomic.h>
+#include <utils/FileMap.h>
+#include <utils/ZipUtils.h>
+#include <utils/ZipFileRO.h>
+#include <utils/Log.h>
+
+#include <string.h>
+#include <memory.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+static volatile int32_t gCount = 0;
+
+int32_t Asset::getGlobalCount()
+{
+    return gCount;
+}
+
+Asset::Asset(void)
+    : mAccessMode(ACCESS_UNKNOWN)
+{
+    int count = android_atomic_inc(&gCount)+1;
+    //LOGI("Creating Asset %p #%d\n", this, count);
+}
+
+Asset::~Asset(void)
+{
+    int count = android_atomic_dec(&gCount);
+    //LOGI("Destroying Asset in %p #%d\n", this, count);
+}
+
+/*
+ * Create a new Asset from a file on disk.  There is a fair chance that
+ * the file doesn't actually exist.
+ *
+ * We can use "mode" to decide how we want to go about it.
+ */
+/*static*/ Asset* Asset::createFromFile(const char* fileName, AccessMode mode)
+{
+    _FileAsset* pAsset;
+    status_t result;
+    off_t length;
+    int fd;
+
+    fd = open(fileName, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return NULL;
+
+    /*
+     * Under Linux, the lseek fails if we actually opened a directory.  To
+     * be correct we should test the file type explicitly, but since we
+     * always open things read-only it doesn't really matter, so there's
+     * no value in incurring the extra overhead of an fstat() call.
+     */
+    length = lseek(fd, 0, SEEK_END);
+    if (length < 0) {
+        ::close(fd);
+        return NULL;
+    }
+    (void) lseek(fd, 0, SEEK_SET);
+
+    pAsset = new _FileAsset;
+    result = pAsset->openChunk(fileName, fd, 0, length);
+    if (result != NO_ERROR) {
+        delete pAsset;
+        return NULL;
+    }
+
+    pAsset->mAccessMode = mode;
+    return pAsset;
+}
+
+
+/*
+ * Create a new Asset from a compressed file on disk.  There is a fair chance
+ * that the file doesn't actually exist.
+ *
+ * We currently support gzip files.  We might want to handle .bz2 someday.
+ */
+/*static*/ Asset* Asset::createFromCompressedFile(const char* fileName,
+    AccessMode mode)
+{
+    _CompressedAsset* pAsset;
+    status_t result;
+    off_t fileLen;
+    bool scanResult;
+    long offset;
+    int method;
+    long uncompressedLen, compressedLen;
+    int fd;
+
+    fd = open(fileName, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return NULL;
+
+    fileLen = lseek(fd, 0, SEEK_END);
+    if (fileLen < 0) {
+        ::close(fd);
+        return NULL;
+    }
+    (void) lseek(fd, 0, SEEK_SET);
+
+    /* want buffered I/O for the file scan; must dup so fclose() is safe */
+    FILE* fp = fdopen(dup(fd), "rb");
+    if (fp == NULL) {
+        ::close(fd);
+        return NULL;
+    }
+
+    unsigned long crc32;
+    scanResult = ZipUtils::examineGzip(fp, &method, &uncompressedLen,
+                    &compressedLen, &crc32);
+    offset = ftell(fp);
+    fclose(fp);
+    if (!scanResult) {
+        LOGD("File '%s' is not in gzip format\n", fileName);
+        ::close(fd);
+        return NULL;
+    }
+
+    pAsset = new _CompressedAsset;
+    result = pAsset->openChunk(fd, offset, method, uncompressedLen,
+                compressedLen);
+    if (result != NO_ERROR) {
+        delete pAsset;
+        return NULL;
+    }
+
+    pAsset->mAccessMode = mode;
+    return pAsset;
+}
+
+
+#if 0
+/*
+ * Create a new Asset from part of an open file.
+ */
+/*static*/ Asset* Asset::createFromFileSegment(int fd, off_t offset,
+    size_t length, AccessMode mode)
+{
+    _FileAsset* pAsset;
+    status_t result;
+
+    pAsset = new _FileAsset;
+    result = pAsset->openChunk(NULL, fd, offset, length);
+    if (result != NO_ERROR)
+        return NULL;
+
+    pAsset->mAccessMode = mode;
+    return pAsset;
+}
+
+/*
+ * Create a new Asset from compressed data in an open file.
+ */
+/*static*/ Asset* Asset::createFromCompressedData(int fd, off_t offset,
+    int compressionMethod, size_t uncompressedLen, size_t compressedLen,
+    AccessMode mode)
+{
+    _CompressedAsset* pAsset;
+    status_t result;
+
+    pAsset = new _CompressedAsset;
+    result = pAsset->openChunk(fd, offset, compressionMethod,
+                uncompressedLen, compressedLen);
+    if (result != NO_ERROR)
+        return NULL;
+
+    pAsset->mAccessMode = mode;
+    return pAsset;
+}
+#endif
+
+/*
+ * Create a new Asset from a memory mapping.
+ */
+/*static*/ Asset* Asset::createFromUncompressedMap(FileMap* dataMap,
+    AccessMode mode)
+{
+    _FileAsset* pAsset;
+    status_t result;
+
+    pAsset = new _FileAsset;
+    result = pAsset->openChunk(dataMap);
+    if (result != NO_ERROR)
+        return NULL;
+
+    pAsset->mAccessMode = mode;
+    return pAsset;
+}
+
+/*
+ * Create a new Asset from compressed data in a memory mapping.
+ */
+/*static*/ Asset* Asset::createFromCompressedMap(FileMap* dataMap,
+    int method, size_t uncompressedLen, AccessMode mode)
+{
+    _CompressedAsset* pAsset;
+    status_t result;
+
+    pAsset = new _CompressedAsset;
+    result = pAsset->openChunk(dataMap, method, uncompressedLen);
+    if (result != NO_ERROR)
+        return NULL;
+
+    pAsset->mAccessMode = mode;
+    return pAsset;
+}
+
+
+/*
+ * Do generic seek() housekeeping.  Pass in the offset/whence values from
+ * the seek request, along with the current chunk offset and the chunk
+ * length.
+ *
+ * Returns the new chunk offset, or -1 if the seek is illegal.
+ */
+off_t Asset::handleSeek(off_t offset, int whence, off_t curPosn, off_t maxPosn)
+{
+    off_t newOffset;
+
+    switch (whence) {
+    case SEEK_SET:
+        newOffset = offset;
+        break;
+    case SEEK_CUR:
+        newOffset = curPosn + offset;
+        break;
+    case SEEK_END:
+        newOffset = maxPosn + offset;
+        break;
+    default:
+        LOGW("unexpected whence %d\n", whence);
+        // this was happening due to an off_t size mismatch
+        assert(false);
+        return (off_t) -1;
+    }
+
+    if (newOffset < 0 || newOffset > maxPosn) {
+        LOGW("seek out of range: want %ld, end=%ld\n",
+            (long) newOffset, (long) maxPosn);
+        return (off_t) -1;
+    }
+
+    return newOffset;
+}
+
+
+/*
+ * ===========================================================================
+ *      _FileAsset
+ * ===========================================================================
+ */
+
+/*
+ * Constructor.
+ */
+_FileAsset::_FileAsset(void)
+    : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mMap(NULL), mBuf(NULL)
+{
+}
+
+/*
+ * Destructor.  Release resources.
+ */
+_FileAsset::~_FileAsset(void)
+{
+    close();
+}
+
+/*
+ * Operate on a chunk of an uncompressed file.
+ *
+ * Zero-length chunks are allowed.
+ */
+status_t _FileAsset::openChunk(const char* fileName, int fd, off_t offset, size_t length)
+{
+    assert(mFp == NULL);    // no reopen
+    assert(mMap == NULL);
+    assert(fd >= 0);
+    assert(offset >= 0);
+
+    /*
+     * Seek to end to get file length.
+     */
+    off_t fileLength;
+    fileLength = lseek(fd, 0, SEEK_END);
+    if (fileLength == (off_t) -1) {
+        // probably a bad file descriptor
+        LOGD("failed lseek (errno=%d)\n", errno);
+        return UNKNOWN_ERROR;
+    }
+
+    if ((off_t) (offset + length) > fileLength) {
+        LOGD("start (%ld) + len (%ld) > end (%ld)\n",
+            (long) offset, (long) length, (long) fileLength);
+        return BAD_INDEX;
+    }
+
+    /* after fdopen, the fd will be closed on fclose() */
+    mFp = fdopen(fd, "rb");
+    if (mFp == NULL)
+        return UNKNOWN_ERROR;
+
+    mStart = offset;
+    mLength = length;
+    assert(mOffset == 0);
+
+    /* seek the FILE* to the start of chunk */
+    if (fseek(mFp, mStart, SEEK_SET) != 0) {
+        assert(false);
+    }
+
+    mFileName = fileName != NULL ? strdup(fileName) : NULL;
+    
+    return NO_ERROR;
+}
+
+/*
+ * Create the chunk from the map.
+ */
+status_t _FileAsset::openChunk(FileMap* dataMap)
+{
+    assert(mFp == NULL);    // no reopen
+    assert(mMap == NULL);
+    assert(dataMap != NULL);
+
+    mMap = dataMap;
+    mStart = -1;            // not used
+    mLength = dataMap->getDataLength();
+    assert(mOffset == 0);
+
+    return NO_ERROR;
+}
+
+/*
+ * Read a chunk of data.
+ */
+ssize_t _FileAsset::read(void* buf, size_t count)
+{
+    size_t maxLen;
+    size_t actual;
+
+    assert(mOffset >= 0 && mOffset <= mLength);
+
+    if (getAccessMode() == ACCESS_BUFFER) {
+        /*
+         * On first access, read or map the entire file.  The caller has
+         * requested buffer access, either because they're going to be
+         * using the buffer or because what they're doing has appropriate
+         * performance needs and access patterns.
+         */
+        if (mBuf == NULL)
+            getBuffer(false);
+    }
+
+    /* adjust count if we're near EOF */
+    maxLen = mLength - mOffset;
+    if (count > maxLen)
+        count = maxLen;
+
+    if (!count)
+        return 0;
+
+    if (mMap != NULL) {
+        /* copy from mapped area */
+        //printf("map read\n");
+        memcpy(buf, (char*)mMap->getDataPtr() + mOffset, count);
+        actual = count;
+    } else if (mBuf != NULL) {
+        /* copy from buffer */
+        //printf("buf read\n");
+        memcpy(buf, (char*)mBuf + mOffset, count);
+        actual = count;
+    } else {
+        /* read from the file */
+        //printf("file read\n");
+        if (ftell(mFp) != mStart + mOffset) {
+            LOGE("Hosed: %ld != %ld+%ld\n",
+                ftell(mFp), (long) mStart, (long) mOffset);
+            assert(false);
+        }
+
+        /*
+         * This returns 0 on error or eof.  We need to use ferror() or feof()
+         * to tell the difference, but we don't currently have those on the
+         * device.  However, we know how much data is *supposed* to be in the
+         * file, so if we don't read the full amount we know something is
+         * hosed.
+         */
+        actual = fread(buf, 1, count, mFp);
+        if (actual == 0)        // something failed -- I/O error?
+            return -1;
+
+        assert(actual == count);
+    }
+
+    mOffset += actual;
+    return actual;
+}
+
+/*
+ * Seek to a new position.
+ */
+off_t _FileAsset::seek(off_t offset, int whence)
+{
+    off_t newPosn;
+    long actualOffset;
+
+    // compute new position within chunk
+    newPosn = handleSeek(offset, whence, mOffset, mLength);
+    if (newPosn == (off_t) -1)
+        return newPosn;
+
+    actualOffset = (long) (mStart + newPosn);
+
+    if (mFp != NULL) {
+        if (fseek(mFp, (long) actualOffset, SEEK_SET) != 0)
+            return (off_t) -1;
+    }
+
+    mOffset = actualOffset - mStart;
+    return mOffset;
+}
+
+/*
+ * Close the asset.
+ */
+void _FileAsset::close(void)
+{
+    if (mMap != NULL) {
+        mMap->release();
+        mMap = NULL;
+    }
+    if (mBuf != NULL) {
+        delete[] mBuf;
+        mBuf = NULL;
+    }
+
+    if (mFileName != NULL) {
+        free(mFileName);
+        mFileName = NULL;
+    }
+    
+    if (mFp != NULL) {
+        // can only be NULL when called from destructor
+        // (otherwise we would never return this object)
+        fclose(mFp);
+        mFp = NULL;
+    }
+}
+
+/*
+ * Return a read-only pointer to a buffer.
+ *
+ * We can either read the whole thing in or map the relevant piece of
+ * the source file.  Ideally a map would be established at a higher
+ * level and we'd be using a different object, but we didn't, so we
+ * deal with it here.
+ */
+const void* _FileAsset::getBuffer(bool wordAligned)
+{
+    /* subsequent requests just use what we did previously */
+    if (mBuf != NULL)
+        return mBuf;
+    if (mMap != NULL) {
+        if (!wordAligned) {
+            return  mMap->getDataPtr();
+        }
+        return ensureAlignment(mMap);
+    }
+
+    assert(mFp != NULL);
+
+    if (mLength < kReadVsMapThreshold) {
+        unsigned char* buf;
+        long allocLen;
+
+        /* zero-length files are allowed; not sure about zero-len allocs */
+        /* (works fine with gcc + x86linux) */
+        allocLen = mLength;
+        if (mLength == 0)
+            allocLen = 1;
+
+        buf = new unsigned char[allocLen];
+        if (buf == NULL) {
+            LOGE("alloc of %ld bytes failed\n", (long) allocLen);
+            return NULL;
+        }
+
+        LOGV("Asset %p allocating buffer size %d (smaller than threshold)", this, (int)allocLen);
+        if (mLength > 0) {
+            long oldPosn = ftell(mFp);
+            fseek(mFp, mStart, SEEK_SET);
+            if (fread(buf, 1, mLength, mFp) != (size_t) mLength) {
+                LOGE("failed reading %ld bytes\n", (long) mLength);
+                delete[] buf;
+                return NULL;
+            }
+            fseek(mFp, oldPosn, SEEK_SET);
+        }
+
+        LOGV(" getBuffer: loaded into buffer\n");
+
+        mBuf = buf;
+        return mBuf;
+    } else {
+        FileMap* map;
+
+        map = new FileMap;
+        if (!map->create(NULL, fileno(mFp), mStart, mLength, true)) {
+            map->release();
+            return NULL;
+        }
+
+        LOGV(" getBuffer: mapped\n");
+
+        mMap = map;
+        if (!wordAligned) {
+            return  mMap->getDataPtr();
+        }
+        return ensureAlignment(mMap);
+    }
+}
+
+int _FileAsset::openFileDescriptor(off_t* outStart, off_t* outLength) const
+{
+    if (mMap != NULL) {
+        const char* fname = mMap->getFileName();
+        if (fname == NULL) {
+            fname = mFileName;
+        }
+        if (fname == NULL) {
+            return -1;
+        }
+        *outStart = mMap->getDataOffset();
+        *outLength = mMap->getDataLength();
+        return open(fname, O_RDONLY | O_BINARY);
+    }
+    if (mFileName == NULL) {
+        return -1;
+    }
+    *outStart = mStart;
+    *outLength = mLength;
+    return open(mFileName, O_RDONLY | O_BINARY);
+}
+
+const void* _FileAsset::ensureAlignment(FileMap* map)
+{
+    void* data = map->getDataPtr();
+    if ((((size_t)data)&0x3) == 0) {
+        // We can return this directly if it is aligned on a word
+        // boundary.
+        return data;
+    }
+    // If not aligned on a word boundary, then we need to copy it into
+    // our own buffer.
+    LOGV("Copying FileAsset %p to buffer size %d to make it aligned.", this, (int)mLength);
+    unsigned char* buf = new unsigned char[mLength];
+    if (buf == NULL) {
+        LOGE("alloc of %ld bytes failed\n", (long) mLength);
+        return NULL;
+    }
+    memcpy(buf, data, mLength);
+    mBuf = buf;
+    return buf;
+}
+
+/*
+ * ===========================================================================
+ *      _CompressedAsset
+ * ===========================================================================
+ */
+
+/*
+ * Constructor.
+ */
+_CompressedAsset::_CompressedAsset(void)
+    : mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0),
+      mMap(NULL), mFd(-1), mBuf(NULL)
+{
+}
+
+/*
+ * Destructor.  Release resources.
+ */
+_CompressedAsset::~_CompressedAsset(void)
+{
+    close();
+}
+
+/*
+ * Open a chunk of compressed data inside a file.
+ *
+ * This currently just sets up some values and returns.  On the first
+ * read, we expand the entire file into a buffer and return data from it.
+ */
+status_t _CompressedAsset::openChunk(int fd, off_t offset,
+    int compressionMethod, size_t uncompressedLen, size_t compressedLen)
+{
+    assert(mFd < 0);        // no re-open
+    assert(mMap == NULL);
+    assert(fd >= 0);
+    assert(offset >= 0);
+    assert(compressedLen > 0);
+
+    if (compressionMethod != ZipFileRO::kCompressDeflated) {
+        assert(false);
+        return UNKNOWN_ERROR;
+    }
+
+    mStart = offset;
+    mCompressedLen = compressedLen;
+    mUncompressedLen = uncompressedLen;
+    assert(mOffset == 0);
+    mFd = fd;
+    assert(mBuf == NULL);
+
+    return NO_ERROR;
+}
+
+/*
+ * Open a chunk of compressed data in a mapped region.
+ *
+ * Nothing is expanded until the first read call.
+ */
+status_t _CompressedAsset::openChunk(FileMap* dataMap, int compressionMethod,
+    size_t uncompressedLen)
+{
+    assert(mFd < 0);        // no re-open
+    assert(mMap == NULL);
+    assert(dataMap != NULL);
+
+    if (compressionMethod != ZipFileRO::kCompressDeflated) {
+        assert(false);
+        return UNKNOWN_ERROR;
+    }
+
+    mMap = dataMap;
+    mStart = -1;        // not used
+    mCompressedLen = dataMap->getDataLength();
+    mUncompressedLen = uncompressedLen;
+    assert(mOffset == 0);
+
+    return NO_ERROR;
+}
+
+/*
+ * Read data from a chunk of compressed data.
+ *
+ * [For now, that's just copying data out of a buffer.]
+ */
+ssize_t _CompressedAsset::read(void* buf, size_t count)
+{
+    size_t maxLen;
+    size_t actual;
+
+    assert(mOffset >= 0 && mOffset <= mUncompressedLen);
+
+    // TODO: if mAccessMode == ACCESS_STREAMING, use zlib more cleverly
+
+    if (mBuf == NULL) {
+        if (getBuffer(false) == NULL)
+            return -1;
+    }
+    assert(mBuf != NULL);
+
+    /* adjust count if we're near EOF */
+    maxLen = mUncompressedLen - mOffset;
+    if (count > maxLen)
+        count = maxLen;
+
+    if (!count)
+        return 0;
+
+    /* copy from buffer */
+    //printf("comp buf read\n");
+    memcpy(buf, (char*)mBuf + mOffset, count);
+    actual = count;
+
+    mOffset += actual;
+    return actual;
+}
+
+/*
+ * Handle a seek request.
+ *
+ * If we're working in a streaming mode, this is going to be fairly
+ * expensive, because it requires plowing through a bunch of compressed
+ * data.
+ */
+off_t _CompressedAsset::seek(off_t offset, int whence)
+{
+    off_t newPosn;
+
+    // compute new position within chunk
+    newPosn = handleSeek(offset, whence, mOffset, mUncompressedLen);
+    if (newPosn == (off_t) -1)
+        return newPosn;
+
+    mOffset = newPosn;
+    return mOffset;
+}
+
+/*
+ * Close the asset.
+ */
+void _CompressedAsset::close(void)
+{
+    if (mMap != NULL) {
+        mMap->release();
+        mMap = NULL;
+    }
+    if (mBuf != NULL) {
+        delete[] mBuf;
+        mBuf = NULL;
+    }
+
+    if (mFd > 0) {
+        ::close(mFd);
+        mFd = -1;
+    }
+}
+
+/*
+ * Get a pointer to a read-only buffer of data.
+ *
+ * The first time this is called, we expand the compressed data into a
+ * buffer.
+ */
+const void* _CompressedAsset::getBuffer(bool wordAligned)
+{
+    unsigned char* buf = NULL;
+
+    if (mBuf != NULL)
+        return mBuf;
+
+    if (mUncompressedLen > UNCOMPRESS_DATA_MAX) {
+        LOGD("Data exceeds UNCOMPRESS_DATA_MAX (%ld vs %d)\n",
+            (long) mUncompressedLen, UNCOMPRESS_DATA_MAX);
+        goto bail;
+    }
+
+    /*
+     * Allocate a buffer and read the file into it.
+     */
+    buf = new unsigned char[mUncompressedLen];
+    if (buf == NULL) {
+        LOGW("alloc %ld bytes failed\n", (long) mUncompressedLen);
+        goto bail;
+    }
+
+    if (mMap != NULL) {
+        if (!ZipFileRO::inflateBuffer(buf, mMap->getDataPtr(),
+                mUncompressedLen, mCompressedLen))
+            goto bail;
+    } else {
+        assert(mFd >= 0);
+
+        /*
+         * Seek to the start of the compressed data.
+         */
+        if (lseek(mFd, mStart, SEEK_SET) != mStart)
+            goto bail;
+
+        /*
+         * Expand the data into it.
+         */
+        if (!ZipUtils::inflateToBuffer(mFd, buf, mUncompressedLen,
+                mCompressedLen))
+            goto bail;
+    }
+
+    /* success! */
+    mBuf = buf;
+    buf = NULL;
+
+bail:
+    delete[] buf;
+    return mBuf;
+}
+
diff --git a/libs/utils/AssetDir.cpp b/libs/utils/AssetDir.cpp
new file mode 100644
index 0000000..c5f664e
--- /dev/null
+++ b/libs/utils/AssetDir.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+//
+// Provide access to a virtual directory in "asset space".  Most of the
+// implementation is in the header file or in friend functions in
+// AssetManager.
+//
+#include <utils/AssetDir.h>
+
+using namespace android;
+
+
+/*
+ * Find a matching entry in a vector of FileInfo.  Because it's sorted, we
+ * can use a binary search.
+ *
+ * Assumes the vector is sorted in ascending order.
+ */
+/*static*/ int AssetDir::FileInfo::findEntry(const SortedVector<FileInfo>* pVector,
+    const String8& fileName)
+{
+    FileInfo tmpInfo;
+
+    tmpInfo.setFileName(fileName);
+    return pVector->indexOf(tmpInfo);
+
+#if 0  // don't need this after all (uses 1/2 compares of SortedVector though)
+    int lo, hi, cur;
+
+    lo = 0;
+    hi = pVector->size() -1;
+    while (lo <= hi) {
+        int cmp;
+
+        cur = (hi + lo) / 2;
+        cmp = strcmp(pVector->itemAt(cur).getFileName(), fileName);
+        if (cmp == 0) {
+            /* match, bail */
+            return cur;
+        } else if (cmp < 0) {
+            /* too low */
+            lo = cur + 1;
+        } else {
+            /* too high */
+            hi = cur -1;
+        }
+    }
+
+    return -1;
+#endif
+}
+
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
new file mode 100644
index 0000000..447b801
--- /dev/null
+++ b/libs/utils/AssetManager.cpp
@@ -0,0 +1,1637 @@
+/*
+ * 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.
+ */
+
+//
+// Provide access to read-only assets.
+//
+
+#define LOG_TAG "asset"
+//#define LOG_NDEBUG 0
+
+#include <utils/AssetManager.h>
+#include <utils/AssetDir.h>
+#include <utils/Asset.h>
+#include <utils/Atomic.h>
+#include <utils/String8.h>
+#include <utils/ResourceTypes.h>
+#include <utils/String8.h>
+#include <utils/ZipFileRO.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <utils/threads.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Names for default app, locale, and vendor.  We might want to change
+ * these to be an actual locale, e.g. always use en-US as the default.
+ */
+static const char* kDefaultLocale = "default";
+static const char* kDefaultVendor = "default";
+static const char* kAssetsRoot = "assets";
+static const char* kAppZipName = NULL; //"classes.jar";
+static const char* kSystemAssets = "framework/framework-res.apk";
+
+static const char* kExcludeExtension = ".EXCLUDE";
+
+static Asset* const kExcludedAsset = (Asset*) 0xd000000d;
+
+static volatile int32_t gCount = 0;
+
+
+/*
+ * ===========================================================================
+ *      AssetManager
+ * ===========================================================================
+ */
+
+int32_t AssetManager::getGlobalCount()
+{
+    return gCount;
+}
+
+AssetManager::AssetManager(CacheMode cacheMode)
+    : mLocale(NULL), mVendor(NULL),
+      mResources(NULL), mConfig(new ResTable_config),
+      mCacheMode(cacheMode), mCacheValid(false)
+{
+    int count = android_atomic_inc(&gCount)+1;
+    //LOGI("Creating AssetManager %p #%d\n", this, count);
+    memset(mConfig, 0, sizeof(ResTable_config));
+}
+
+AssetManager::~AssetManager(void)
+{
+    int count = android_atomic_dec(&gCount);
+    //LOGI("Destroying AssetManager in %p #%d\n", this, count);
+
+    delete mConfig;
+    delete mResources;
+
+    // don't have a String class yet, so make sure we clean up
+    delete[] mLocale;
+    delete[] mVendor;
+}
+
+bool AssetManager::addAssetPath(const String8& path, void** cookie)
+{
+    AutoMutex _l(mLock);
+
+    asset_path ap;
+
+    String8 realPath(path);
+    if (kAppZipName) {
+        realPath.appendPath(kAppZipName);
+    }
+    ap.type = ::getFileType(realPath.string());
+    if (ap.type == kFileTypeRegular) {
+        ap.path = realPath;
+    } else {
+        ap.path = path;
+        ap.type = ::getFileType(path.string());
+        if (ap.type != kFileTypeDirectory && ap.type != kFileTypeRegular) {
+            LOGW("Asset path %s is neither a directory nor file (type=%d).",
+                 path.string(), (int)ap.type);
+            return false;
+        }
+    }
+
+    // Skip if we have it already.
+    for (size_t i=0; i<mAssetPaths.size(); i++) {
+        if (mAssetPaths[i].path == ap.path) {
+            if (cookie) {
+                *cookie = (void*)(i+1);
+            }
+            return true;
+        }
+    }
+    
+    LOGV("In %p Asset %s path: %s", this,
+         ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
+
+    mAssetPaths.add(ap);
+
+    // new paths are always added at the end
+    if (cookie) {
+        *cookie = (void*)mAssetPaths.size();
+    }
+
+    return true;
+}
+
+bool AssetManager::addDefaultAssets()
+{
+    const char* root = getenv("ANDROID_ROOT");
+    LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set");
+
+    String8 path(root);
+    path.appendPath(kSystemAssets);
+
+    return addAssetPath(path, NULL);
+}
+
+void* AssetManager::nextAssetPath(void* cookie) const
+{
+    AutoMutex _l(mLock);
+    size_t next = ((size_t)cookie)+1;
+    return next > mAssetPaths.size() ? NULL : (void*)next;
+}
+
+String8 AssetManager::getAssetPath(void* cookie) const
+{
+    AutoMutex _l(mLock);
+    const size_t which = ((size_t)cookie)-1;
+    if (which < mAssetPaths.size()) {
+        return mAssetPaths[which].path;
+    }
+    return String8();
+}
+
+/*
+ * Set the current locale.  Use NULL to indicate no locale.
+ *
+ * Close and reopen Zip archives as appropriate, and reset cached
+ * information in the locale-specific sections of the tree.
+ */
+void AssetManager::setLocale(const char* locale)
+{
+    AutoMutex _l(mLock);
+    setLocaleLocked(locale);
+}
+
+void AssetManager::setLocaleLocked(const char* locale)
+{
+    if (mLocale != NULL) {
+        /* previously set, purge cached data */
+        purgeFileNameCacheLocked();
+        //mZipSet.purgeLocale();
+        delete[] mLocale;
+    }
+    mLocale = strdupNew(locale);
+    
+    updateResourceParamsLocked();
+}
+
+/*
+ * Set the current vendor.  Use NULL to indicate no vendor.
+ *
+ * Close and reopen Zip archives as appropriate, and reset cached
+ * information in the vendor-specific sections of the tree.
+ */
+void AssetManager::setVendor(const char* vendor)
+{
+    AutoMutex _l(mLock);
+
+    if (mVendor != NULL) {
+        /* previously set, purge cached data */
+        purgeFileNameCacheLocked();
+        //mZipSet.purgeVendor();
+        delete[] mVendor;
+    }
+    mVendor = strdupNew(vendor);
+}
+
+void AssetManager::setConfiguration(const ResTable_config& config, const char* locale)
+{
+    AutoMutex _l(mLock);
+    *mConfig = config;
+    if (locale) {
+        setLocaleLocked(locale);
+    } else if (config.language[0] != 0) {
+        char spec[9];
+        spec[0] = config.language[0];
+        spec[1] = config.language[1];
+        if (config.country[0] != 0) {
+            spec[2] = '_';
+            spec[3] = config.country[0];
+            spec[4] = config.country[1];
+            spec[5] = 0;
+        } else {
+            spec[3] = 0;
+        }
+        setLocaleLocked(spec);
+    } else {
+        updateResourceParamsLocked();
+    }
+}
+
+/*
+ * Open an asset.
+ *
+ * The data could be;
+ *  - In a file on disk (assetBase + fileName).
+ *  - In a compressed file on disk (assetBase + fileName.gz).
+ *  - In a Zip archive, uncompressed or compressed.
+ *
+ * It can be in a number of different directories and Zip archives.
+ * The search order is:
+ *  - [appname]
+ *    - locale + vendor
+ *    - "default" + vendor
+ *    - locale + "default"
+ *    - "default + "default"
+ *  - "common"
+ *    - (same as above)
+ *
+ * To find a particular file, we have to try up to eight paths with
+ * all three forms of data.
+ *
+ * We should probably reject requests for "illegal" filenames, e.g. those
+ * with illegal characters or "../" backward relative paths.
+ */
+Asset* AssetManager::open(const char* fileName, AccessMode mode)
+{
+    AutoMutex _l(mLock);
+
+    LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+
+
+    if (mCacheMode != CACHE_OFF && !mCacheValid)
+        loadFileNameCacheLocked();
+
+    String8 assetName(kAssetsRoot);
+    assetName.appendPath(fileName);
+
+    /*
+     * For each top-level asset path, search for the asset.
+     */
+
+    size_t i = mAssetPaths.size();
+    while (i > 0) {
+        i--;
+        LOGV("Looking for asset '%s' in '%s'\n",
+                assetName.string(), mAssetPaths.itemAt(i).path.string());
+        Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, mAssetPaths.itemAt(i));
+        if (pAsset != NULL) {
+            return pAsset != kExcludedAsset ? pAsset : NULL;
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Open a non-asset file as if it were an asset.
+ *
+ * The "fileName" is the partial path starting from the application
+ * name.
+ */
+Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode)
+{
+    AutoMutex _l(mLock);
+
+    LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+
+
+    if (mCacheMode != CACHE_OFF && !mCacheValid)
+        loadFileNameCacheLocked();
+
+    /*
+     * For each top-level asset path, search for the asset.
+     */
+
+    size_t i = mAssetPaths.size();
+    while (i > 0) {
+        i--;
+        LOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.string());
+        Asset* pAsset = openNonAssetInPathLocked(
+            fileName, mode, mAssetPaths.itemAt(i));
+        if (pAsset != NULL) {
+            return pAsset != kExcludedAsset ? pAsset : NULL;
+        }
+    }
+
+    return NULL;
+}
+
+Asset* AssetManager::openNonAsset(void* cookie, const char* fileName, AccessMode mode)
+{
+    const size_t which = ((size_t)cookie)-1;
+
+    AutoMutex _l(mLock);
+
+    LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+
+
+    if (mCacheMode != CACHE_OFF && !mCacheValid)
+        loadFileNameCacheLocked();
+
+    if (which < mAssetPaths.size()) {
+        LOGV("Looking for non-asset '%s' in '%s'\n", fileName,
+                mAssetPaths.itemAt(which).path.string());
+        Asset* pAsset = openNonAssetInPathLocked(
+            fileName, mode, mAssetPaths.itemAt(which));
+        if (pAsset != NULL) {
+            return pAsset != kExcludedAsset ? pAsset : NULL;
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Get the type of a file in the asset namespace.
+ *
+ * This currently only works for regular files.  All others (including
+ * directories) will return kFileTypeNonexistent.
+ */
+FileType AssetManager::getFileType(const char* fileName)
+{
+    Asset* pAsset = NULL;
+
+    /*
+     * Open the asset.  This is less efficient than simply finding the
+     * file, but it's not too bad (we don't uncompress or mmap data until
+     * the first read() call).
+     */
+    pAsset = open(fileName, Asset::ACCESS_STREAMING);
+    delete pAsset;
+
+    if (pAsset == NULL)
+        return kFileTypeNonexistent;
+    else
+        return kFileTypeRegular;
+}
+
+const ResTable* AssetManager::getResTable(bool required) const
+{
+    ResTable* rt = mResources;
+    if (rt) {
+        return rt;
+    }
+
+    // Iterate through all asset packages, collecting resources from each.
+
+    AutoMutex _l(mLock);
+
+    if (mResources != NULL) {
+        return mResources;
+    }
+
+    if (required) {
+        LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+    }
+
+    if (mCacheMode != CACHE_OFF && !mCacheValid)
+        const_cast<AssetManager*>(this)->loadFileNameCacheLocked();
+
+    const size_t N = mAssetPaths.size();
+    for (size_t i=0; i<N; i++) {
+        Asset* ass = NULL;
+        bool shared = true;
+        const asset_path& ap = mAssetPaths.itemAt(i);
+        LOGV("Looking for resource asset in '%s'\n", ap.path.string());
+        if (ap.type != kFileTypeDirectory) {
+            ass = const_cast<AssetManager*>(this)->
+                mZipSet.getZipResourceTable(ap.path);
+            if (ass == NULL) {
+                LOGV("loading resource table %s\n", ap.path.string());
+                ass = const_cast<AssetManager*>(this)->
+                    openNonAssetInPathLocked("resources.arsc",
+                                             Asset::ACCESS_BUFFER,
+                                             ap);
+                if (ass != NULL && ass != kExcludedAsset) {
+                    ass = const_cast<AssetManager*>(this)->
+                        mZipSet.setZipResourceTable(ap.path, ass);
+                }
+            }
+        } else {
+            LOGV("loading resource table %s\n", ap.path.string());
+            Asset* ass = const_cast<AssetManager*>(this)->
+                openNonAssetInPathLocked("resources.arsc",
+                                         Asset::ACCESS_BUFFER,
+                                         ap);
+            shared = false;
+        }
+        if (ass != NULL && ass != kExcludedAsset) {
+            if (rt == NULL) {
+                mResources = rt = new ResTable();
+                updateResourceParamsLocked();
+            }
+            LOGV("Installing resource asset %p in to table %p\n", ass, mResources);
+            rt->add(ass, (void*)(i+1), !shared);
+
+            if (!shared) {
+                delete ass;
+            }
+        }
+    }
+
+    if (required && !rt) LOGW("Unable to find resources file resources.arsc");
+    if (!rt) {
+        mResources = rt = new ResTable();
+    }
+    return rt;
+}
+
+void AssetManager::updateResourceParamsLocked() const
+{
+    ResTable* res = mResources;
+    if (!res) {
+        return;
+    }
+
+    size_t llen = mLocale ? strlen(mLocale) : 0;
+    mConfig->language[0] = 0;
+    mConfig->language[1] = 0;
+    mConfig->country[0] = 0;
+    mConfig->country[1] = 0;
+    if (llen >= 2) {
+        mConfig->language[0] = mLocale[0];
+        mConfig->language[1] = mLocale[1];
+    }
+    if (llen >= 5) {
+        mConfig->country[0] = mLocale[3];
+        mConfig->country[1] = mLocale[4];
+    }
+    mConfig->size = sizeof(*mConfig);
+
+    res->setParameters(mConfig);
+}
+
+const ResTable& AssetManager::getResources(bool required) const
+{
+    const ResTable* rt = getResTable(required);
+    return *rt;
+}
+
+bool AssetManager::isUpToDate()
+{
+    AutoMutex _l(mLock);
+    return mZipSet.isUpToDate();
+}
+
+void AssetManager::getLocales(Vector<String8>* locales) const
+{
+    ResTable* res = mResources;
+    if (res != NULL) {
+        res->getLocales(locales);
+    }
+}
+
+/*
+ * Open a non-asset file as if it were an asset, searching for it in the
+ * specified app.
+ *
+ * Pass in a NULL values for "appName" if the common app directory should
+ * be used.
+ */
+Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode mode,
+    const asset_path& ap)
+{
+    Asset* pAsset = NULL;
+
+    /* look at the filesystem on disk */
+    if (ap.type == kFileTypeDirectory) {
+        String8 path(ap.path);
+        path.appendPath(fileName);
+
+        pAsset = openAssetFromFileLocked(path, mode);
+
+        if (pAsset == NULL) {
+            /* try again, this time with ".gz" */
+            path.append(".gz");
+            pAsset = openAssetFromFileLocked(path, mode);
+        }
+
+        if (pAsset != NULL) {
+            //printf("FOUND NA '%s' on disk\n", fileName);
+            pAsset->setAssetSource(path);
+        }
+
+    /* look inside the zip file */
+    } else {
+        String8 path(fileName);
+
+        /* check the appropriate Zip file */
+        ZipFileRO* pZip;
+        ZipEntryRO entry;
+
+        pZip = getZipFileLocked(ap);
+        if (pZip != NULL) {
+            //printf("GOT zip, checking NA '%s'\n", (const char*) path);
+            entry = pZip->findEntryByName(path.string());
+            if (entry != NULL) {
+                //printf("FOUND NA in Zip file for %s\n", appName ? appName : kAppCommon);
+                pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
+            }
+        }
+
+        if (pAsset != NULL) {
+            /* create a "source" name, for debug/display */
+            pAsset->setAssetSource(
+                    createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()), String8(""),
+                                                String8(fileName)));
+        }
+    }
+
+    return pAsset;
+}
+
+/*
+ * Open an asset, searching for it in the directory hierarchy for the
+ * specified app.
+ *
+ * Pass in a NULL values for "appName" if the common app directory should
+ * be used.
+ */
+Asset* AssetManager::openInPathLocked(const char* fileName, AccessMode mode,
+    const asset_path& ap)
+{
+    Asset* pAsset = NULL;
+
+    /*
+     * Try various combinations of locale and vendor.
+     */
+    if (mLocale != NULL && mVendor != NULL)
+        pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, mVendor);
+    if (pAsset == NULL && mVendor != NULL)
+        pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, mVendor);
+    if (pAsset == NULL && mLocale != NULL)
+        pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, NULL);
+    if (pAsset == NULL)
+        pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, NULL);
+
+    return pAsset;
+}
+
+/*
+ * Open an asset, searching for it in the directory hierarchy for the
+ * specified locale and vendor.
+ *
+ * We also search in "app.jar".
+ *
+ * Pass in NULL values for "appName", "locale", and "vendor" if the
+ * defaults should be used.
+ */
+Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode mode,
+    const asset_path& ap, const char* locale, const char* vendor)
+{
+    Asset* pAsset = NULL;
+
+    if (ap.type == kFileTypeDirectory) {
+        if (mCacheMode == CACHE_OFF) {
+            /* look at the filesystem on disk */
+            String8 path(createPathNameLocked(ap, locale, vendor));
+            path.appendPath(fileName);
+    
+            String8 excludeName(path);
+            excludeName.append(kExcludeExtension);
+            if (::getFileType(excludeName.string()) != kFileTypeNonexistent) {
+                /* say no more */
+                //printf("+++ excluding '%s'\n", (const char*) excludeName);
+                return kExcludedAsset;
+            }
+    
+            pAsset = openAssetFromFileLocked(path, mode);
+    
+            if (pAsset == NULL) {
+                /* try again, this time with ".gz" */
+                path.append(".gz");
+                pAsset = openAssetFromFileLocked(path, mode);
+            }
+    
+            if (pAsset != NULL)
+                pAsset->setAssetSource(path);
+        } else {
+            /* find in cache */
+            String8 path(createPathNameLocked(ap, locale, vendor));
+            path.appendPath(fileName);
+    
+            AssetDir::FileInfo tmpInfo;
+            bool found = false;
+    
+            String8 excludeName(path);
+            excludeName.append(kExcludeExtension);
+    
+            if (mCache.indexOf(excludeName) != NAME_NOT_FOUND) {
+                /* go no farther */
+                //printf("+++ Excluding '%s'\n", (const char*) excludeName);
+                return kExcludedAsset;
+            }
+
+            /*
+             * File compression extensions (".gz") don't get stored in the
+             * name cache, so we have to try both here.
+             */
+            if (mCache.indexOf(path) != NAME_NOT_FOUND) {
+                found = true;
+                pAsset = openAssetFromFileLocked(path, mode);
+                if (pAsset == NULL) {
+                    /* try again, this time with ".gz" */
+                    path.append(".gz");
+                    pAsset = openAssetFromFileLocked(path, mode);
+                }
+            }
+
+            if (pAsset != NULL)
+                pAsset->setAssetSource(path);
+
+            /*
+             * Don't continue the search into the Zip files.  Our cached info
+             * said it was a file on disk; to be consistent with openDir()
+             * we want to return the loose asset.  If the cached file gets
+             * removed, we fail.
+             *
+             * The alternative is to update our cache when files get deleted,
+             * or make some sort of "best effort" promise, but for now I'm
+             * taking the hard line.
+             */
+            if (found) {
+                if (pAsset == NULL)
+                    LOGD("Expected file not found: '%s'\n", path.string());
+                return pAsset;
+            }
+        }
+    }
+
+    /*
+     * Either it wasn't found on disk or on the cached view of the disk.
+     * Dig through the currently-opened set of Zip files.  If caching
+     * is disabled, the Zip file may get reopened.
+     */
+    if (pAsset == NULL && ap.type == kFileTypeRegular) {
+        String8 path;
+
+        path.appendPath((locale != NULL) ? locale : kDefaultLocale);
+        path.appendPath((vendor != NULL) ? vendor : kDefaultVendor);
+        path.appendPath(fileName);
+
+        /* check the appropriate Zip file */
+        ZipFileRO* pZip;
+        ZipEntryRO entry;
+
+        pZip = getZipFileLocked(ap);
+        if (pZip != NULL) {
+            //printf("GOT zip, checking '%s'\n", (const char*) path);
+            entry = pZip->findEntryByName(path.string());
+            if (entry != NULL) {
+                //printf("FOUND in Zip file for %s/%s-%s\n",
+                //    appName, locale, vendor);
+                pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
+            }
+        }
+
+        if (pAsset != NULL) {
+            /* create a "source" name, for debug/display */
+            pAsset->setAssetSource(createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()),
+                                                             String8(""), String8(fileName)));
+        }
+    }
+
+    return pAsset;
+}
+
+/*
+ * Create a "source name" for a file from a Zip archive.
+ */
+String8 AssetManager::createZipSourceNameLocked(const String8& zipFileName,
+    const String8& dirName, const String8& fileName)
+{
+    String8 sourceName("zip:");
+    sourceName.append(zipFileName);
+    sourceName.append(":");
+    if (dirName.length() > 0) {
+        sourceName.appendPath(dirName);
+    }
+    sourceName.appendPath(fileName);
+    return sourceName;
+}
+
+/*
+ * Create a path to a loose asset (asset-base/app/locale/vendor).
+ */
+String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* locale,
+    const char* vendor)
+{
+    String8 path(ap.path);
+    path.appendPath((locale != NULL) ? locale : kDefaultLocale);
+    path.appendPath((vendor != NULL) ? vendor : kDefaultVendor);
+    return path;
+}
+
+/*
+ * Create a path to a loose asset (asset-base/app/rootDir).
+ */
+String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* rootDir)
+{
+    String8 path(ap.path);
+    if (rootDir != NULL) path.appendPath(rootDir);
+    return path;
+}
+
+/*
+ * Return a pointer to one of our open Zip archives.  Returns NULL if no
+ * matching Zip file exists.
+ *
+ * Right now we have 2 possible Zip files (1 each in app/"common").
+ *
+ * If caching is set to CACHE_OFF, to get the expected behavior we
+ * need to reopen the Zip file on every request.  That would be silly
+ * and expensive, so instead we just check the file modification date.
+ *
+ * Pass in NULL values for "appName", "locale", and "vendor" if the
+ * generics should be used.
+ */
+ZipFileRO* AssetManager::getZipFileLocked(const asset_path& ap)
+{
+    LOGV("getZipFileLocked() in %p\n", this);
+
+    return mZipSet.getZip(ap.path);
+}
+
+/*
+ * Try to open an asset from a file on disk.
+ *
+ * If the file is compressed with gzip, we seek to the start of the
+ * deflated data and pass that in (just like we would for a Zip archive).
+ *
+ * For uncompressed data, we may already have an mmap()ed version sitting
+ * around.  If so, we want to hand that to the Asset instead.
+ *
+ * This returns NULL if the file doesn't exist, couldn't be opened, or
+ * claims to be a ".gz" but isn't.
+ */
+Asset* AssetManager::openAssetFromFileLocked(const String8& pathName,
+    AccessMode mode)
+{
+    Asset* pAsset = NULL;
+
+    if (strcasecmp(pathName.getPathExtension().string(), ".gz") == 0) {
+        //printf("TRYING '%s'\n", (const char*) pathName);
+        pAsset = Asset::createFromCompressedFile(pathName.string(), mode);
+    } else {
+        //printf("TRYING '%s'\n", (const char*) pathName);
+        pAsset = Asset::createFromFile(pathName.string(), mode);
+    }
+
+    return pAsset;
+}
+
+/*
+ * Given an entry in a Zip archive, create a new Asset object.
+ *
+ * If the entry is uncompressed, we may want to create or share a
+ * slice of shared memory.
+ */
+Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile,
+    const ZipEntryRO entry, AccessMode mode, const String8& entryName)
+{
+    Asset* pAsset = NULL;
+
+    // TODO: look for previously-created shared memory slice?
+    int method;
+    long uncompressedLen;
+
+    //printf("USING Zip '%s'\n", pEntry->getFileName());
+
+    //pZipFile->getEntryInfo(entry, &method, &uncompressedLen, &compressedLen,
+    //    &offset);
+    if (!pZipFile->getEntryInfo(entry, &method, &uncompressedLen, NULL, NULL,
+            NULL, NULL))
+    {
+        LOGW("getEntryInfo failed\n");
+        return NULL;
+    }
+
+    FileMap* dataMap = pZipFile->createEntryFileMap(entry);
+    if (dataMap == NULL) {
+        LOGW("create map from entry failed\n");
+        return NULL;
+    }
+
+    if (method == ZipFileRO::kCompressStored) {
+        pAsset = Asset::createFromUncompressedMap(dataMap, mode);
+        LOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.string(),
+                dataMap->getFileName(), mode, pAsset);
+    } else {
+        pAsset = Asset::createFromCompressedMap(dataMap, method,
+            uncompressedLen, mode);
+        LOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.string(),
+                dataMap->getFileName(), mode, pAsset);
+    }
+    if (pAsset == NULL) {
+        /* unexpected */
+        LOGW("create from segment failed\n");
+    }
+
+    return pAsset;
+}
+
+
+
+/*
+ * Open a directory in the asset namespace.
+ *
+ * An "asset directory" is simply the combination of all files in all
+ * locations, with ".gz" stripped for loose files.  With app, locale, and
+ * vendor defined, we have 8 directories and 2 Zip archives to scan.
+ *
+ * Pass in "" for the root dir.
+ */
+AssetDir* AssetManager::openDir(const char* dirName)
+{
+    AutoMutex _l(mLock);
+
+    AssetDir* pDir = NULL;
+    SortedVector<AssetDir::FileInfo>* pMergedInfo = NULL;
+
+    LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+    assert(dirName != NULL);
+
+    //printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase);
+
+    if (mCacheMode != CACHE_OFF && !mCacheValid)
+        loadFileNameCacheLocked();
+
+    pDir = new AssetDir;
+
+    /*
+     * Scan the various directories, merging what we find into a single
+     * vector.  We want to scan them in reverse priority order so that
+     * the ".EXCLUDE" processing works correctly.  Also, if we decide we
+     * want to remember where the file is coming from, we'll get the right
+     * version.
+     *
+     * We start with Zip archives, then do loose files.
+     */
+    pMergedInfo = new SortedVector<AssetDir::FileInfo>;
+
+    size_t i = mAssetPaths.size();
+    while (i > 0) {
+        i--;
+        const asset_path& ap = mAssetPaths.itemAt(i);
+        if (ap.type == kFileTypeRegular) {
+            LOGV("Adding directory %s from zip %s", dirName, ap.path.string());
+            scanAndMergeZipLocked(pMergedInfo, ap, kAssetsRoot, dirName);
+        } else {
+            LOGV("Adding directory %s from dir %s", dirName, ap.path.string());
+            scanAndMergeDirLocked(pMergedInfo, ap, kAssetsRoot, dirName);
+        }
+    }
+
+#if 0
+    printf("FILE LIST:\n");
+    for (i = 0; i < (size_t) pMergedInfo->size(); i++) {
+        printf(" %d: (%d) '%s'\n", i,
+            pMergedInfo->itemAt(i).getFileType(),
+            (const char*) pMergedInfo->itemAt(i).getFileName());
+    }
+#endif
+
+    pDir->setFileList(pMergedInfo);
+    return pDir;
+}
+
+/*
+ * Scan the contents of the specified directory and merge them into the
+ * "pMergedInfo" vector, removing previous entries if we find "exclude"
+ * directives.
+ *
+ * Returns "false" if we found nothing to contribute.
+ */
+bool AssetManager::scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+    const asset_path& ap, const char* rootDir, const char* dirName)
+{
+    SortedVector<AssetDir::FileInfo>* pContents;
+    String8 path;
+
+    assert(pMergedInfo != NULL);
+
+    //printf("scanAndMergeDir: %s %s %s %s\n", appName, locale, vendor,dirName);
+
+    if (mCacheValid) {
+        int i, start, count;
+
+        pContents = new SortedVector<AssetDir::FileInfo>;
+
+        /*
+         * Get the basic partial path and find it in the cache.  That's
+         * the start point for the search.
+         */
+        path = createPathNameLocked(ap, rootDir);
+        if (dirName[0] != '\0')
+            path.appendPath(dirName);
+
+        start = mCache.indexOf(path);
+        if (start == NAME_NOT_FOUND) {
+            //printf("+++ not found in cache: dir '%s'\n", (const char*) path);
+            delete pContents;
+            return false;
+        }
+
+        /*
+         * The match string looks like "common/default/default/foo/bar/".
+         * The '/' on the end ensures that we don't match on the directory
+         * itself or on ".../foo/barfy/".
+         */
+        path.append("/");
+
+        count = mCache.size();
+
+        /*
+         * Pick out the stuff in the current dir by examining the pathname.
+         * It needs to match the partial pathname prefix, and not have a '/'
+         * (fssep) anywhere after the prefix.
+         */
+        for (i = start+1; i < count; i++) {
+            if (mCache[i].getFileName().length() > path.length() &&
+                strncmp(mCache[i].getFileName().string(), path.string(), path.length()) == 0)
+            {
+                const char* name = mCache[i].getFileName().string();
+                // XXX THIS IS BROKEN!  Looks like we need to store the full
+                // path prefix separately from the file path.
+                if (strchr(name + path.length(), '/') == NULL) {
+                    /* grab it, reducing path to just the filename component */
+                    AssetDir::FileInfo tmp = mCache[i];
+                    tmp.setFileName(tmp.getFileName().getPathLeaf());
+                    pContents->add(tmp);
+                }
+            } else {
+                /* no longer in the dir or its subdirs */
+                break;
+            }
+
+        }
+    } else {
+        path = createPathNameLocked(ap, rootDir);
+        if (dirName[0] != '\0')
+            path.appendPath(dirName);
+        pContents = scanDirLocked(path);
+        if (pContents == NULL)
+            return false;
+    }
+
+    // if we wanted to do an incremental cache fill, we would do it here
+
+    /*
+     * Process "exclude" directives.  If we find a filename that ends with
+     * ".EXCLUDE", we look for a matching entry in the "merged" set, and
+     * remove it if we find it.  We also delete the "exclude" entry.
+     */
+    int i, count, exclExtLen;
+
+    count = pContents->size();
+    exclExtLen = strlen(kExcludeExtension);
+    for (i = 0; i < count; i++) {
+        const char* name;
+        int nameLen;
+
+        name = pContents->itemAt(i).getFileName().string();
+        nameLen = strlen(name);
+        if (nameLen > exclExtLen &&
+            strcmp(name + (nameLen - exclExtLen), kExcludeExtension) == 0)
+        {
+            String8 match(name, nameLen - exclExtLen);
+            int matchIdx;
+
+            matchIdx = AssetDir::FileInfo::findEntry(pMergedInfo, match);
+            if (matchIdx > 0) {
+                LOGV("Excluding '%s' [%s]\n",
+                    pMergedInfo->itemAt(matchIdx).getFileName().string(),
+                    pMergedInfo->itemAt(matchIdx).getSourceName().string());
+                pMergedInfo->removeAt(matchIdx);
+            } else {
+                //printf("+++ no match on '%s'\n", (const char*) match);
+            }
+
+            LOGD("HEY: size=%d removing %d\n", (int)pContents->size(), i);
+            pContents->removeAt(i);
+            i--;        // adjust "for" loop
+            count--;    //  and loop limit
+        }
+    }
+
+    mergeInfoLocked(pMergedInfo, pContents);
+
+    delete pContents;
+
+    return true;
+}
+
+/*
+ * Scan the contents of the specified directory, and stuff what we find
+ * into a newly-allocated vector.
+ *
+ * Files ending in ".gz" will have their extensions removed.
+ *
+ * We should probably think about skipping files with "illegal" names,
+ * e.g. illegal characters (/\:) or excessive length.
+ *
+ * Returns NULL if the specified directory doesn't exist.
+ */
+SortedVector<AssetDir::FileInfo>* AssetManager::scanDirLocked(const String8& path)
+{
+    SortedVector<AssetDir::FileInfo>* pContents = NULL;
+    DIR* dir;
+    struct dirent* entry;
+    FileType fileType;
+
+    LOGV("Scanning dir '%s'\n", path.string());
+
+    dir = opendir(path.string());
+    if (dir == NULL)
+        return NULL;
+
+    pContents = new SortedVector<AssetDir::FileInfo>;
+
+    while (1) {
+        entry = readdir(dir);
+        if (entry == NULL)
+            break;
+
+        if (strcmp(entry->d_name, ".") == 0 ||
+            strcmp(entry->d_name, "..") == 0)
+            continue;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+        if (entry->d_type == DT_REG)
+            fileType = kFileTypeRegular;
+        else if (entry->d_type == DT_DIR)
+            fileType = kFileTypeDirectory;
+        else
+            fileType = kFileTypeUnknown;
+#else
+        // stat the file
+        fileType = ::getFileType(path.appendPathCopy(entry->d_name).string());
+#endif
+
+        if (fileType != kFileTypeRegular && fileType != kFileTypeDirectory)
+            continue;
+
+        AssetDir::FileInfo info;
+        info.set(String8(entry->d_name), fileType);
+        if (strcasecmp(info.getFileName().getPathExtension().string(), ".gz") == 0)
+            info.setFileName(info.getFileName().getBasePath());
+        info.setSourceName(path.appendPathCopy(info.getFileName()));
+        pContents->add(info);
+    }
+
+    closedir(dir);
+    return pContents;
+}
+
+/*
+ * Scan the contents out of the specified Zip archive, and merge what we
+ * find into "pMergedInfo".  If the Zip archive in question doesn't exist,
+ * we return immediately.
+ *
+ * Returns "false" if we found nothing to contribute.
+ */
+bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+    const asset_path& ap, const char* rootDir, const char* baseDirName)
+{
+    ZipFileRO* pZip;
+    Vector<String8> dirs;
+    AssetDir::FileInfo info;
+    SortedVector<AssetDir::FileInfo> contents;
+    String8 sourceName, zipName, dirName;
+
+    pZip = mZipSet.getZip(ap.path);
+    if (pZip == NULL) {
+        LOGW("Failure opening zip %s\n", ap.path.string());
+        return false;
+    }
+
+    zipName = ZipSet::getPathName(ap.path.string());
+
+    /* convert "sounds" to "rootDir/sounds" */
+    if (rootDir != NULL) dirName = rootDir;
+    dirName.appendPath(baseDirName);
+
+    /*
+     * Scan through the list of files, looking for a match.  The files in
+     * the Zip table of contents are not in sorted order, so we have to
+     * process the entire list.  We're looking for a string that begins
+     * with the characters in "dirName", is followed by a '/', and has no
+     * subsequent '/' in the stuff that follows.
+     *
+     * What makes this especially fun is that directories are not stored
+     * explicitly in Zip archives, so we have to infer them from context.
+     * When we see "sounds/foo.wav" we have to leave a note to ourselves
+     * to insert a directory called "sounds" into the list.  We store
+     * these in temporary vector so that we only return each one once.
+     *
+     * Name comparisons are case-sensitive to match UNIX filesystem
+     * semantics.
+     */
+    int dirNameLen = dirName.length();
+    for (int i = 0; i < pZip->getNumEntries(); i++) {
+        ZipEntryRO entry;
+        char nameBuf[256];
+
+        entry = pZip->findEntryByIndex(i);
+        if (pZip->getEntryFileName(entry, nameBuf, sizeof(nameBuf)) != 0) {
+            // TODO: fix this if we expect to have long names
+            LOGE("ARGH: name too long?\n");
+            continue;
+        }
+        if (dirNameLen == 0 ||
+            (strncmp(nameBuf, dirName.string(), dirNameLen) == 0 &&
+             nameBuf[dirNameLen] == '/'))
+        {
+            const char* cp;
+            const char* nextSlash;
+
+            cp = nameBuf + dirNameLen;
+            if (dirNameLen != 0)
+                cp++;       // advance past the '/'
+
+            nextSlash = strchr(cp, '/');
+//xxx this may break if there are bare directory entries
+            if (nextSlash == NULL) {
+                /* this is a file in the requested directory */
+
+                info.set(String8(nameBuf).getPathLeaf(), kFileTypeRegular);
+
+                info.setSourceName(
+                    createZipSourceNameLocked(zipName, dirName, info.getFileName()));
+
+                contents.add(info);
+                //printf("FOUND: file '%s'\n", (const char*) info.mFileName);
+            } else {
+                /* this is a subdir; add it if we don't already have it*/
+                String8 subdirName(cp, nextSlash - cp);
+                size_t j;
+                size_t N = dirs.size();
+
+                for (j = 0; j < N; j++) {
+                    if (subdirName == dirs[j]) {
+                        break;
+                    }
+                }
+                if (j == N) {
+                    dirs.add(subdirName);
+                }
+
+                //printf("FOUND: dir '%s'\n", (const char*) subdirName);
+            }
+        }
+    }
+
+    /*
+     * Add the set of unique directories.
+     */
+    for (int i = 0; i < (int) dirs.size(); i++) {
+        info.set(dirs[i], kFileTypeDirectory);
+        info.setSourceName(
+            createZipSourceNameLocked(zipName, dirName, info.getFileName()));
+        contents.add(info);
+    }
+
+    mergeInfoLocked(pMergedInfo, &contents);
+
+    return true;
+}
+
+
+/*
+ * Merge two vectors of FileInfo.
+ *
+ * The merged contents will be stuffed into *pMergedInfo.
+ *
+ * If an entry for a file exists in both "pMergedInfo" and "pContents",
+ * we use the newer "pContents" entry.
+ */
+void AssetManager::mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+    const SortedVector<AssetDir::FileInfo>* pContents)
+{
+    /*
+     * Merge what we found in this directory with what we found in
+     * other places.
+     *
+     * Two basic approaches:
+     * (1) Create a new array that holds the unique values of the two
+     *     arrays.
+     * (2) Take the elements from pContents and shove them into pMergedInfo.
+     *
+     * Because these are vectors of complex objects, moving elements around
+     * inside the vector requires constructing new objects and allocating
+     * storage for members.  With approach #1, we're always adding to the
+     * end, whereas with #2 we could be inserting multiple elements at the
+     * front of the vector.  Approach #1 requires a full copy of the
+     * contents of pMergedInfo, but approach #2 requires the same copy for
+     * every insertion at the front of pMergedInfo.
+     *
+     * (We should probably use a SortedVector interface that allows us to
+     * just stuff items in, trusting us to maintain the sort order.)
+     */
+    SortedVector<AssetDir::FileInfo>* pNewSorted;
+    int mergeMax, contMax;
+    int mergeIdx, contIdx;
+
+    pNewSorted = new SortedVector<AssetDir::FileInfo>;
+    mergeMax = pMergedInfo->size();
+    contMax = pContents->size();
+    mergeIdx = contIdx = 0;
+
+    while (mergeIdx < mergeMax || contIdx < contMax) {
+        if (mergeIdx == mergeMax) {
+            /* hit end of "merge" list, copy rest of "contents" */
+            pNewSorted->add(pContents->itemAt(contIdx));
+            contIdx++;
+        } else if (contIdx == contMax) {
+            /* hit end of "cont" list, copy rest of "merge" */
+            pNewSorted->add(pMergedInfo->itemAt(mergeIdx));
+            mergeIdx++;
+        } else if (pMergedInfo->itemAt(mergeIdx) == pContents->itemAt(contIdx))
+        {
+            /* items are identical, add newer and advance both indices */
+            pNewSorted->add(pContents->itemAt(contIdx));
+            mergeIdx++;
+            contIdx++;
+        } else if (pMergedInfo->itemAt(mergeIdx) < pContents->itemAt(contIdx))
+        {
+            /* "merge" is lower, add that one */
+            pNewSorted->add(pMergedInfo->itemAt(mergeIdx));
+            mergeIdx++;
+        } else {
+            /* "cont" is lower, add that one */
+            assert(pContents->itemAt(contIdx) < pMergedInfo->itemAt(mergeIdx));
+            pNewSorted->add(pContents->itemAt(contIdx));
+            contIdx++;
+        }
+    }
+
+    /*
+     * Overwrite the "merged" list with the new stuff.
+     */
+    *pMergedInfo = *pNewSorted;
+    delete pNewSorted;
+
+#if 0       // for Vector, rather than SortedVector
+    int i, j;
+    for (i = pContents->size() -1; i >= 0; i--) {
+        bool add = true;
+
+        for (j = pMergedInfo->size() -1; j >= 0; j--) {
+            /* case-sensitive comparisons, to behave like UNIX fs */
+            if (strcmp(pContents->itemAt(i).mFileName,
+                       pMergedInfo->itemAt(j).mFileName) == 0)
+            {
+                /* match, don't add this entry */
+                add = false;
+                break;
+            }
+        }
+
+        if (add)
+            pMergedInfo->add(pContents->itemAt(i));
+    }
+#endif
+}
+
+
+/*
+ * Load all files into the file name cache.  We want to do this across
+ * all combinations of { appname, locale, vendor }, performing a recursive
+ * directory traversal.
+ *
+ * This is not the most efficient data structure.  Also, gathering the
+ * information as we needed it (file-by-file or directory-by-directory)
+ * would be faster.  However, on the actual device, 99% of the files will
+ * live in Zip archives, so this list will be very small.  The trouble
+ * is that we have to check the "loose" files first, so it's important
+ * that we don't beat the filesystem silly looking for files that aren't
+ * there.
+ *
+ * Note on thread safety: this is the only function that causes updates
+ * to mCache, and anybody who tries to use it will call here if !mCacheValid,
+ * so we need to employ a mutex here.
+ */
+void AssetManager::loadFileNameCacheLocked(void)
+{
+    assert(!mCacheValid);
+    assert(mCache.size() == 0);
+
+#ifdef DO_TIMINGS   // need to link against -lrt for this now
+    DurationTimer timer;
+    timer.start();
+#endif
+
+    fncScanLocked(&mCache, "");
+
+#ifdef DO_TIMINGS
+    timer.stop();
+    LOGD("Cache scan took %.3fms\n",
+        timer.durationUsecs() / 1000.0);
+#endif
+
+#if 0
+    int i;
+    printf("CACHED FILE LIST (%d entries):\n", mCache.size());
+    for (i = 0; i < (int) mCache.size(); i++) {
+        printf(" %d: (%d) '%s'\n", i,
+            mCache.itemAt(i).getFileType(),
+            (const char*) mCache.itemAt(i).getFileName());
+    }
+#endif
+
+    mCacheValid = true;
+}
+
+/*
+ * Scan up to 8 versions of the specified directory.
+ */
+void AssetManager::fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+    const char* dirName)
+{
+    size_t i = mAssetPaths.size();
+    while (i > 0) {
+        i--;
+        const asset_path& ap = mAssetPaths.itemAt(i);
+        fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, NULL, dirName);
+        if (mLocale != NULL)
+            fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, NULL, dirName);
+        if (mVendor != NULL)
+            fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, mVendor, dirName);
+        if (mLocale != NULL && mVendor != NULL)
+            fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, mVendor, dirName);
+    }
+}
+
+/*
+ * Recursively scan this directory and all subdirs.
+ *
+ * This is similar to scanAndMergeDir, but we don't remove the .EXCLUDE
+ * files, and we prepend the extended partial path to the filenames.
+ */
+bool AssetManager::fncScanAndMergeDirLocked(
+    SortedVector<AssetDir::FileInfo>* pMergedInfo,
+    const asset_path& ap, const char* locale, const char* vendor,
+    const char* dirName)
+{
+    SortedVector<AssetDir::FileInfo>* pContents;
+    String8 partialPath;
+    String8 fullPath;
+
+    // XXX This is broken -- the filename cache needs to hold the base
+    // asset path separately from its filename.
+    
+    partialPath = createPathNameLocked(ap, locale, vendor);
+    if (dirName[0] != '\0') {
+        partialPath.appendPath(dirName);
+    }
+
+    fullPath = partialPath;
+    pContents = scanDirLocked(fullPath);
+    if (pContents == NULL) {
+        return false;       // directory did not exist
+    }
+
+    /*
+     * Scan all subdirectories of the current dir, merging what we find
+     * into "pMergedInfo".
+     */
+    for (int i = 0; i < (int) pContents->size(); i++) {
+        if (pContents->itemAt(i).getFileType() == kFileTypeDirectory) {
+            String8 subdir(dirName);
+            subdir.appendPath(pContents->itemAt(i).getFileName());
+
+            fncScanAndMergeDirLocked(pMergedInfo, ap, locale, vendor, subdir.string());
+        }
+    }
+
+    /*
+     * To be consistent, we want entries for the root directory.  If
+     * we're the root, add one now.
+     */
+    if (dirName[0] == '\0') {
+        AssetDir::FileInfo tmpInfo;
+
+        tmpInfo.set(String8(""), kFileTypeDirectory);
+        tmpInfo.setSourceName(createPathNameLocked(ap, locale, vendor));
+        pContents->add(tmpInfo);
+    }
+
+    /*
+     * We want to prepend the extended partial path to every entry in
+     * "pContents".  It's the same value for each entry, so this will
+     * not change the sorting order of the vector contents.
+     */
+    for (int i = 0; i < (int) pContents->size(); i++) {
+        const AssetDir::FileInfo& info = pContents->itemAt(i);
+        pContents->editItemAt(i).setFileName(partialPath.appendPathCopy(info.getFileName()));
+    }
+
+    mergeInfoLocked(pMergedInfo, pContents);
+    return true;
+}
+
+/*
+ * Trash the cache.
+ */
+void AssetManager::purgeFileNameCacheLocked(void)
+{
+    mCacheValid = false;
+    mCache.clear();
+}
+
+/*
+ * ===========================================================================
+ *      AssetManager::SharedZip
+ * ===========================================================================
+ */
+
+
+Mutex AssetManager::SharedZip::gLock;
+DefaultKeyedVector<String8, wp<AssetManager::SharedZip> > AssetManager::SharedZip::gOpen;
+
+AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen)
+    : mPath(path), mZipFile(NULL), mModWhen(modWhen), mResourceTableAsset(NULL)
+{
+    //LOGI("Creating SharedZip %p %s\n", this, (const char*)mPath);
+    mZipFile = new ZipFileRO;
+    LOGV("+++ opening zip '%s'\n", mPath.string());
+    if (mZipFile->open(mPath.string()) != NO_ERROR) {
+        LOGD("failed to open Zip archive '%s'\n", mPath.string());
+        delete mZipFile;
+        mZipFile = NULL;
+    }
+}
+
+sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path)
+{
+    AutoMutex _l(gLock);
+    time_t modWhen = getFileModDate(path);
+    sp<SharedZip> zip = gOpen.valueFor(path).promote();
+    if (zip != NULL && zip->mModWhen == modWhen) {
+        return zip;
+    }
+    zip = new SharedZip(path, modWhen);
+    gOpen.add(path, zip);
+    return zip;
+
+}
+
+ZipFileRO* AssetManager::SharedZip::getZip()
+{
+    return mZipFile;
+}
+
+Asset* AssetManager::SharedZip::getResourceTableAsset()
+{
+    LOGV("Getting from SharedZip %p resource asset %p\n", this, mResourceTableAsset);
+    return mResourceTableAsset;
+}
+
+Asset* AssetManager::SharedZip::setResourceTableAsset(Asset* asset)
+{
+    {
+        AutoMutex _l(gLock);
+        if (mResourceTableAsset == NULL) {
+            mResourceTableAsset = asset;
+            // This is not thread safe the first time it is called, so
+            // do it here with the global lock held.
+            asset->getBuffer(true);
+            return asset;
+        }
+    }
+    delete asset;
+    return mResourceTableAsset;
+}
+
+bool AssetManager::SharedZip::isUpToDate()
+{
+    time_t modWhen = getFileModDate(mPath.string());
+    return mModWhen == modWhen;
+}
+
+AssetManager::SharedZip::~SharedZip()
+{
+    //LOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath);
+    if (mResourceTableAsset != NULL) {
+        delete mResourceTableAsset;
+    }
+    if (mZipFile != NULL) {
+        delete mZipFile;
+        LOGV("Closed '%s'\n", mPath.string());
+    }
+}
+
+/*
+ * ===========================================================================
+ *      AssetManager::ZipSet
+ * ===========================================================================
+ */
+
+/*
+ * Constructor.
+ */
+AssetManager::ZipSet::ZipSet(void)
+{
+}
+
+/*
+ * Destructor.  Close any open archives.
+ */
+AssetManager::ZipSet::~ZipSet(void)
+{
+    size_t N = mZipFile.size();
+    for (size_t i = 0; i < N; i++)
+        closeZip(i);
+}
+
+/*
+ * Close a Zip file and reset the entry.
+ */
+void AssetManager::ZipSet::closeZip(int idx)
+{
+    mZipFile.editItemAt(idx) = NULL;
+}
+
+
+/*
+ * Retrieve the appropriate Zip file from the set.
+ */
+ZipFileRO* AssetManager::ZipSet::getZip(const String8& path)
+{
+    int idx = getIndex(path);
+    sp<SharedZip> zip = mZipFile[idx];
+    if (zip == NULL) {
+        zip = SharedZip::get(path);
+        mZipFile.editItemAt(idx) = zip;
+    }
+    return zip->getZip();
+}
+
+Asset* AssetManager::ZipSet::getZipResourceTable(const String8& path)
+{
+    int idx = getIndex(path);
+    sp<SharedZip> zip = mZipFile[idx];
+    if (zip == NULL) {
+        zip = SharedZip::get(path);
+        mZipFile.editItemAt(idx) = zip;
+    }
+    return zip->getResourceTableAsset();
+}
+
+Asset* AssetManager::ZipSet::setZipResourceTable(const String8& path,
+                                                 Asset* asset)
+{
+    int idx = getIndex(path);
+    sp<SharedZip> zip = mZipFile[idx];
+    // doesn't make sense to call before previously accessing.
+    return zip->setResourceTableAsset(asset);
+}
+
+/*
+ * Generate the partial pathname for the specified archive.  The caller
+ * gets to prepend the asset root directory.
+ *
+ * Returns something like "common/en-US-noogle.jar".
+ */
+/*static*/ String8 AssetManager::ZipSet::getPathName(const char* zipPath)
+{
+    return String8(zipPath);
+}
+
+bool AssetManager::ZipSet::isUpToDate()
+{
+    const size_t N = mZipFile.size();
+    for (size_t i=0; i<N; i++) {
+        if (mZipFile[i] != NULL && !mZipFile[i]->isUpToDate()) {
+            return false;
+        }
+    }
+    return true;
+}
+
+/*
+ * Compute the zip file's index.
+ *
+ * "appName", "locale", and "vendor" should be set to NULL to indicate the
+ * default directory.
+ */
+int AssetManager::ZipSet::getIndex(const String8& zip) const
+{
+    const size_t N = mZipPath.size();
+    for (size_t i=0; i<N; i++) {
+        if (mZipPath[i] == zip) {
+            return i;
+        }
+    }
+
+    mZipPath.add(zip);
+    mZipFile.add(NULL);
+
+    return mZipPath.size()-1;
+}
+
diff --git a/libs/utils/Binder.cpp b/libs/utils/Binder.cpp
new file mode 100644
index 0000000..37e4685
--- /dev/null
+++ b/libs/utils/Binder.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2005 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 <utils/Binder.h>
+
+#include <utils/Atomic.h>
+#include <utils/BpBinder.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+
+#include <stdio.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+sp<IInterface>  IBinder::queryLocalInterface(const String16& descriptor)
+{
+    return NULL;
+}
+
+BBinder* IBinder::localBinder()
+{
+    return NULL;
+}
+
+BpBinder* IBinder::remoteBinder()
+{
+    return NULL;
+}
+
+bool IBinder::checkSubclass(const void* /*subclassID*/) const
+{
+    return false;
+}
+
+// ---------------------------------------------------------------------------
+
+class BBinder::Extras
+{
+public:
+    Mutex mLock;
+    BpBinder::ObjectManager mObjects;
+};
+
+// ---------------------------------------------------------------------------
+
+BBinder::BBinder()
+    : mExtras(NULL)
+{
+}
+
+bool BBinder::isBinderAlive() const
+{
+    return true;
+}
+
+status_t BBinder::pingBinder()
+{
+    return NO_ERROR;
+}
+
+String16 BBinder::getInterfaceDescriptor() const
+{
+    LOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this);
+    return String16();
+}
+
+status_t BBinder::transact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    data.setDataPosition(0);
+
+    status_t err = NO_ERROR;
+    switch (code) {
+        case PING_TRANSACTION:
+            reply->writeInt32(pingBinder());
+            break;
+        default:
+            err = onTransact(code, data, reply, flags);
+            break;
+    }
+
+    if (reply != NULL) {
+        reply->setDataPosition(0);
+    }
+
+    return err;
+}
+
+status_t BBinder::linkToDeath(
+    const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
+{
+    return INVALID_OPERATION;
+}
+
+status_t BBinder::unlinkToDeath(
+    const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+    wp<DeathRecipient>* outRecipient)
+{
+    return INVALID_OPERATION;
+}
+
+status_t BBinder::dump(int fd, const Vector<String16>& args)
+{
+    return NO_ERROR;
+}
+
+void BBinder::attachObject(
+    const void* objectID, void* object, void* cleanupCookie,
+    object_cleanup_func func)
+{
+    Extras* e = mExtras;
+
+    if (!e) {
+        e = new Extras;
+        if (android_atomic_cmpxchg(0, reinterpret_cast<int32_t>(e),
+                reinterpret_cast<volatile int32_t*>(&mExtras)) != 0) {
+            delete e;
+            e = mExtras;
+        }
+        if (e == 0) return; // out of memory
+    }
+
+    AutoMutex _l(e->mLock);
+    e->mObjects.attach(objectID, object, cleanupCookie, func);
+}
+
+void* BBinder::findObject(const void* objectID) const
+{
+    Extras* e = mExtras;
+    if (!e) return NULL;
+
+    AutoMutex _l(e->mLock);
+    return e->mObjects.find(objectID);
+}
+
+void BBinder::detachObject(const void* objectID)
+{
+    Extras* e = mExtras;
+    if (!e) return;
+
+    AutoMutex _l(e->mLock);
+    e->mObjects.detach(objectID);
+}
+
+BBinder* BBinder::localBinder()
+{
+    return this;
+}
+
+BBinder::~BBinder()
+{
+    if (mExtras) delete mExtras;
+}
+
+
+status_t BBinder::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case INTERFACE_TRANSACTION:
+            reply->writeString16(getInterfaceDescriptor());
+            return NO_ERROR;
+
+        case DUMP_TRANSACTION: {
+            int fd = data.readFileDescriptor();
+            int argc = data.readInt32();
+            Vector<String16> args;
+            for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+               args.add(data.readString16());
+            }
+            return dump(fd, args);
+        }
+        default:
+            return UNKNOWN_TRANSACTION;
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+enum {
+    // This is used to transfer ownership of the remote binder from
+    // the BpRefBase object holding it (when it is constructed), to the
+    // owner of the BpRefBase object when it first acquires that BpRefBase.
+    kRemoteAcquired = 0x00000001
+};
+
+BpRefBase::BpRefBase(const sp<IBinder>& o)
+    : mRemote(o.get()), mRefs(NULL), mState(0)
+{
+    extendObjectLifetime(OBJECT_LIFETIME_WEAK);
+
+    if (mRemote) {
+        mRemote->incStrong(this);           // Removed on first IncStrong().
+        mRefs = mRemote->createWeak(this);  // Held for our entire lifetime.
+    }
+}
+
+BpRefBase::~BpRefBase()
+{
+    if (mRemote) {
+        if (!(mState&kRemoteAcquired)) {
+            mRemote->decStrong(this);
+        }
+        mRefs->decWeak(this);
+    }
+}
+
+void BpRefBase::onFirstRef()
+{
+    android_atomic_or(kRemoteAcquired, &mState);
+}
+
+void BpRefBase::onLastStrongRef(const void* id)
+{
+    if (mRemote) {
+        mRemote->decStrong(this);
+    }
+}
+
+bool BpRefBase::onIncStrongAttempted(uint32_t flags, const void* id)
+{
+    return mRemote ? mRefs->attemptIncStrong(this) : false;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/utils/BpBinder.cpp b/libs/utils/BpBinder.cpp
new file mode 100644
index 0000000..69ab195
--- /dev/null
+++ b/libs/utils/BpBinder.cpp
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "BpBinder"
+//#define LOG_NDEBUG 0
+
+#include <utils/BpBinder.h>
+
+#include <utils/IPCThreadState.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+
+//#undef LOGV
+//#define LOGV(...) fprintf(stderr, __VA_ARGS__)
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+BpBinder::ObjectManager::ObjectManager()
+{
+}
+
+BpBinder::ObjectManager::~ObjectManager()
+{
+    kill();
+}
+
+void BpBinder::ObjectManager::attach(
+    const void* objectID, void* object, void* cleanupCookie,
+    IBinder::object_cleanup_func func)
+{
+    entry_t e;
+    e.object = object;
+    e.cleanupCookie = cleanupCookie;
+    e.func = func;
+
+    if (mObjects.indexOfKey(objectID) >= 0) {
+        LOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use",
+                objectID, this,  object);
+        return;
+    }
+
+    mObjects.add(objectID, e);
+}
+
+void* BpBinder::ObjectManager::find(const void* objectID) const
+{
+    const ssize_t i = mObjects.indexOfKey(objectID);
+    if (i < 0) return NULL;
+    return mObjects.valueAt(i).object;
+}
+
+void BpBinder::ObjectManager::detach(const void* objectID)
+{
+    mObjects.removeItem(objectID);
+}
+
+void BpBinder::ObjectManager::kill()
+{
+    const size_t N = mObjects.size();
+    LOGV("Killing %d objects in manager %p", N, this);
+    for (size_t i=0; i<N; i++) {
+        const entry_t& e = mObjects.valueAt(i);
+        if (e.func != NULL) {
+            e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);
+        }
+    }
+
+    mObjects.clear();
+}
+
+// ---------------------------------------------------------------------------
+
+BpBinder::BpBinder(int32_t handle)
+    : mHandle(handle)
+    , mAlive(1)
+    , mObitsSent(0)
+    , mObituaries(NULL)
+{
+    LOGV("Creating BpBinder %p handle %d\n", this, mHandle);
+
+    extendObjectLifetime(OBJECT_LIFETIME_WEAK);
+    IPCThreadState::self()->incWeakHandle(handle);
+}
+
+String16 BpBinder::getInterfaceDescriptor() const
+{
+    String16 res;
+    Parcel send, reply;
+    status_t err = const_cast<BpBinder*>(this)->transact(
+            INTERFACE_TRANSACTION, send, &reply);
+    if (err == NO_ERROR) {
+        res = reply.readString16();
+    }
+    return res;
+}
+
+bool BpBinder::isBinderAlive() const
+{
+    return mAlive != 0;
+}
+
+status_t BpBinder::pingBinder()
+{
+    Parcel send;
+    Parcel reply;
+    status_t err = transact(PING_TRANSACTION, send, &reply);
+    if (err != NO_ERROR) return err;
+    if (reply.dataSize() < sizeof(status_t)) return NOT_ENOUGH_DATA;
+    return (status_t)reply.readInt32();
+}
+
+status_t BpBinder::dump(int fd, const Vector<String16>& args)
+{
+    Parcel send;
+    Parcel reply;
+    send.writeFileDescriptor(fd);
+    const size_t numArgs = args.size();
+    send.writeInt32(numArgs);
+    for (size_t i = 0; i < numArgs; i++) {
+        send.writeString16(args[i]);
+    }
+    status_t err = transact(DUMP_TRANSACTION, send, &reply);
+    return err;
+}
+
+status_t BpBinder::transact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    // Once a binder has died, it will never come back to life.
+    if (mAlive) {
+        status_t status = IPCThreadState::self()->transact(
+            mHandle, code, data, reply, flags);
+        if (status == DEAD_OBJECT) mAlive = 0;
+        return status;
+    }
+
+    return DEAD_OBJECT;
+}
+
+status_t BpBinder::linkToDeath(
+    const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
+{
+    Obituary ob;
+    ob.recipient = recipient;
+    ob.cookie = cookie;
+    ob.flags = flags;
+
+    LOG_ALWAYS_FATAL_IF(recipient == NULL,
+                        "linkToDeath(): recipient must be non-NULL");
+
+    {
+        AutoMutex _l(mLock);
+
+        if (!mObitsSent) {
+            if (!mObituaries) {
+                mObituaries = new Vector<Obituary>;
+                if (!mObituaries) {
+                    return NO_MEMORY;
+                }
+                LOGV("Requesting death notification: %p handle %d\n", this, mHandle);
+                getWeakRefs()->incWeak(this);
+                IPCThreadState* self = IPCThreadState::self();
+                self->requestDeathNotification(mHandle, this);
+                self->flushCommands();
+            }
+            ssize_t res = mObituaries->add(ob);
+            return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
+        }
+    }
+
+    return DEAD_OBJECT;
+}
+
+status_t BpBinder::unlinkToDeath(
+    const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+    wp<DeathRecipient>* outRecipient)
+{
+    AutoMutex _l(mLock);
+
+    if (mObitsSent) {
+        return DEAD_OBJECT;
+    }
+
+    const size_t N = mObituaries ? mObituaries->size() : 0;
+    for (size_t i=0; i<N; i++) {
+        const Obituary& obit = mObituaries->itemAt(i);
+        if ((obit.recipient == recipient
+                    || (recipient == NULL && obit.cookie == cookie))
+                && obit.flags == flags) {
+            const uint32_t allFlags = obit.flags|flags;
+            if (outRecipient != NULL) {
+                *outRecipient = mObituaries->itemAt(i).recipient;
+            }
+            mObituaries->removeAt(i);
+            if (mObituaries->size() == 0) {
+                LOGV("Clearing death notification: %p handle %d\n", this, mHandle);
+                IPCThreadState* self = IPCThreadState::self();
+                self->clearDeathNotification(mHandle, this);
+                self->flushCommands();
+                delete mObituaries;
+                mObituaries = NULL;
+            }
+            return NO_ERROR;
+        }
+    }
+
+    return NAME_NOT_FOUND;
+}
+
+void BpBinder::sendObituary()
+{
+    LOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
+        this, mHandle, mObitsSent ? "true" : "false");
+
+    mAlive = 0;
+    if (mObitsSent) return;
+
+    mLock.lock();
+    Vector<Obituary>* obits = mObituaries;
+    if(obits != NULL) {
+        LOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
+        IPCThreadState* self = IPCThreadState::self();
+        self->clearDeathNotification(mHandle, this);
+        self->flushCommands();
+        mObituaries = NULL;
+    }
+    mObitsSent = 1;
+    mLock.unlock();
+
+    LOGV("Reporting death of proxy %p for %d recipients\n",
+        this, obits ? obits->size() : 0);
+
+    if (obits != NULL) {
+        const size_t N = obits->size();
+        for (size_t i=0; i<N; i++) {
+            reportOneDeath(obits->itemAt(i));
+        }
+
+        delete obits;
+    }
+}
+
+void BpBinder::reportOneDeath(const Obituary& obit)
+{
+    sp<DeathRecipient> recipient = obit.recipient.promote();
+    LOGV("Reporting death to recipient: %p\n", recipient.get());
+    if (recipient == NULL) return;
+
+    recipient->binderDied(this);
+}
+
+
+void BpBinder::attachObject(
+    const void* objectID, void* object, void* cleanupCookie,
+    object_cleanup_func func)
+{
+    AutoMutex _l(mLock);
+    LOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);
+    mObjects.attach(objectID, object, cleanupCookie, func);
+}
+
+void* BpBinder::findObject(const void* objectID) const
+{
+    AutoMutex _l(mLock);
+    return mObjects.find(objectID);
+}
+
+void BpBinder::detachObject(const void* objectID)
+{
+    AutoMutex _l(mLock);
+    mObjects.detach(objectID);
+}
+
+BpBinder* BpBinder::remoteBinder()
+{
+    return this;
+}
+
+BpBinder::~BpBinder()
+{
+    LOGV("Destroying BpBinder %p handle %d\n", this, mHandle);
+
+    IPCThreadState* ipc = IPCThreadState::self();
+
+    mLock.lock();
+    Vector<Obituary>* obits = mObituaries;
+    if(obits != NULL) {
+        if (ipc) ipc->clearDeathNotification(mHandle, this);
+        mObituaries = NULL;
+    }
+    mLock.unlock();
+
+    if (obits != NULL) {
+        // XXX Should we tell any remaining DeathRecipient
+        // objects that the last strong ref has gone away, so they
+        // are no longer linked?
+        delete obits;
+    }
+
+    if (ipc) {
+        ipc->expungeHandle(mHandle, this);
+        ipc->decWeakHandle(mHandle);
+    }
+}
+
+void BpBinder::onFirstRef()
+{
+    LOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle);
+    IPCThreadState* ipc = IPCThreadState::self();
+    if (ipc) ipc->incStrongHandle(mHandle);
+}
+
+void BpBinder::onLastStrongRef(const void* id)
+{
+    LOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle);
+    IF_LOGV() {
+        printRefs();
+    }
+    IPCThreadState* ipc = IPCThreadState::self();
+    if (ipc) ipc->decStrongHandle(mHandle);
+}
+
+bool BpBinder::onIncStrongAttempted(uint32_t flags, const void* id)
+{
+    LOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, mHandle);
+    IPCThreadState* ipc = IPCThreadState::self();
+    return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/utils/BufferedTextOutput.cpp b/libs/utils/BufferedTextOutput.cpp
new file mode 100644
index 0000000..989662e
--- /dev/null
+++ b/libs/utils/BufferedTextOutput.cpp
@@ -0,0 +1,279 @@
+/*
+ * 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 <utils/BufferedTextOutput.h>
+
+#include <utils/Atomic.h>
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <cutils/threads.h>
+
+#include <private/utils/Static.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+struct BufferedTextOutput::BufferState : public RefBase
+{
+    BufferState(int32_t _seq)
+        : seq(_seq)
+        , buffer(NULL)
+        , bufferPos(0)
+        , bufferSize(0)
+        , atFront(true)
+        , indent(0)
+        , bundle(0) {
+    }
+    ~BufferState() {
+        free(buffer);
+    }
+    
+    status_t append(const char* txt, size_t len) {
+        if ((len+bufferPos) > bufferSize) {
+            void* b = realloc(buffer, ((len+bufferPos)*3)/2);
+            if (!b) return NO_MEMORY;
+            buffer = (char*)b;
+        }
+        memcpy(buffer+bufferPos, txt, len);
+        bufferPos += len;
+        return NO_ERROR;
+    }
+    
+    void restart() {
+        bufferPos = 0;
+        atFront = true;
+        if (bufferSize > 256) {
+            void* b = realloc(buffer, 256);
+            if (b) {
+                buffer = (char*)b;
+                bufferSize = 256;
+            }
+        }
+    }
+    
+    const int32_t seq;
+    char* buffer;
+    size_t bufferPos;
+    size_t bufferSize;
+    bool atFront;
+    int32_t indent;
+    int32_t bundle;
+};
+
+struct BufferedTextOutput::ThreadState
+{
+    Vector<sp<BufferedTextOutput::BufferState> > states;
+};
+
+static mutex_t          gMutex;
+
+static thread_store_t   tls;
+
+BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState()
+{
+    ThreadState*  ts = (ThreadState*) thread_store_get( &tls );
+    if (ts) return ts;
+    ts = new ThreadState;
+    thread_store_set( &tls, ts, threadDestructor );
+    return ts;
+}
+
+void BufferedTextOutput::threadDestructor(void *st)
+{
+    delete ((ThreadState*)st);
+}
+
+static volatile int32_t gSequence = 0;
+
+static volatile int32_t gFreeBufferIndex = -1;
+
+static int32_t allocBufferIndex()
+{
+    int32_t res = -1;
+    
+    mutex_lock(&gMutex);
+    
+    if (gFreeBufferIndex >= 0) {
+        res = gFreeBufferIndex;
+        gFreeBufferIndex = gTextBuffers[res];
+        gTextBuffers.editItemAt(res) = -1;
+
+    } else {
+        res = gTextBuffers.size();
+        gTextBuffers.add(-1);
+    }
+
+    mutex_unlock(&gMutex);
+    
+    return res;
+}
+
+static void freeBufferIndex(int32_t idx)
+{
+    mutex_lock(&gMutex);
+    gTextBuffers.editItemAt(idx) = gFreeBufferIndex;
+    gFreeBufferIndex = idx;
+    mutex_unlock(&gMutex);
+}
+
+// ---------------------------------------------------------------------------
+
+BufferedTextOutput::BufferedTextOutput(uint32_t flags)
+    : mFlags(flags)
+    , mSeq(android_atomic_inc(&gSequence))
+    , mIndex(allocBufferIndex())
+{
+    mGlobalState = new BufferState(mSeq);
+    if (mGlobalState) mGlobalState->incStrong(this);
+}
+    
+BufferedTextOutput::~BufferedTextOutput()
+{
+    if (mGlobalState) mGlobalState->decStrong(this);
+    freeBufferIndex(mIndex);
+}
+
+status_t BufferedTextOutput::print(const char* txt, size_t len)
+{
+    //printf("BufferedTextOutput: printing %d\n", len);
+    
+    AutoMutex _l(mLock);
+    BufferState* b = getBuffer();
+    
+    const char* const end = txt+len;
+    
+    status_t err;
+
+    while (txt < end) {
+        // Find the next line.
+        const char* first = txt;
+        while (txt < end && *txt != '\n') txt++;
+        
+        // Include this and all following empty lines.
+        while (txt < end && *txt == '\n') txt++;
+        
+        // Special cases for first data on a line.
+        if (b->atFront) {
+            if (b->indent > 0) {
+                // If this is the start of a line, add the indent.
+                const char* prefix = stringForIndent(b->indent);
+                err = b->append(prefix, strlen(prefix));
+                if (err != NO_ERROR) return err;
+                
+            } else if (*(txt-1) == '\n' && !b->bundle) {
+                // Fast path: if we are not indenting or bundling, and
+                // have been given one or more complete lines, just write
+                // them out without going through the buffer.
+                
+                // Slurp up all of the lines.
+                const char* lastLine = txt+1;
+                while (txt < end) {
+                    if (*txt++ == '\n') lastLine = txt;
+                }
+                struct iovec vec;
+                vec.iov_base = (void*)first;
+                vec.iov_len = lastLine-first;
+                //printf("Writing %d bytes of data!\n", vec.iov_len);
+                writeLines(vec, 1);
+                txt = lastLine;
+                continue;
+            }
+        }
+        
+        // Append the new text to the buffer.
+        err = b->append(first, txt-first);
+        if (err != NO_ERROR) return err;
+        b->atFront = *(txt-1) == '\n';
+        
+        // If we have finished a line and are not bundling, write
+        // it out.
+        //printf("Buffer is now %d bytes\n", b->bufferPos);
+        if (b->atFront && !b->bundle) {
+            struct iovec vec;
+            vec.iov_base = b->buffer;
+            vec.iov_len = b->bufferPos;
+            //printf("Writing %d bytes of data!\n", vec.iov_len);
+            writeLines(vec, 1);
+            b->restart();
+        }
+    }
+    
+    return NO_ERROR;
+}
+
+void BufferedTextOutput::moveIndent(int delta)
+{
+    AutoMutex _l(mLock);
+    BufferState* b = getBuffer();
+    b->indent += delta;
+    if (b->indent < 0) b->indent = 0;
+}
+
+void BufferedTextOutput::pushBundle()
+{
+    AutoMutex _l(mLock);
+    BufferState* b = getBuffer();
+    b->bundle++;
+}
+
+void BufferedTextOutput::popBundle()
+{
+    AutoMutex _l(mLock);
+    BufferState* b = getBuffer();
+    b->bundle--;
+    LOG_FATAL_IF(b->bundle < 0,
+        "TextOutput::popBundle() called more times than pushBundle()");
+    if (b->bundle < 0) b->bundle = 0;
+    
+    if (b->bundle == 0) {
+        // Last bundle, write out data if it is complete.  If it is not
+        // complete, don't write until the last line is done... this may
+        // or may not be the write thing to do, but it's the easiest.
+        if (b->bufferPos > 0 && b->atFront) {
+            struct iovec vec;
+            vec.iov_base = b->buffer;
+            vec.iov_len = b->bufferPos;
+            writeLines(vec, 1);
+            b->restart();
+        }
+    }
+}
+
+BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const
+{
+    if ((mFlags&MULTITHREADED) != 0) {
+        ThreadState* ts = getThreadState();
+        if (ts) {
+            while (ts->states.size() <= (size_t)mIndex) ts->states.add(NULL);
+            BufferState* bs = ts->states[mIndex].get();
+            if (bs != NULL && bs->seq == mSeq) return bs;
+            
+            ts->states.editItemAt(mIndex) = new BufferState(mIndex);
+            bs = ts->states[mIndex].get();
+            if (bs != NULL) return bs;
+        }
+    }
+    
+    return mGlobalState;
+}
+
+}; // namespace android
diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp
new file mode 100644
index 0000000..26fb22a
--- /dev/null
+++ b/libs/utils/CallStack.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "CallStack"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if HAVE_DLADDR
+#include <dlfcn.h>
+#endif
+
+#if HAVE_CXXABI
+#include <cxxabi.h>
+#endif
+
+#include <unwind.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/CallStack.h>
+#include <utils/threads.h>
+
+
+/*****************************************************************************/
+namespace android {
+
+
+typedef struct {
+    size_t count;
+    size_t ignore;
+    const void** addrs;
+} stack_crawl_state_t;
+
+static
+_Unwind_Reason_Code trace_function(_Unwind_Context *context, void *arg)
+{
+    stack_crawl_state_t* state = (stack_crawl_state_t*)arg;
+    if (state->count) {
+        void* ip = (void*)_Unwind_GetIP(context);
+        if (ip) {
+            if (state->ignore) {
+                state->ignore--;
+            } else {
+                state->addrs[0] = ip; 
+                state->addrs++;
+                state->count--;
+            }
+        }
+    }
+    return _URC_NO_REASON;
+}
+
+static
+int backtrace(const void** addrs, size_t ignore, size_t size)
+{
+    stack_crawl_state_t state;
+    state.count = size;
+    state.ignore = ignore;
+    state.addrs = addrs;
+    _Unwind_Backtrace(trace_function, (void*)&state);
+    return size - state.count;
+}
+
+/*****************************************************************************/
+
+static 
+const char *lookup_symbol(const void* addr, void **offset, char* name, size_t bufSize)
+{
+#if HAVE_DLADDR
+    Dl_info info;
+    if (dladdr(addr, &info)) {
+        *offset = info.dli_saddr;
+        return info.dli_sname;
+    }
+#endif
+    return NULL;
+}
+
+static 
+int32_t linux_gcc_demangler(const char *mangled_name, char *unmangled_name, size_t buffersize)
+{
+    size_t out_len = 0;
+#if HAVE_CXXABI
+    int status = 0;
+    char *demangled = abi::__cxa_demangle(mangled_name, 0, &out_len, &status);
+    if (status == 0) {
+        // OK
+        if (out_len < buffersize) memcpy(unmangled_name, demangled, out_len);
+        else out_len = 0;
+        free(demangled);
+    } else {
+        out_len = 0;
+    }
+#endif
+    return out_len;
+}
+
+/*****************************************************************************/
+
+class MapInfo {
+    struct mapinfo {
+        struct mapinfo *next;
+        uint64_t start;
+        uint64_t end;
+        char name[];
+    };
+
+    const char *map_to_name(uint64_t pc, const char* def) {
+        mapinfo* mi = getMapInfoList();
+        while(mi) {
+            if ((pc >= mi->start) && (pc < mi->end))
+                return mi->name;
+            mi = mi->next;
+        }
+        return def;
+    }
+
+    mapinfo *parse_maps_line(char *line) {
+        mapinfo *mi;
+        int len = strlen(line);
+        if (len < 1) return 0;
+        line[--len] = 0;
+        if (len < 50) return 0;
+        if (line[20] != 'x') return 0;
+        mi = (mapinfo*)malloc(sizeof(mapinfo) + (len - 47));
+        if (mi == 0) return 0;
+        mi->start = strtoull(line, 0, 16);
+        mi->end = strtoull(line + 9, 0, 16);
+        mi->next = 0;
+        strcpy(mi->name, line + 49);
+        return mi;
+    }
+
+    mapinfo* getMapInfoList() {
+        Mutex::Autolock _l(mLock);
+        if (milist == 0) {
+            char data[1024];
+            FILE *fp;
+            sprintf(data, "/proc/%d/maps", getpid());
+            fp = fopen(data, "r");
+            if (fp) {
+                while(fgets(data, 1024, fp)) {
+                    mapinfo *mi = parse_maps_line(data);
+                    if(mi) {
+                        mi->next = milist;
+                        milist = mi;
+                    }
+                }
+                fclose(fp);
+            }
+        }
+        return milist;
+    }
+    mapinfo*    milist;
+    Mutex       mLock;
+    static MapInfo sMapInfo;
+
+public:
+    MapInfo()
+     : milist(0) {
+    }
+
+    ~MapInfo() {
+        while (milist) {
+            mapinfo *next = milist->next;
+            free(milist);
+            milist = next;
+        }
+    }
+    
+    static const char *mapAddressToName(const void* pc, const char* def) {
+        return sMapInfo.map_to_name((uint64_t)pc, def);
+    }
+
+};
+
+/*****************************************************************************/
+
+MapInfo MapInfo::sMapInfo;
+
+/*****************************************************************************/
+
+CallStack::CallStack()
+    : mCount(0)
+{
+}
+
+CallStack::CallStack(const CallStack& rhs)
+    : mCount(rhs.mCount)
+{
+    if (mCount) {
+        memcpy(mStack, rhs.mStack, mCount*sizeof(void*));
+    }
+}
+
+CallStack::~CallStack()
+{
+}
+
+CallStack& CallStack::operator = (const CallStack& rhs)
+{
+    mCount = rhs.mCount;
+    if (mCount) {
+        memcpy(mStack, rhs.mStack, mCount*sizeof(void*));
+    }
+    return *this;
+}
+
+bool CallStack::operator == (const CallStack& rhs) const {
+    if (mCount != rhs.mCount)
+        return false;
+    return !mCount || (memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) == 0);
+}
+
+bool CallStack::operator != (const CallStack& rhs) const {
+    return !operator == (rhs);
+}
+
+bool CallStack::operator < (const CallStack& rhs) const {
+    if (mCount != rhs.mCount)
+        return mCount < rhs.mCount;
+    return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) < 0;
+}
+
+bool CallStack::operator >= (const CallStack& rhs) const {
+    return !operator < (rhs);
+}
+
+bool CallStack::operator > (const CallStack& rhs) const {
+    if (mCount != rhs.mCount)
+        return mCount > rhs.mCount;
+    return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) > 0;
+}
+
+bool CallStack::operator <= (const CallStack& rhs) const {
+    return !operator > (rhs);
+}
+
+const void* CallStack::operator [] (int index) const {
+    if (index >= int(mCount))
+        return 0;
+    return mStack[index];
+}
+
+
+void CallStack::clear()
+{
+    mCount = 0;
+}
+
+void CallStack::update(int32_t ignoreDepth, int32_t maxDepth)
+{
+    if (maxDepth > MAX_DEPTH)
+        maxDepth = MAX_DEPTH;
+    mCount = backtrace(mStack, ignoreDepth, maxDepth);
+}
+
+// Return the stack frame name on the designated level
+String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const
+{
+    String8 res;
+    char namebuf[1024];
+    char tmp[256];
+    char tmp1[32];
+    char tmp2[32];
+    void *offs;
+
+    const void* ip = mStack[level];
+    if (!ip) return res;
+
+    if (prefix) res.append(prefix);
+    snprintf(tmp1, 32, "#%02d  ", level);
+    res.append(tmp1);
+
+    const char* name = lookup_symbol(ip, &offs, namebuf, sizeof(namebuf));
+    if (name) {
+        if (linux_gcc_demangler(name, tmp, 256) != 0)
+            name = tmp;
+        snprintf(tmp1, 32, "0x%p: <", ip);
+        snprintf(tmp2, 32, ">+0x%p", offs);
+        res.append(tmp1);
+        res.append(name);
+        res.append(tmp2);
+    } else { 
+        name = MapInfo::mapAddressToName(ip, "<unknown>");
+        snprintf(tmp, 256, "pc %p  %s", ip, name);
+        res.append(tmp);
+    }
+    res.append("\n");
+
+    return res;
+}
+
+// Dump a stack trace to the log
+void CallStack::dump(const char* prefix) const
+{
+    /* 
+     * Sending a single long log may be truncated since the stack levels can
+     * get very deep. So we request function names of each frame individually.
+     */
+    for (int i=0; i<int(mCount); i++) {
+        LOGD("%s", toStringSingleLevel(prefix, i).string());
+    }
+}
+
+// Return a string (possibly very long) containing the complete stack trace
+String8 CallStack::toString(const char* prefix) const
+{
+    String8 res;
+
+    for (int i=0; i<int(mCount); i++) {
+        res.append(toStringSingleLevel(prefix, i).string());
+    }
+
+    return res;
+}
+
+/*****************************************************************************/
+
+}; // namespace android
diff --git a/libs/utils/Debug.cpp b/libs/utils/Debug.cpp
new file mode 100644
index 0000000..f7988ec
--- /dev/null
+++ b/libs/utils/Debug.cpp
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2005 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 <utils/Debug.h>
+
+#include <utils/misc.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------
+
+static const char indentStr[] =
+"                                                                            "
+"                                                                            ";
+
+const char* stringForIndent(int32_t indentLevel)
+{
+    ssize_t off = sizeof(indentStr)-1-(indentLevel*2);
+    return indentStr + (off < 0 ? 0 : off);
+}
+
+// ---------------------------------------------------------------------
+
+static void defaultPrintFunc(void* cookie, const char* txt)
+{
+    printf("%s", txt);
+}
+
+// ---------------------------------------------------------------------
+
+static inline int isident(int c)
+{
+    return isalnum(c) || c == '_';
+}
+
+static inline bool isasciitype(char c)
+{
+    if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true;
+    return false;
+}
+
+static inline char makehexdigit(uint32_t val)
+{
+    return "0123456789abcdef"[val&0xF];
+}
+
+static char* appendhexnum(uint32_t val, char* out)
+{
+    for( int32_t i=28; i>=0; i-=4 ) {
+        *out++ = makehexdigit( val>>i );
+    }
+    *out = 0;
+    return out;
+}
+
+static inline char makeupperhexdigit(uint32_t val)
+{
+    return "0123456789ABCDEF"[val&0xF];
+}
+
+static char* appendupperhexnum(uint32_t val, char* out)
+{
+    for( int32_t i=28; i>=0; i-=4 ) {
+        *out++ = makeupperhexdigit( val>>i );
+    }
+    *out = 0;
+    return out;
+}
+
+static char* appendcharornum(char c, char* out, bool skipzero = true)
+{
+    if (skipzero && c == 0) return out;
+
+    if (isasciitype(c)) {
+        *out++ = c;
+        return out;
+    }
+
+    *out++ = '\\';
+    *out++ = 'x';
+    *out++ = makehexdigit(c>>4);
+    *out++ = makehexdigit(c);
+    return out;
+}
+
+static char* typetostring(uint32_t type, char* out,
+                          bool fullContext = true,
+                          bool strict = false)
+{
+    char* pos = out;
+    char c[4];
+    c[0] = (char)((type>>24)&0xFF);
+    c[1] = (char)((type>>16)&0xFF);
+    c[2] = (char)((type>>8)&0xFF);
+    c[3] = (char)(type&0xFF);
+    bool valid;
+    if( !strict ) {
+        // now even less strict!
+        // valid = isasciitype(c[3]);
+        valid = true;
+        int32_t i = 0;
+        bool zero = true;
+        while (valid && i<3) {
+            if (c[i] == 0) {
+                if (!zero) valid = false;
+            } else {
+                zero = false;
+                //if (!isasciitype(c[i])) valid = false;
+            }
+            i++;
+        }
+        // if all zeros, not a valid type code.
+        if (zero) valid = false;
+    } else {
+        valid = isident(c[3]) ? true : false;
+        int32_t i = 0;
+        bool zero = true;
+        while (valid && i<3) {
+            if (c[i] == 0) {
+                if (!zero) valid = false;
+            } else {
+                zero = false;
+                if (!isident(c[i])) valid = false;
+            }
+            i++;
+        }
+    }
+    if( valid && (!fullContext || c[0] != '0' || c[1] != 'x') ) {
+        if( fullContext ) *pos++ = '\'';
+        pos = appendcharornum(c[0], pos);
+        pos = appendcharornum(c[1], pos);
+        pos = appendcharornum(c[2], pos);
+        pos = appendcharornum(c[3], pos);
+        if( fullContext ) *pos++ = '\'';
+        *pos = 0;
+        return pos;
+    }
+    
+    if( fullContext ) {
+        *pos++ = '0';
+        *pos++ = 'x';
+    }
+    return appendhexnum(type, pos);
+}
+
+void printTypeCode(uint32_t typeCode, debugPrintFunc func, void* cookie)
+{
+    char buffer[32];
+    char* end = typetostring(typeCode, buffer);
+    *end = 0;
+    func ? (*func)(cookie, buffer) : defaultPrintFunc(cookie, buffer);
+}
+
+void printHexData(int32_t indent, const void *buf, size_t length,
+    size_t bytesPerLine, int32_t singleLineBytesCutoff,
+    size_t alignment, bool cStyle,
+    debugPrintFunc func, void* cookie)
+{
+    if (alignment == 0) {
+        if (bytesPerLine >= 16) alignment = 4;
+        else if (bytesPerLine >= 8) alignment = 2;
+        else alignment = 1;
+    }
+    if (func == NULL) func = defaultPrintFunc;
+
+    size_t offset;
+    
+    unsigned char *pos = (unsigned char *)buf;
+    
+    if (pos == NULL) {
+        if (singleLineBytesCutoff < 0) func(cookie, "\n");
+        func(cookie, "(NULL)");
+        return;
+    }
+    
+    if (length == 0) {
+        if (singleLineBytesCutoff < 0) func(cookie, "\n");
+        func(cookie, "(empty)");
+        return;
+    }
+    
+    if ((int32_t)length < 0) {
+        if (singleLineBytesCutoff < 0) func(cookie, "\n");
+        char buf[64];
+        sprintf(buf, "(bad length: %d)", length);
+        func(cookie, buf);
+        return;
+    }
+    
+    char buffer[256];
+    static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1);
+    
+    if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine;
+    
+    const bool oneLine = (int32_t)length <= singleLineBytesCutoff;
+    bool newLine = false;
+    if (cStyle) {
+        indent++;
+        func(cookie, "{\n");
+        newLine = true;
+    } else if (!oneLine) {
+        func(cookie, "\n");
+        newLine = true;
+    }
+    
+    for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) {
+        long remain = length;
+
+        char* c = buffer;
+        if (!oneLine && !cStyle) {
+            sprintf(c, "0x%08x: ", (int)offset);
+            c += 12;
+        }
+
+        size_t index;
+        size_t word;
+        
+        for (word = 0; word < bytesPerLine; ) {
+
+#ifdef HAVE_LITTLE_ENDIAN
+            const size_t startIndex = word+(alignment-(alignment?1:0));
+            const ssize_t dir = -1;
+#else
+            const size_t startIndex = word;
+            const ssize_t dir = 1;
+#endif
+
+            for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) {
+            
+                if (!cStyle) {
+                    if (index == 0 && word > 0 && alignment > 0) {
+                        *c++ = ' ';
+                    }
+                
+                    if (remain-- > 0) {
+                        const unsigned char val = *(pos+startIndex+(index*dir));
+                        *c++ = makehexdigit(val>>4);
+                        *c++ = makehexdigit(val);
+                    } else if (!oneLine) {
+                        *c++ = ' ';
+                        *c++ = ' ';
+                    }
+                } else {
+                    if (remain > 0) {
+                        if (index == 0 && word > 0) {
+                            *c++ = ',';
+                            *c++ = ' ';
+                        }
+                        if (index == 0) {
+                            *c++ = '0';
+                            *c++ = 'x';
+                        }
+                        const unsigned char val = *(pos+startIndex+(index*dir));
+                        *c++ = makehexdigit(val>>4);
+                        *c++ = makehexdigit(val);
+                        remain--;
+                    }
+                }
+            }
+            
+            word += index;
+        }
+
+        if (!cStyle) {
+            remain = length;
+            *c++ = ' ';
+            *c++ = '\'';
+            for (index = 0; index < bytesPerLine; index++) {
+
+                if (remain-- > 0) {
+                    const unsigned char val = pos[index];
+                    *c++ = (val >= ' ' && val < 127) ? val : '.';
+                } else if (!oneLine) {
+                    *c++ = ' ';
+                }
+            }
+            
+            *c++ = '\'';
+            if (length > bytesPerLine) *c++ = '\n';
+        } else {
+            if (remain > 0) *c++ = ',';
+            *c++ = '\n';
+        }
+
+        if (newLine && indent) func(cookie, stringForIndent(indent));
+        *c = 0;
+        func(cookie, buffer);
+        newLine = true;
+        
+        if (length <= bytesPerLine) break;
+        length -= bytesPerLine;
+    }
+
+    if (cStyle) {
+        if (indent > 0) func(cookie, stringForIndent(indent-1));
+        func(cookie, "};");
+    }
+}
+
+}; // namespace android
+
diff --git a/libs/utils/FileMap.cpp b/libs/utils/FileMap.cpp
new file mode 100644
index 0000000..e1ba9b2
--- /dev/null
+++ b/libs/utils/FileMap.cpp
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+//
+// Shared file mapping class.
+//
+
+#define LOG_TAG "filemap"
+
+#include <utils/FileMap.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_POSIX_FILEMAP
+#include <sys/mman.h>
+#endif
+
+#include <string.h>
+#include <memory.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*static*/ long FileMap::mPageSize = -1;
+
+
+/*
+ * Constructor.  Create an empty object.
+ */
+FileMap::FileMap(void)
+    : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
+      mDataPtr(NULL), mDataLength(0)
+{
+}
+
+/*
+ * Destructor.
+ */
+FileMap::~FileMap(void)
+{
+    assert(mRefCount == 0);
+
+    //printf("+++ removing FileMap %p %u\n", mDataPtr, mDataLength);
+
+    mRefCount = -100;       // help catch double-free
+    if (mFileName != NULL) {
+        free(mFileName);
+    }
+#ifdef HAVE_POSIX_FILEMAP    
+    if (munmap(mBasePtr, mBaseLength) != 0) {
+        LOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength);
+    }
+#endif
+#ifdef HAVE_WIN32_FILEMAP
+    if ( UnmapViewOfFile(mBasePtr) == 0) {
+        LOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr, 
+              GetLastError() );
+    }
+    CloseHandle(mFileMapping);
+    CloseHandle(mFileHandle);
+#endif
+}
+
+
+/*
+ * Create a new mapping on an open file.
+ *
+ * Closing the file descriptor does not unmap the pages, so we don't
+ * claim ownership of the fd.
+ *
+ * Returns "false" on failure.
+ */
+bool FileMap::create(const char* origFileName, int fd, off_t offset, size_t length, bool readOnly)
+{
+#ifdef HAVE_WIN32_FILEMAP
+    int     adjust;
+    off_t   adjOffset;
+    size_t  adjLength;
+
+    if (mPageSize == -1) {
+        SYSTEM_INFO  si;
+        
+        GetSystemInfo( &si );
+        mPageSize = si.dwAllocationGranularity;
+    }
+
+    DWORD  protect = readOnly ? PAGE_READONLY : PAGE_READWRITE;
+    
+    mFileHandle  = (HANDLE) _get_osfhandle(fd);
+    mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL);
+    if (mFileMapping == NULL) {
+        LOGE("CreateFileMapping(%p, %lx) failed with error %ld\n",
+              mFileHandle, protect, GetLastError() );
+        return false;
+    }
+    
+    adjust    = offset % mPageSize;
+    adjOffset = offset - adjust;
+    adjLength = length + adjust;
+    
+    mBasePtr = MapViewOfFile( mFileMapping, 
+                              readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
+                              0,
+                              (DWORD)(adjOffset),
+                              adjLength );
+    if (mBasePtr == NULL) {
+        LOGE("MapViewOfFile(%ld, %ld) failed with error %ld\n",
+              adjOffset, adjLength, GetLastError() );
+        CloseHandle(mFileMapping);
+        mFileMapping = INVALID_HANDLE_VALUE;
+        return false;
+    }
+#endif
+#ifdef HAVE_POSIX_FILEMAP
+    int     prot, flags, adjust;
+    off_t   adjOffset;
+    size_t  adjLength;
+
+    void* ptr;
+
+    assert(mRefCount == 1);
+    assert(fd >= 0);
+    assert(offset >= 0);
+    assert(length > 0);
+
+    /* init on first use */
+    if (mPageSize == -1) {
+#if NOT_USING_KLIBC
+        mPageSize = sysconf(_SC_PAGESIZE);
+        if (mPageSize == -1) {
+            LOGE("could not get _SC_PAGESIZE\n");
+            return false;
+        }
+#else
+        /* this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM */
+        mPageSize = 4096;
+#endif
+    }
+
+    adjust   = offset % mPageSize;
+try_again:
+    adjOffset = offset - adjust;
+    adjLength = length + adjust;
+
+    flags = MAP_SHARED;
+    prot = PROT_READ;
+    if (!readOnly)
+        prot |= PROT_WRITE;
+
+    ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset);
+    if (ptr == MAP_FAILED) {
+    	// Cygwin does not seem to like file mapping files from an offset.
+    	// So if we fail, try again with offset zero
+    	if (adjOffset > 0) {
+    		adjust = offset;
+    		goto try_again;
+    	}
+    
+        LOGE("mmap(%ld,%ld) failed: %s\n",
+            (long) adjOffset, (long) adjLength, strerror(errno));
+        return false;
+    }
+    mBasePtr = ptr;
+#endif /* HAVE_POSIX_FILEMAP */
+
+    mFileName = origFileName != NULL ? strdup(origFileName) : NULL;
+    mBaseLength = adjLength;
+    mDataOffset = offset;
+    mDataPtr = (char*) mBasePtr + adjust;
+    mDataLength = length;
+
+    assert(mBasePtr != NULL);
+
+    LOGV("MAP: base %p/%d data %p/%d\n",
+        mBasePtr, (int) mBaseLength, mDataPtr, (int) mDataLength);
+
+    return true;
+}
+
+/*
+ * Provide guidance to the system.
+ */
+int FileMap::advise(MapAdvice advice)
+{
+#if HAVE_MADVISE
+    int cc, sysAdvice;
+
+    switch (advice) {
+        case NORMAL:        sysAdvice = MADV_NORMAL;        break;
+        case RANDOM:        sysAdvice = MADV_RANDOM;        break;
+        case SEQUENTIAL:    sysAdvice = MADV_SEQUENTIAL;    break;
+        case WILLNEED:      sysAdvice = MADV_WILLNEED;      break;
+        case DONTNEED:      sysAdvice = MADV_DONTNEED;      break;
+        default:
+                            assert(false);
+                            return -1;
+    }
+
+    cc = madvise(mBasePtr, mBaseLength, sysAdvice);
+    if (cc != 0)
+        LOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
+    return cc;
+#else
+	return -1;
+#endif // HAVE_MADVISE
+}
diff --git a/libs/utils/IDataConnection.cpp b/libs/utils/IDataConnection.cpp
new file mode 100644
index 0000000..c6d49aa
--- /dev/null
+++ b/libs/utils/IDataConnection.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <utils/IDataConnection.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+enum
+{
+    CONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+    DISCONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1
+};
+
+class BpDataConnection : public BpInterface<IDataConnection>
+{
+public:
+    BpDataConnection::BpDataConnection(const sp<IBinder>& impl)
+        : BpInterface<IDataConnection>(impl)
+    {
+    }
+
+	virtual void connect()
+	{
+		Parcel data, reply;
+        data.writeInterfaceToken(IDataConnection::descriptor());
+		remote()->transact(CONNECT_TRANSACTION, data, &reply);
+	}
+	
+	virtual void disconnect()
+	{
+		Parcel data, reply;
+		remote()->transact(DISCONNECT_TRANSACTION, data, &reply);
+	}
+};
+
+IMPLEMENT_META_INTERFACE(DataConnection, "android.utils.IDataConnection");
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnDataConnection::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code)
+    {
+		case CONNECT_TRANSACTION:
+		{                   
+            CHECK_INTERFACE(IDataConnection, data, reply);
+			connect();
+			return NO_ERROR;
+		}    
+		
+		case DISCONNECT_TRANSACTION:
+		{                   
+            CHECK_INTERFACE(IDataConnection, data, reply);
+			disconnect();
+			return NO_ERROR;
+		}
+       
+		default:
+			return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/utils/IInterface.cpp b/libs/utils/IInterface.cpp
new file mode 100644
index 0000000..6ea8178
--- /dev/null
+++ b/libs/utils/IInterface.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2005 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 <utils/IInterface.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+sp<IBinder> IInterface::asBinder()
+{
+    return this ? onAsBinder() : NULL;
+}
+
+sp<const IBinder> IInterface::asBinder() const
+{
+    return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/utils/IMemory.cpp b/libs/utils/IMemory.cpp
new file mode 100644
index 0000000..429bc2b
--- /dev/null
+++ b/libs/utils/IMemory.cpp
@@ -0,0 +1,486 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "IMemory"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <utils/IMemory.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+#include <utils/Parcel.h>
+#include <utils/CallStack.h>
+
+#define VERBOSE   0
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class HeapCache : public IBinder::DeathRecipient
+{
+public:
+    HeapCache();
+    virtual ~HeapCache();
+    
+    virtual void binderDied(const wp<IBinder>& who);
+
+    sp<IMemoryHeap> find_heap(const sp<IBinder>& binder); 
+    void pin_heap(const sp<IBinder>& binder); 
+    void free_heap(const sp<IBinder>& binder); 
+    sp<IMemoryHeap> get_heap(const sp<IBinder>& binder);
+    void dump_heaps();
+
+private:
+    // For IMemory.cpp
+    struct heap_info_t {
+        sp<IMemoryHeap> heap;
+        int32_t         count;
+    };
+
+    void free_heap(const wp<IBinder>& binder); 
+
+    Mutex mHeapCacheLock;
+    KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
+};
+
+static sp<HeapCache> gHeapCache = new HeapCache();
+
+/******************************************************************************/
+
+enum {
+    HEAP_ID = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMemoryHeap : public BpInterface<IMemoryHeap>
+{
+public:
+    BpMemoryHeap(const sp<IBinder>& impl);
+    virtual ~BpMemoryHeap();
+
+    virtual int getHeapID() const;
+    virtual void* getBase() const;
+    virtual size_t getSize() const;
+    virtual uint32_t getFlags() const;
+
+private:
+    friend class IMemory;
+    friend class HeapCache;
+    
+    // for debugging in this module
+    static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
+        return gHeapCache->find_heap(binder);
+    }
+    static inline void free_heap(const sp<IBinder>& binder) {
+        gHeapCache->free_heap(binder);
+    }
+    static inline sp<IMemoryHeap> get_heap(const sp<IBinder>& binder) {
+        return gHeapCache->get_heap(binder);
+    }
+    static inline void dump_heaps() {
+        gHeapCache->dump_heaps();       
+    }
+    void inline pin_heap() const {
+        gHeapCache->pin_heap(const_cast<BpMemoryHeap*>(this)->asBinder());
+    }
+
+    void assertMapped() const;
+    void assertReallyMapped() const;
+    void pinHeap() const;
+
+    mutable volatile int32_t mHeapId;
+    mutable void*       mBase;
+    mutable size_t      mSize;
+    mutable uint32_t    mFlags;
+    mutable bool        mRealHeap;
+    mutable Mutex       mLock;
+};
+
+// ----------------------------------------------------------------------------
+
+enum {
+    GET_MEMORY = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMemory : public BpInterface<IMemory>
+{
+public:
+    BpMemory(const sp<IBinder>& impl);
+    virtual ~BpMemory();
+    virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
+    
+private:
+    mutable sp<IMemoryHeap> mHeap;
+    mutable ssize_t mOffset;
+    mutable size_t mSize;
+};
+
+/******************************************************************************/
+
+void* IMemory::fastPointer(const sp<IBinder>& binder, ssize_t offset) const
+{
+    sp<IMemoryHeap> realHeap = BpMemoryHeap::get_heap(binder);
+    void* const base = realHeap->base();
+    if (base == MAP_FAILED)
+        return 0;
+    return static_cast<char*>(base) + offset;
+}
+
+void* IMemory::pointer() const {
+    ssize_t offset;
+    sp<IMemoryHeap> heap = getMemory(&offset);
+    void* const base = heap!=0 ? heap->base() : MAP_FAILED;
+    if (base == MAP_FAILED)
+        return 0;
+    return static_cast<char*>(base) + offset;
+}
+
+size_t IMemory::size() const {
+    size_t size;
+    getMemory(NULL, &size);
+    return size;
+}
+
+ssize_t IMemory::offset() const {
+    ssize_t offset;
+    getMemory(&offset);
+    return offset;
+}
+
+/******************************************************************************/
+
+BpMemory::BpMemory(const sp<IBinder>& impl)
+    : BpInterface<IMemory>(impl), mOffset(0), mSize(0)
+{
+}
+
+BpMemory::~BpMemory()
+{
+}
+
+sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
+{
+    if (mHeap == 0) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
+        if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
+            sp<IBinder> heap = reply.readStrongBinder();
+            ssize_t o = reply.readInt32();
+            size_t s = reply.readInt32();
+            if (heap != 0) {
+                mHeap = interface_cast<IMemoryHeap>(heap);
+                if (mHeap != 0) {
+                    mOffset = o;
+                    mSize = s;
+                }
+            }
+        }
+    }
+    if (offset) *offset = mOffset;
+    if (size) *size = mSize;
+    return mHeap;
+}
+
+// ---------------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory");
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnMemory::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case GET_MEMORY: {
+            CHECK_INTERFACE(IMemory, data, reply);
+            ssize_t offset;
+            size_t size;
+            reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() );
+            reply->writeInt32(offset);
+            reply->writeInt32(size);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+
+/******************************************************************************/
+
+BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)
+    : BpInterface<IMemoryHeap>(impl),
+        mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)
+{
+}
+
+BpMemoryHeap::~BpMemoryHeap() {
+    if (mHeapId != -1) {
+        close(mHeapId);
+        if (mRealHeap) {
+            // by construction we're the last one
+            if (mBase != MAP_FAILED) {
+                sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
+
+                if (VERBOSE) {
+                    LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d", 
+                            binder.get(), this, mSize, mHeapId);
+                    CallStack stack;
+                    stack.update();
+                    stack.dump("callstack");
+                }
+
+                munmap(mBase, mSize);
+            }
+        } else {
+            // remove from list only if it was mapped before
+            sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
+            free_heap(binder);
+        }
+    }
+}
+
+void BpMemoryHeap::assertMapped() const
+{
+    if (mHeapId == -1) {
+        sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());
+        sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
+        heap->assertReallyMapped();
+        if (heap->mBase != MAP_FAILED) {
+            Mutex::Autolock _l(mLock);
+            if (mHeapId == -1) {
+                mBase   = heap->mBase;
+                mSize   = heap->mSize;
+                android_atomic_write( dup( heap->mHeapId ), &mHeapId );
+            }
+        } else {
+            // something went wrong
+            free_heap(binder);
+        }
+    }
+}
+
+void BpMemoryHeap::assertReallyMapped() const
+{
+    if (mHeapId == -1) {
+
+        // remote call without mLock held, worse case scenario, we end up
+        // calling transact() from multiple threads, but that's not a problem,
+        // only mmap below must be in the critical section.
+        
+        Parcel data, reply;
+        data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
+        status_t err = remote()->transact(HEAP_ID, data, &reply);
+        int parcel_fd = reply.readFileDescriptor();
+        ssize_t size = reply.readInt32();
+        uint32_t flags = reply.readInt32();
+
+        LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%d, err=%d (%s)",
+                asBinder().get(), parcel_fd, size, err, strerror(-err));
+
+        int fd = dup( parcel_fd );
+        LOGE_IF(fd==-1, "cannot dup fd=%d, size=%d, err=%d (%s)",
+                parcel_fd, size, err, strerror(errno));
+
+        int access = PROT_READ;
+        if (!(flags & READ_ONLY)) {
+            access |= PROT_WRITE;
+        }
+
+        Mutex::Autolock _l(mLock);
+        if (mHeapId == -1) {
+            mRealHeap = true;
+            mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
+            if (mBase == MAP_FAILED) {
+                LOGE("cannot map BpMemoryHeap (binder=%p), size=%d, fd=%d (%s)",
+                        asBinder().get(), size, fd, strerror(errno));
+                close(fd);
+            } else {
+                if (flags & MAP_ONCE) {
+                    //LOGD("pinning heap (binder=%p, size=%d, fd=%d",
+                    //        asBinder().get(), size, fd);
+                    pin_heap();
+                }
+                mSize = size;
+                mFlags = flags;
+                android_atomic_write(fd, &mHeapId);
+            }
+        }
+    }
+}
+
+int BpMemoryHeap::getHeapID() const {
+    assertMapped();
+    return mHeapId;
+}
+
+void* BpMemoryHeap::getBase() const {
+    assertMapped();
+    return mBase;
+}
+
+size_t BpMemoryHeap::getSize() const {
+    assertMapped();
+    return mSize;
+}
+
+uint32_t BpMemoryHeap::getFlags() const {
+    assertMapped();
+    return mFlags;
+}
+
+// ---------------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
+
+status_t BnMemoryHeap::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+       case HEAP_ID: {
+            CHECK_INTERFACE(IMemoryHeap, data, reply);
+            reply->writeFileDescriptor(getHeapID());
+            reply->writeInt32(getSize());
+            reply->writeInt32(getFlags());
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+/*****************************************************************************/
+
+HeapCache::HeapCache()
+    : DeathRecipient()
+{
+}
+
+HeapCache::~HeapCache()
+{
+}
+
+void HeapCache::binderDied(const wp<IBinder>& binder)
+{
+    //LOGD("binderDied binder=%p", binder.unsafe_get());
+    free_heap(binder); 
+}
+
+sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder) 
+{
+    Mutex::Autolock _l(mHeapCacheLock);
+    ssize_t i = mHeapCache.indexOfKey(binder);
+    if (i>=0) {
+        heap_info_t& info = mHeapCache.editValueAt(i);
+        LOGD_IF(VERBOSE,
+                "found binder=%p, heap=%p, size=%d, fd=%d, count=%d", 
+                binder.get(), info.heap.get(),
+                static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
+                static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
+                info.count);
+        android_atomic_inc(&info.count);
+        return info.heap;
+    } else {
+        heap_info_t info;
+        info.heap = interface_cast<IMemoryHeap>(binder);
+        info.count = 1;
+        //LOGD("adding binder=%p, heap=%p, count=%d",
+        //      binder.get(), info.heap.get(), info.count);
+        mHeapCache.add(binder, info);
+        return info.heap;
+    }
+}
+
+void HeapCache::pin_heap(const sp<IBinder>& binder) 
+{
+    Mutex::Autolock _l(mHeapCacheLock);
+    ssize_t i = mHeapCache.indexOfKey(binder);
+    if (i>=0) {
+        heap_info_t& info(mHeapCache.editValueAt(i));
+        android_atomic_inc(&info.count);
+        binder->linkToDeath(this);
+    } else {
+        LOGE("pin_heap binder=%p not found!!!", binder.get());
+    }    
+}
+
+void HeapCache::free_heap(const sp<IBinder>& binder)  {
+    free_heap( wp<IBinder>(binder) );
+}
+
+void HeapCache::free_heap(const wp<IBinder>& binder) 
+{
+    sp<IMemoryHeap> rel;
+    {
+        Mutex::Autolock _l(mHeapCacheLock);
+        ssize_t i = mHeapCache.indexOfKey(binder);
+        if (i>=0) {
+            heap_info_t& info(mHeapCache.editValueAt(i));
+            int32_t c = android_atomic_dec(&info.count);
+            if (c == 1) {
+                LOGD_IF(VERBOSE,
+                        "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d", 
+                        binder.unsafe_get(), info.heap.get(),
+                        static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
+                        static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
+                        info.count);
+                rel = mHeapCache.valueAt(i).heap;
+                mHeapCache.removeItemsAt(i);
+            }
+        } else {
+            LOGE("free_heap binder=%p not found!!!", binder.unsafe_get());
+        }
+    }
+}
+
+sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder)
+{
+    sp<IMemoryHeap> realHeap;
+    Mutex::Autolock _l(mHeapCacheLock);
+    ssize_t i = mHeapCache.indexOfKey(binder);
+    if (i>=0)   realHeap = mHeapCache.valueAt(i).heap;
+    else        realHeap = interface_cast<IMemoryHeap>(binder);
+    return realHeap;
+}
+
+void HeapCache::dump_heaps() 
+{
+    Mutex::Autolock _l(mHeapCacheLock);
+    int c = mHeapCache.size();
+    for (int i=0 ; i<c ; i++) {
+        const heap_info_t& info = mHeapCache.valueAt(i);
+        BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
+        LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)",
+                mHeapCache.keyAt(i).unsafe_get(),
+                info.heap.get(), info.count, 
+                h->mHeapId, h->mBase, h->mSize);
+    }
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/utils/IPCThreadState.cpp b/libs/utils/IPCThreadState.cpp
new file mode 100644
index 0000000..04ae142
--- /dev/null
+++ b/libs/utils/IPCThreadState.cpp
@@ -0,0 +1,1030 @@
+/*
+ * Copyright (C) 2005 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 <utils/IPCThreadState.h>
+
+#include <utils/Binder.h>
+#include <utils/BpBinder.h>
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/TextOutput.h>
+#include <utils/threads.h>
+
+#include <private/utils/binder_module.h>
+#include <private/utils/Static.h>
+
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_WIN32_THREADS
+#include <windows.h>
+#endif
+
+
+#if LOG_NDEBUG
+
+#define IF_LOG_TRANSACTIONS() if (false)
+#define IF_LOG_COMMANDS() if (false)
+#define LOG_REMOTEREFS(...) 
+#define IF_LOG_REMOTEREFS() if (false)
+#define LOG_THREADPOOL(...) 
+#define LOG_ONEWAY(...) 
+
+#else
+
+#define IF_LOG_TRANSACTIONS() IF_LOG(LOG_VERBOSE, "transact")
+#define IF_LOG_COMMANDS() IF_LOG(LOG_VERBOSE, "ipc")
+#define LOG_REMOTEREFS(...) LOG(LOG_DEBUG, "remoterefs", __VA_ARGS__)
+#define IF_LOG_REMOTEREFS() IF_LOG(LOG_DEBUG, "remoterefs")
+#define LOG_THREADPOOL(...) LOG(LOG_DEBUG, "threadpool", __VA_ARGS__)
+#define LOG_ONEWAY(...) LOG(LOG_DEBUG, "ipc", __VA_ARGS__)
+
+#endif
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+static const char* getReturnString(size_t idx);
+static const char* getCommandString(size_t idx);
+static const void* printReturnCommand(TextOutput& out, const void* _cmd);
+static const void* printCommand(TextOutput& out, const void* _cmd);
+
+// This will result in a missing symbol failure if the IF_LOG_COMMANDS()
+// conditionals don't get stripped...  but that is probably what we want.
+#if !LOG_NDEBUG
+static const char *kReturnStrings[] = {
+#if 1 /* TODO: error update strings */
+    "unknown",
+#else
+    "BR_OK",
+    "BR_TIMEOUT",
+    "BR_WAKEUP",
+    "BR_TRANSACTION",
+    "BR_REPLY",
+    "BR_ACQUIRE_RESULT",
+    "BR_DEAD_REPLY",
+    "BR_TRANSACTION_COMPLETE",
+    "BR_INCREFS",
+    "BR_ACQUIRE",
+    "BR_RELEASE",
+    "BR_DECREFS",
+    "BR_ATTEMPT_ACQUIRE",
+    "BR_EVENT_OCCURRED",
+    "BR_NOOP",
+    "BR_SPAWN_LOOPER",
+    "BR_FINISHED",
+    "BR_DEAD_BINDER",
+    "BR_CLEAR_DEATH_NOTIFICATION_DONE"
+#endif
+};
+
+static const char *kCommandStrings[] = {
+#if 1 /* TODO: error update strings */
+    "unknown",
+#else
+    "BC_NOOP",
+    "BC_TRANSACTION",
+    "BC_REPLY",
+    "BC_ACQUIRE_RESULT",
+    "BC_FREE_BUFFER",
+    "BC_TRANSACTION_COMPLETE",
+    "BC_INCREFS",
+    "BC_ACQUIRE",
+    "BC_RELEASE",
+    "BC_DECREFS",
+    "BC_INCREFS_DONE",
+    "BC_ACQUIRE_DONE",
+    "BC_ATTEMPT_ACQUIRE",
+    "BC_RETRIEVE_ROOT_OBJECT",
+    "BC_SET_THREAD_ENTRY",
+    "BC_REGISTER_LOOPER",
+    "BC_ENTER_LOOPER",
+    "BC_EXIT_LOOPER",
+    "BC_SYNC",
+    "BC_STOP_PROCESS",
+    "BC_STOP_SELF",
+    "BC_REQUEST_DEATH_NOTIFICATION",
+    "BC_CLEAR_DEATH_NOTIFICATION",
+    "BC_DEAD_BINDER_DONE"
+#endif
+};
+
+static const char* getReturnString(size_t idx)
+{
+    if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[0]))
+        return kReturnStrings[idx];
+    else
+        return "unknown";
+}
+
+static const char* getCommandString(size_t idx)
+{
+    if (idx < sizeof(kCommandStrings) / sizeof(kCommandStrings[0]))
+        return kCommandStrings[idx];
+    else
+        return "unknown";
+}
+
+static const void* printBinderTransactionData(TextOutput& out, const void* data)
+{
+    const binder_transaction_data* btd =
+        (const binder_transaction_data*)data;
+    out << "target=" << btd->target.ptr << " (cookie " << btd->cookie << ")" << endl
+        << "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl
+        << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
+        << " bytes)" << endl
+        << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
+        << " bytes)" << endl;
+    return btd+1;
+}
+
+static const void* printReturnCommand(TextOutput& out, const void* _cmd)
+{
+    static const int32_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]);
+    
+    const int32_t* cmd = (const int32_t*)_cmd;
+    int32_t code = *cmd++;
+    if (code == BR_ERROR) {
+        out << "BR_ERROR: " << (void*)(*cmd++) << endl;
+        return cmd;
+    } else if (code < 0 || code >= N) {
+        out << "Unknown reply: " << code << endl;
+        return cmd;
+    }
+    
+    out << kReturnStrings[code];
+    switch (code) {
+        case BR_TRANSACTION:
+        case BR_REPLY: {
+            out << ": " << indent;
+            cmd = (const int32_t *)printBinderTransactionData(out, cmd);
+            out << dedent;
+        } break;
+        
+        case BR_ACQUIRE_RESULT: {
+            const int32_t res = *cmd++;
+            out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
+        } break;
+        
+        case BR_INCREFS:
+        case BR_ACQUIRE:
+        case BR_RELEASE:
+        case BR_DECREFS: {
+            const int32_t b = *cmd++;
+            const int32_t c = *cmd++;
+            out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
+        } break;
+    
+        case BR_ATTEMPT_ACQUIRE: {
+            const int32_t p = *cmd++;
+            const int32_t b = *cmd++;
+            const int32_t c = *cmd++;
+            out << ": target=" << (void*)b << " (cookie " << (void*)c
+                << "), pri=" << p;
+        } break;
+
+        case BR_DEAD_BINDER:
+        case BR_CLEAR_DEATH_NOTIFICATION_DONE: {
+            const int32_t c = *cmd++;
+            out << ": death cookie " << (void*)c;
+        } break;
+    }
+    
+    out << endl;
+    return cmd;
+}
+
+static const void* printCommand(TextOutput& out, const void* _cmd)
+{
+    static const int32_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
+    
+    const int32_t* cmd = (const int32_t*)_cmd;
+    int32_t code = *cmd++;
+    if (code < 0 || code >= N) {
+        out << "Unknown command: " << code << endl;
+        return cmd;
+    }
+    
+    out << kCommandStrings[code];
+    switch (code) {
+        case BC_TRANSACTION:
+        case BC_REPLY: {
+            out << ": " << indent;
+            cmd = (const int32_t *)printBinderTransactionData(out, cmd);
+            out << dedent;
+        } break;
+        
+        case BC_ACQUIRE_RESULT: {
+            const int32_t res = *cmd++;
+            out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
+        } break;
+        
+        case BC_FREE_BUFFER: {
+            const int32_t buf = *cmd++;
+            out << ": buffer=" << (void*)buf;
+        } break;
+        
+        case BC_INCREFS:
+        case BC_ACQUIRE:
+        case BC_RELEASE:
+        case BC_DECREFS: {
+            const int32_t d = *cmd++;
+            out << ": descriptor=" << (void*)d;
+        } break;
+    
+        case BC_INCREFS_DONE:
+        case BC_ACQUIRE_DONE: {
+            const int32_t b = *cmd++;
+            const int32_t c = *cmd++;
+            out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
+        } break;
+        
+        case BC_ATTEMPT_ACQUIRE: {
+            const int32_t p = *cmd++;
+            const int32_t d = *cmd++;
+            out << ": decriptor=" << (void*)d << ", pri=" << p;
+        } break;
+        
+        case BC_REQUEST_DEATH_NOTIFICATION:
+        case BC_CLEAR_DEATH_NOTIFICATION: {
+            const int32_t h = *cmd++;
+            const int32_t c = *cmd++;
+            out << ": handle=" << h << " (death cookie " << (void*)c << ")";
+        } break;
+
+        case BC_DEAD_BINDER_DONE: {
+            const int32_t c = *cmd++;
+            out << ": death cookie " << (void*)c;
+        } break;
+    }
+    
+    out << endl;
+    return cmd;
+}
+#endif
+
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+static bool gShutdown = false;
+
+IPCThreadState* IPCThreadState::self()
+{
+    if (gHaveTLS) {
+restart:
+        const pthread_key_t k = gTLS;
+        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
+        if (st) return st;
+        return new IPCThreadState;
+    }
+    
+    if (gShutdown) return NULL;
+    
+    pthread_mutex_lock(&gTLSMutex);
+    if (!gHaveTLS) {
+        if (pthread_key_create(&gTLS, threadDestructor) != 0) {
+            pthread_mutex_unlock(&gTLSMutex);
+            return NULL;
+        }
+        gHaveTLS = true;
+    }
+    pthread_mutex_unlock(&gTLSMutex);
+    goto restart;
+}
+
+void IPCThreadState::shutdown()
+{
+    gShutdown = true;
+    
+    if (gHaveTLS) {
+        // XXX Need to wait for all thread pool threads to exit!
+        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS);
+        if (st) {
+            delete st;
+            pthread_setspecific(gTLS, NULL);
+        }
+        gHaveTLS = false;
+    }
+}
+
+sp<ProcessState> IPCThreadState::process()
+{
+    return mProcess;
+}
+
+status_t IPCThreadState::clearLastError()
+{
+    const status_t err = mLastError;
+    mLastError = NO_ERROR;
+    return err;
+}
+
+int IPCThreadState::getCallingPid()
+{
+    return mCallingPid;
+}
+
+int IPCThreadState::getCallingUid()
+{
+    return mCallingUid;
+}
+
+int64_t IPCThreadState::clearCallingIdentity()
+{
+    int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
+    clearCaller();
+    return token;
+}
+
+void IPCThreadState::restoreCallingIdentity(int64_t token)
+{
+    mCallingUid = (int)(token>>32);
+    mCallingPid = (int)token;
+}
+
+void IPCThreadState::clearCaller()
+{
+    if (mProcess->supportsProcesses()) {
+        mCallingPid = getpid();
+        mCallingUid = getuid();
+    } else {
+        mCallingPid = -1;
+        mCallingUid = -1;
+    }
+}
+
+void IPCThreadState::flushCommands()
+{
+    if (mProcess->mDriverFD <= 0)
+        return;
+    talkWithDriver(false);
+}
+
+void IPCThreadState::joinThreadPool(bool isMain)
+{
+    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
+
+    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
+    
+    status_t result;
+    do {
+        int32_t cmd;
+        
+        // When we've cleared the incoming command queue, process any pending derefs
+        if (mIn.dataPosition() >= mIn.dataSize()) {
+            size_t numPending = mPendingWeakDerefs.size();
+            if (numPending > 0) {
+                for (size_t i = 0; i < numPending; i++) {
+                    RefBase::weakref_type* refs = mPendingWeakDerefs[i];
+                    refs->decWeak(mProcess.get());
+                }
+                mPendingWeakDerefs.clear();
+            }
+
+            numPending = mPendingStrongDerefs.size();
+            if (numPending > 0) {
+                for (size_t i = 0; i < numPending; i++) {
+                    BBinder* obj = mPendingStrongDerefs[i];
+                    obj->decStrong(mProcess.get());
+                }
+                mPendingStrongDerefs.clear();
+            }
+        }
+
+        // now get the next command to be processed, waiting if necessary
+        result = talkWithDriver();
+        if (result >= NO_ERROR) {
+            size_t IN = mIn.dataAvail();
+            if (IN < sizeof(int32_t)) continue;
+            cmd = mIn.readInt32();
+            IF_LOG_COMMANDS() {
+                alog << "Processing top-level Command: "
+                    << getReturnString(cmd) << endl;
+            }
+            result = executeCommand(cmd);
+        }
+        
+        // Let this thread exit the thread pool if it is no longer
+        // needed and it is not the main process thread.
+        if(result == TIMED_OUT && !isMain) {
+            break;
+        }
+    } while (result != -ECONNREFUSED && result != -EBADF);
+
+    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
+        (void*)pthread_self(), getpid(), (void*)result);
+    
+    mOut.writeInt32(BC_EXIT_LOOPER);
+    talkWithDriver(false);
+}
+
+void IPCThreadState::stopProcess(bool immediate)
+{
+    //LOGI("**** STOPPING PROCESS");
+    flushCommands();
+    int fd = mProcess->mDriverFD;
+    mProcess->mDriverFD = -1;
+    close(fd);
+    //kill(getpid(), SIGKILL);
+}
+
+status_t IPCThreadState::transact(int32_t handle,
+                                  uint32_t code, const Parcel& data,
+                                  Parcel* reply, uint32_t flags)
+{
+    status_t err = data.errorCheck();
+
+    flags |= TF_ACCEPT_FDS;
+
+    IF_LOG_TRANSACTIONS() {
+        TextOutput::Bundle _b(alog);
+        alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
+            << handle << " / code " << TypeCode(code) << ": "
+            << indent << data << dedent << endl;
+    }
+    
+    if (err == NO_ERROR) {
+        LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
+            (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
+        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
+    }
+    
+    if (err != NO_ERROR) {
+        if (reply) reply->setError(err);
+        return (mLastError = err);
+    }
+    
+    if ((flags & TF_ONE_WAY) == 0) {
+        if (reply) {
+            err = waitForResponse(reply);
+        } else {
+            Parcel fakeReply;
+            err = waitForResponse(&fakeReply);
+        }
+        
+        IF_LOG_TRANSACTIONS() {
+            TextOutput::Bundle _b(alog);
+            alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
+                << handle << ": ";
+            if (reply) alog << indent << *reply << dedent << endl;
+            else alog << "(none requested)" << endl;
+        }
+    } else {
+        err = waitForResponse(NULL, NULL);
+    }
+    
+    return err;
+}
+
+void IPCThreadState::incStrongHandle(int32_t handle)
+{
+    LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle);
+    mOut.writeInt32(BC_ACQUIRE);
+    mOut.writeInt32(handle);
+}
+
+void IPCThreadState::decStrongHandle(int32_t handle)
+{
+    LOG_REMOTEREFS("IPCThreadState::decStrongHandle(%d)\n", handle);
+    mOut.writeInt32(BC_RELEASE);
+    mOut.writeInt32(handle);
+}
+
+void IPCThreadState::incWeakHandle(int32_t handle)
+{
+    LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
+    mOut.writeInt32(BC_INCREFS);
+    mOut.writeInt32(handle);
+}
+
+void IPCThreadState::decWeakHandle(int32_t handle)
+{
+    LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle);
+    mOut.writeInt32(BC_DECREFS);
+    mOut.writeInt32(handle);
+}
+
+status_t IPCThreadState::attemptIncStrongHandle(int32_t handle)
+{
+    mOut.writeInt32(BC_ATTEMPT_ACQUIRE);
+    mOut.writeInt32(0); // xxx was thread priority
+    mOut.writeInt32(handle);
+    status_t result = UNKNOWN_ERROR;
+    
+    waitForResponse(NULL, &result);
+    
+#if LOG_REFCOUNTS
+    printf("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
+        handle, result == NO_ERROR ? "SUCCESS" : "FAILURE");
+#endif
+    
+    return result;
+}
+
+void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder)
+{
+#if LOG_REFCOUNTS
+    printf("IPCThreadState::expungeHandle(%ld)\n", handle);
+#endif
+    self()->mProcess->expungeHandle(handle, binder);
+}
+
+status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
+{
+    mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
+    mOut.writeInt32((int32_t)handle);
+    mOut.writeInt32((int32_t)proxy);
+    return NO_ERROR;
+}
+
+status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
+{
+    mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION);
+    mOut.writeInt32((int32_t)handle);
+    mOut.writeInt32((int32_t)proxy);
+    return NO_ERROR;
+}
+
+IPCThreadState::IPCThreadState()
+    : mProcess(ProcessState::self())
+{
+    pthread_setspecific(gTLS, this);
+        clearCaller();
+    mIn.setDataCapacity(256);
+    mOut.setDataCapacity(256);
+}
+
+IPCThreadState::~IPCThreadState()
+{
+}
+
+status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
+{
+    status_t err;
+    status_t statusBuffer;
+    err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
+    if (err < NO_ERROR) return err;
+    
+    return waitForResponse(NULL, NULL);
+}
+
+status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
+{
+    int32_t cmd;
+    int32_t err;
+
+    while (1) {
+        if ((err=talkWithDriver()) < NO_ERROR) break;
+        err = mIn.errorCheck();
+        if (err < NO_ERROR) break;
+        if (mIn.dataAvail() == 0) continue;
+        
+        cmd = mIn.readInt32();
+        
+        IF_LOG_COMMANDS() {
+            alog << "Processing waitForResponse Command: "
+                << getReturnString(cmd) << endl;
+        }
+
+        switch (cmd) {
+        case BR_TRANSACTION_COMPLETE:
+            if (!reply && !acquireResult) goto finish;
+            break;
+        
+        case BR_DEAD_REPLY:
+            err = DEAD_OBJECT;
+            goto finish;
+
+        case BR_FAILED_REPLY:
+            err = FAILED_TRANSACTION;
+            goto finish;
+        
+        case BR_ACQUIRE_RESULT:
+            {
+                LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
+                const int32_t result = mIn.readInt32();
+                if (!acquireResult) continue;
+                *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
+            }
+            goto finish;
+        
+        case BR_REPLY:
+            {
+                binder_transaction_data tr;
+                err = mIn.read(&tr, sizeof(tr));
+                LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
+                if (err != NO_ERROR) goto finish;
+
+                if (reply) {
+                    if ((tr.flags & TF_STATUS_CODE) == 0) {
+                        reply->ipcSetDataReference(
+                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+                            tr.data_size,
+                            reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+                            tr.offsets_size/sizeof(size_t),
+                            freeBuffer, this);
+                    } else {
+                        err = *static_cast<const status_t*>(tr.data.ptr.buffer);
+                        freeBuffer(NULL,
+                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+                            tr.data_size,
+                            reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+                            tr.offsets_size/sizeof(size_t), this);
+                    }
+                } else {
+                    freeBuffer(NULL,
+                        reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+                        tr.data_size,
+                        reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+                        tr.offsets_size/sizeof(size_t), this);
+                    continue;
+                }
+            }
+            goto finish;
+
+        default:
+            err = executeCommand(cmd);
+            if (err != NO_ERROR) goto finish;
+            break;
+        }
+    }
+
+finish:
+    if (err != NO_ERROR) {
+        if (acquireResult) *acquireResult = err;
+        if (reply) reply->setError(err);
+        mLastError = err;
+    }
+    
+    return err;
+}
+
+status_t IPCThreadState::talkWithDriver(bool doReceive)
+{
+    LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");
+    
+    binder_write_read bwr;
+    
+    // Is the read buffer empty?
+    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
+    
+    // We don't want to write anything if we are still reading
+    // from data left in the input buffer and the caller
+    // has requested to read the next data.
+    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
+    
+    bwr.write_size = outAvail;
+    bwr.write_buffer = (long unsigned int)mOut.data();
+
+    // This is what we'll read.
+    if (doReceive && needRead) {
+        bwr.read_size = mIn.dataCapacity();
+        bwr.read_buffer = (long unsigned int)mIn.data();
+    } else {
+        bwr.read_size = 0;
+    }
+    
+    IF_LOG_COMMANDS() {
+        TextOutput::Bundle _b(alog);
+        if (outAvail != 0) {
+            alog << "Sending commands to driver: " << indent;
+            const void* cmds = (const void*)bwr.write_buffer;
+            const void* end = ((const uint8_t*)cmds)+bwr.write_size;
+            alog << HexDump(cmds, bwr.write_size) << endl;
+            while (cmds < end) cmds = printCommand(alog, cmds);
+            alog << dedent;
+        }
+        alog << "Size of receive buffer: " << bwr.read_size
+            << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
+    }
+    
+    // Return immediately if there is nothing to do.
+    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
+    
+    bwr.write_consumed = 0;
+    bwr.read_consumed = 0;
+    status_t err;
+    do {
+        IF_LOG_COMMANDS() {
+            alog << "About to read/write, write size = " << mOut.dataSize() << endl;
+        }
+#if defined(HAVE_ANDROID_OS)
+        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
+            err = NO_ERROR;
+        else
+            err = -errno;
+#else
+        err = INVALID_OPERATION;
+#endif
+        IF_LOG_COMMANDS() {
+            alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
+        }
+    } while (err == -EINTR);
+    
+    IF_LOG_COMMANDS() {
+        alog << "Our err: " << (void*)err << ", write consumed: "
+            << bwr.write_consumed << " (of " << mOut.dataSize()
+			<< "), read consumed: " << bwr.read_consumed << endl;
+    }
+
+    if (err >= NO_ERROR) {
+        if (bwr.write_consumed > 0) {
+            if (bwr.write_consumed < (ssize_t)mOut.dataSize())
+                mOut.remove(0, bwr.write_consumed);
+            else
+                mOut.setDataSize(0);
+        }
+        if (bwr.read_consumed > 0) {
+            mIn.setDataSize(bwr.read_consumed);
+            mIn.setDataPosition(0);
+        }
+        IF_LOG_COMMANDS() {
+            TextOutput::Bundle _b(alog);
+            alog << "Remaining data size: " << mOut.dataSize() << endl;
+            alog << "Received commands from driver: " << indent;
+            const void* cmds = mIn.data();
+            const void* end = mIn.data() + mIn.dataSize();
+            alog << HexDump(cmds, mIn.dataSize()) << endl;
+            while (cmds < end) cmds = printReturnCommand(alog, cmds);
+            alog << dedent;
+        }
+        return NO_ERROR;
+    }
+    
+    return err;
+}
+
+status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
+    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
+{
+    binder_transaction_data tr;
+
+    tr.target.handle = handle;
+    tr.code = code;
+    tr.flags = binderFlags;
+    
+    const status_t err = data.errorCheck();
+    if (err == NO_ERROR) {
+        tr.data_size = data.ipcDataSize();
+        tr.data.ptr.buffer = data.ipcData();
+        tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
+        tr.data.ptr.offsets = data.ipcObjects();
+    } else if (statusBuffer) {
+        tr.flags |= TF_STATUS_CODE;
+        *statusBuffer = err;
+        tr.data_size = sizeof(status_t);
+        tr.data.ptr.buffer = statusBuffer;
+        tr.offsets_size = 0;
+        tr.data.ptr.offsets = NULL;
+    } else {
+        return (mLastError = err);
+    }
+    
+    mOut.writeInt32(cmd);
+    mOut.write(&tr, sizeof(tr));
+    
+    return NO_ERROR;
+}
+
+sp<BBinder> the_context_object;
+
+void setTheContextObject(sp<BBinder> obj)
+{
+    the_context_object = obj;
+}
+
+status_t IPCThreadState::executeCommand(int32_t cmd)
+{
+    BBinder* obj;
+    RefBase::weakref_type* refs;
+    status_t result = NO_ERROR;
+    
+    switch (cmd) {
+    case BR_ERROR:
+        result = mIn.readInt32();
+        break;
+        
+    case BR_OK:
+        break;
+        
+    case BR_ACQUIRE:
+        refs = (RefBase::weakref_type*)mIn.readInt32();
+        obj = (BBinder*)mIn.readInt32();
+        LOG_ASSERT(refs->refBase() == obj,
+                   "BR_ACQUIRE: object %p does not match cookie %p (expected %p)",
+                   refs, obj, refs->refBase());
+        obj->incStrong(mProcess.get());
+        IF_LOG_REMOTEREFS() {
+            LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);
+            obj->printRefs();
+        }
+        mOut.writeInt32(BC_ACQUIRE_DONE);
+        mOut.writeInt32((int32_t)refs);
+        mOut.writeInt32((int32_t)obj);
+        break;
+        
+    case BR_RELEASE:
+        refs = (RefBase::weakref_type*)mIn.readInt32();
+        obj = (BBinder*)mIn.readInt32();
+        LOG_ASSERT(refs->refBase() == obj,
+                   "BR_RELEASE: object %p does not match cookie %p (expected %p)",
+                   refs, obj, refs->refBase());
+        IF_LOG_REMOTEREFS() {
+            LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
+            obj->printRefs();
+        }
+        mPendingStrongDerefs.push(obj);
+        break;
+        
+    case BR_INCREFS:
+        refs = (RefBase::weakref_type*)mIn.readInt32();
+        obj = (BBinder*)mIn.readInt32();
+        refs->incWeak(mProcess.get());
+        mOut.writeInt32(BC_INCREFS_DONE);
+        mOut.writeInt32((int32_t)refs);
+        mOut.writeInt32((int32_t)obj);
+        break;
+        
+    case BR_DECREFS:
+        refs = (RefBase::weakref_type*)mIn.readInt32();
+        obj = (BBinder*)mIn.readInt32();
+        // NOTE: This assertion is not valid, because the object may no
+        // longer exist (thus the (BBinder*)cast above resulting in a different
+        // memory address).
+        //LOG_ASSERT(refs->refBase() == obj,
+        //           "BR_DECREFS: object %p does not match cookie %p (expected %p)",
+        //           refs, obj, refs->refBase());
+        mPendingWeakDerefs.push(refs);
+        break;
+        
+    case BR_ATTEMPT_ACQUIRE:
+        refs = (RefBase::weakref_type*)mIn.readInt32();
+        obj = (BBinder*)mIn.readInt32();
+         
+        {
+            const bool success = refs->attemptIncStrong(mProcess.get());
+            LOG_ASSERT(success && refs->refBase() == obj,
+                       "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
+                       refs, obj, refs->refBase());
+            
+            mOut.writeInt32(BC_ACQUIRE_RESULT);
+            mOut.writeInt32((int32_t)success);
+        }
+        break;
+    
+    case BR_TRANSACTION:
+        {
+            binder_transaction_data tr;
+            result = mIn.read(&tr, sizeof(tr));
+            LOG_ASSERT(result == NO_ERROR,
+                "Not enough command data for brTRANSACTION");
+            if (result != NO_ERROR) break;
+            
+            Parcel buffer;
+            buffer.ipcSetDataReference(
+                reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+                tr.data_size,
+                reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+                tr.offsets_size/sizeof(size_t), freeBuffer, this);
+            
+            const pid_t origPid = mCallingPid;
+            const uid_t origUid = mCallingUid;
+            
+            mCallingPid = tr.sender_pid;
+            mCallingUid = tr.sender_euid;
+            
+            //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
+            
+            Parcel reply;
+            IF_LOG_TRANSACTIONS() {
+                TextOutput::Bundle _b(alog);
+                alog << "BR_TRANSACTION thr " << (void*)pthread_self()
+                    << " / obj " << tr.target.ptr << " / code "
+                    << TypeCode(tr.code) << ": " << indent << buffer
+                    << dedent << endl
+                    << "Data addr = "
+                    << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
+                    << ", offsets addr="
+                    << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
+            }
+            if (tr.target.ptr) {
+                sp<BBinder> b((BBinder*)tr.cookie);
+                const status_t error = b->transact(tr.code, buffer, &reply, 0);
+                if (error < NO_ERROR) reply.setError(error);
+                
+            } else {
+                const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);
+                if (error < NO_ERROR) reply.setError(error);
+            }
+            
+            //LOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
+            //     mCallingPid, origPid, origUid);
+            
+            if ((tr.flags & TF_ONE_WAY) == 0) {
+                LOG_ONEWAY("Sending reply to %d!", mCallingPid);
+                sendReply(reply, 0);
+            } else {
+                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
+            }
+            
+            mCallingPid = origPid;
+            mCallingUid = origUid;
+            
+            IF_LOG_TRANSACTIONS() {
+                TextOutput::Bundle _b(alog);
+                alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
+                    << tr.target.ptr << ": " << indent << reply << dedent << endl;
+            }
+            
+        }
+        break;
+    
+    case BR_DEAD_BINDER:
+        {
+            BpBinder *proxy = (BpBinder*)mIn.readInt32();
+            proxy->sendObituary();
+            mOut.writeInt32(BC_DEAD_BINDER_DONE);
+            mOut.writeInt32((int32_t)proxy);
+        } break;
+        
+    case BR_CLEAR_DEATH_NOTIFICATION_DONE:
+        {
+            BpBinder *proxy = (BpBinder*)mIn.readInt32();
+            proxy->getWeakRefs()->decWeak(proxy);
+        } break;
+        
+    case BR_FINISHED:
+        result = TIMED_OUT;
+        break;
+        
+    case BR_NOOP:
+        break;
+        
+    case BR_SPAWN_LOOPER:
+        mProcess->spawnPooledThread(false);
+        break;
+        
+    default:
+        printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
+        result = UNKNOWN_ERROR;
+        break;
+    }
+
+    if (result != NO_ERROR) {
+        mLastError = result;
+    }
+    
+    return result;
+}
+
+void IPCThreadState::threadDestructor(void *st)
+{
+	IPCThreadState* const self = static_cast<IPCThreadState*>(st);
+	if (self) {
+		self->flushCommands();
+#if defined(HAVE_ANDROID_OS)
+        ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0);
+#endif
+		delete self;
+	}
+}
+
+
+void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize,
+                                const size_t* objects, size_t objectsSize,
+                                void* cookie)
+{
+    //LOGI("Freeing parcel %p", &parcel);
+    IF_LOG_COMMANDS() {
+        alog << "Writing BC_FREE_BUFFER for " << data << endl;
+    }
+    LOG_ASSERT(data != NULL, "Called with NULL data");
+    if (parcel != NULL) parcel->closeFileDescriptors();
+    IPCThreadState* state = self();
+    state->mOut.writeInt32(BC_FREE_BUFFER);
+    state->mOut.writeInt32((int32_t)data);
+}
+
+}; // namespace android
diff --git a/libs/utils/IPermissionController.cpp b/libs/utils/IPermissionController.cpp
new file mode 100644
index 0000000..f01d38f
--- /dev/null
+++ b/libs/utils/IPermissionController.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "PermissionController"
+
+#include <utils/IPermissionController.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <utils/String8.h>
+
+#include <private/utils/Static.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BpPermissionController : public BpInterface<IPermissionController>
+{
+public:
+    BpPermissionController(const sp<IBinder>& impl)
+        : BpInterface<IPermissionController>(impl)
+    {
+    }
+        
+    virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+        data.writeString16(permission);
+        data.writeInt32(pid);
+        data.writeInt32(uid);
+        remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
+        // fail on exception
+        if (reply.readInt32() != 0) return 0;
+        return reply.readInt32() != 0;
+    }
+};
+
+IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnPermissionController::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    //printf("PermissionController received: "); data.print();
+    switch(code) {
+        case CHECK_PERMISSION_TRANSACTION: {
+            CHECK_INTERFACE(IPermissionController, data, reply);
+            String16 permission = data.readString16();
+            int32_t pid = data.readInt32();
+            int32_t uid = data.readInt32();
+            bool res = checkPermission(permission, pid, uid);
+            // write exception
+            reply->writeInt32(0);
+            reply->writeInt32(res ? 1 : 0);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
+
diff --git a/libs/utils/IServiceManager.cpp b/libs/utils/IServiceManager.cpp
new file mode 100644
index 0000000..9beeadd
--- /dev/null
+++ b/libs/utils/IServiceManager.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "ServiceManager"
+
+#include <utils/IServiceManager.h>
+
+#include <utils/Debug.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <utils/String8.h>
+#include <utils/SystemClock.h>
+
+#include <private/utils/Static.h>
+
+#include <unistd.h>
+
+namespace android {
+
+sp<IServiceManager> defaultServiceManager()
+{
+    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
+    
+    {
+        AutoMutex _l(gDefaultServiceManagerLock);
+        if (gDefaultServiceManager == NULL) {
+            gDefaultServiceManager = interface_cast<IServiceManager>(
+                ProcessState::self()->getContextObject(NULL));
+        }
+    }
+    
+    return gDefaultServiceManager;
+}
+
+bool checkCallingPermission(const String16& permission)
+{
+    return checkCallingPermission(permission, NULL, NULL);
+}
+
+static String16 _permission("permission");
+
+bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
+{
+    IPCThreadState* ipcState = IPCThreadState::self();
+    int32_t pid = ipcState->getCallingPid();
+    int32_t uid = ipcState->getCallingUid();
+    if (outPid) *outPid = pid;
+    if (outUid) *outUid= uid;
+    
+    sp<IPermissionController> pc;
+    gDefaultServiceManagerLock.lock();
+    pc = gPermissionController;
+    gDefaultServiceManagerLock.unlock();
+    
+    int64_t startTime = 0;
+
+    while (true) {
+        if (pc != NULL) {
+            bool res = pc->checkPermission(permission, pid, uid);
+            if (res) {
+                if (startTime != 0) {
+                    LOGI("Check passed after %d seconds for %s from uid=%d pid=%d",
+                            (int)((uptimeMillis()-startTime)/1000),
+                            String8(permission).string(), uid, pid);
+                }
+                return res;
+            }
+            
+            // Is this a permission failure, or did the controller go away?
+            if (pc->asBinder()->isBinderAlive()) {
+                LOGW("Permission failure: %s from uid=%d pid=%d",
+                        String8(permission).string(), uid, pid);
+                return false;
+            }
+            
+            // Object is dead!
+            gDefaultServiceManagerLock.lock();
+            if (gPermissionController == pc) {
+                gPermissionController = NULL;
+            }
+            gDefaultServiceManagerLock.unlock();
+        }
+    
+        // Need to retrieve the permission controller.
+        sp<IBinder> binder = defaultServiceManager()->checkService(_permission);
+        if (binder == NULL) {
+            // Wait for the permission controller to come back...
+            if (startTime == 0) {
+                startTime = uptimeMillis();
+                LOGI("Waiting to check permission %s from uid=%d pid=%d",
+                        String8(permission).string(), uid, pid);
+            }
+            sleep(1);
+        } else {
+            pc = interface_cast<IPermissionController>(binder);
+            // Install the new permission controller, and try again.        
+            gDefaultServiceManagerLock.lock();
+            gPermissionController = pc;
+            gDefaultServiceManagerLock.unlock();
+        }
+    }
+}
+
+// ----------------------------------------------------------------------
+
+class BpServiceManager : public BpInterface<IServiceManager>
+{
+public:
+    BpServiceManager(const sp<IBinder>& impl)
+        : BpInterface<IServiceManager>(impl)
+    {
+    }
+        
+    virtual sp<IBinder> getService(const String16& name) const
+    {
+        unsigned n;
+        for (n = 0; n < 5; n++){
+            sp<IBinder> svc = checkService(name);
+            if (svc != NULL) return svc;
+            LOGI("Waiting for sevice %s...\n", String8(name).string());
+            sleep(1);
+        }
+        return NULL;
+    }
+    
+    virtual sp<IBinder> checkService( const String16& name) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
+        data.writeString16(name);
+        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
+        return reply.readStrongBinder();
+    }
+
+    virtual status_t addService(const String16& name, const sp<IBinder>& service)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
+        data.writeString16(name);
+        data.writeStrongBinder(service);
+        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
+        return err == NO_ERROR ? reply.readInt32() : err;
+    }
+
+    virtual Vector<String16> listServices()
+    {
+        Vector<String16> res;
+        int n = 0;
+
+        for (;;) {
+            Parcel data, reply;
+            data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
+            data.writeInt32(n++);
+            status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
+            if (err != NO_ERROR)
+                break;
+            res.add(reply.readString16());
+        }
+        return res;
+    }
+};
+
+IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnServiceManager::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    //printf("ServiceManager received: "); data.print();
+    switch(code) {
+        case GET_SERVICE_TRANSACTION: {
+            CHECK_INTERFACE(IServiceManager, data, reply);
+            String16 which = data.readString16();
+            sp<IBinder> b = const_cast<BnServiceManager*>(this)->getService(which);
+            reply->writeStrongBinder(b);
+            return NO_ERROR;
+        } break;
+        case CHECK_SERVICE_TRANSACTION: {
+            CHECK_INTERFACE(IServiceManager, data, reply);
+            String16 which = data.readString16();
+            sp<IBinder> b = const_cast<BnServiceManager*>(this)->checkService(which);
+            reply->writeStrongBinder(b);
+            return NO_ERROR;
+        } break;
+        case ADD_SERVICE_TRANSACTION: {
+            CHECK_INTERFACE(IServiceManager, data, reply);
+            String16 which = data.readString16();
+            sp<IBinder> b = data.readStrongBinder();
+            status_t err = addService(which, b);
+            reply->writeInt32(err);
+            return NO_ERROR;
+        } break;
+        case LIST_SERVICES_TRANSACTION: {
+            CHECK_INTERFACE(IServiceManager, data, reply);
+            Vector<String16> list = listServices();
+            const size_t N = list.size();
+            reply->writeInt32(N);
+            for (size_t i=0; i<N; i++) {
+                reply->writeString16(list[i]);
+            }
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
+
diff --git a/libs/utils/InetAddress.cpp b/libs/utils/InetAddress.cpp
new file mode 100644
index 0000000..39a0a68
--- /dev/null
+++ b/libs/utils/InetAddress.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Internet address class.
+//
+#ifdef HAVE_WINSOCK
+# include <winsock2.h>
+#else
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+//# include <arpa/inet.h>
+# include <netdb.h>
+#endif
+
+#include <utils/inet_address.h>
+#include <utils/threads.h>
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+using namespace android;
+
+
+/*
+ * ===========================================================================
+ *      InetAddress
+ * ===========================================================================
+ */
+
+// lock for the next couple of functions; could tuck into InetAddress
+static Mutex*   gGHBNLock;
+
+/*
+ * Lock/unlock access to the hostent struct returned by gethostbyname().
+ */
+static inline void lock_gethostbyname(void)
+{
+    if (gGHBNLock == NULL)
+        gGHBNLock = new Mutex;
+    gGHBNLock->lock();
+}
+static inline void unlock_gethostbyname(void)
+{
+    assert(gGHBNLock != NULL);
+    gGHBNLock->unlock();
+}
+
+
+/*
+ * Constructor -- just init members.  This is private so that callers
+ * are required to use getByName().
+ */
+InetAddress::InetAddress(void)
+    : mAddress(NULL), mLength(-1), mName(NULL)
+{
+}
+
+/*
+ * Destructor -- free address storage.
+ */
+InetAddress::~InetAddress(void)
+{
+    delete[] (char*) mAddress;
+    delete[] mName;
+}
+
+/*
+ * Copy constructor.
+ */
+InetAddress::InetAddress(const InetAddress& orig)
+{
+    *this = orig;   // use assignment code
+}
+
+/*
+ * Assignment operator.
+ */
+InetAddress& InetAddress::operator=(const InetAddress& addr)
+{
+    // handle self-assignment
+    if (this == &addr)
+        return *this;
+    // copy mLength and mAddress
+    mLength = addr.mLength;
+    if (mLength > 0) {
+        mAddress = new char[mLength];
+        memcpy(mAddress, addr.mAddress, mLength);
+        LOG(LOG_DEBUG, "socket",
+            "HEY: copied %d bytes in assignment operator\n", mLength);
+    } else {
+        mAddress = NULL;
+    }
+    // copy mName
+    mName = new char[strlen(addr.mName)+1];
+    strcpy(mName, addr.mName);
+
+    return *this;
+}
+
+/*
+ * Create a new object from a name or a dotted-number IP notation.
+ *
+ * Returns NULL on failure.
+ */
+InetAddress*
+InetAddress::getByName(const char* host)
+{
+    InetAddress* newAddr = NULL;
+    struct sockaddr_in addr;
+    struct hostent* he;
+    DurationTimer hostTimer, lockTimer;
+
+    // gethostbyname() isn't reentrant, so we need to lock things until
+    // we can copy the data out.
+    lockTimer.start();
+    lock_gethostbyname();
+    hostTimer.start();
+
+    he = gethostbyname(host);
+    if (he == NULL) {
+        LOG(LOG_WARN, "socket", "WARNING: cannot resolve host %s\n", host);
+        unlock_gethostbyname();
+        return NULL;
+    }
+
+    memcpy(&addr.sin_addr, he->h_addr, he->h_length);
+    addr.sin_family = he->h_addrtype;
+    addr.sin_port = 0;
+
+    // got it, unlock us
+    hostTimer.stop();
+    he = NULL;
+    unlock_gethostbyname();
+
+    lockTimer.stop();
+    if ((long) lockTimer.durationUsecs() > 100000) {
+        long lockTime = (long) lockTimer.durationUsecs();
+        long hostTime = (long) hostTimer.durationUsecs();
+        LOG(LOG_DEBUG, "socket",
+            "Lookup of %s took %.3fs (gethostbyname=%.3fs lock=%.3fs)\n",
+            host, lockTime / 1000000.0, hostTime / 1000000.0,
+            (lockTime - hostTime) / 1000000.0);
+    }
+
+    // Alloc storage and copy it over.
+    newAddr = new InetAddress();
+    if (newAddr == NULL)
+        return NULL;
+
+    newAddr->mLength = sizeof(struct sockaddr_in);
+    newAddr->mAddress = new char[sizeof(struct sockaddr_in)];
+    if (newAddr->mAddress == NULL) {
+        delete newAddr;
+        return NULL;
+    }
+    memcpy(newAddr->mAddress, &addr, newAddr->mLength);
+
+    // Keep this for debug messages.
+    newAddr->mName = new char[strlen(host)+1];
+    if (newAddr->mName == NULL) {
+        delete newAddr;
+        return NULL;
+    }
+    strcpy(newAddr->mName, host);
+
+    return newAddr;
+}
+
+
+/*
+ * ===========================================================================
+ *      InetSocketAddress
+ * ===========================================================================
+ */
+
+/*
+ * Create an address with the host wildcard (INADDR_ANY).
+ */
+bool InetSocketAddress::create(int port)
+{
+    assert(mAddress == NULL);
+
+    mAddress = InetAddress::getByName("0.0.0.0");
+    if (mAddress == NULL)
+        return false;
+    mPort = port;
+    return true;
+}
+
+/*
+ * Create address with host and port specified.
+ */
+bool InetSocketAddress::create(const InetAddress* addr, int port)
+{
+    assert(mAddress == NULL);
+
+    mAddress = new InetAddress(*addr);  // make a copy
+    if (mAddress == NULL)
+        return false;
+    mPort = port;
+    return true;
+}
+
+/*
+ * Create address with host and port specified.
+ */
+bool InetSocketAddress::create(const char* host, int port)
+{
+    assert(mAddress == NULL);
+
+    mAddress = InetAddress::getByName(host);
+    if (mAddress == NULL)
+        return false;
+    mPort = port;
+    return true;
+}
+
diff --git a/libs/utils/LogSocket.cpp b/libs/utils/LogSocket.cpp
new file mode 100644
index 0000000..55c1b99
--- /dev/null
+++ b/libs/utils/LogSocket.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+
+#ifndef HAVE_WINSOCK
+//#define SOCKETLOG
+#endif
+
+#ifdef SOCKETLOG
+
+#define LOG_TAG "SOCKETLOG"
+
+#include <string.h>
+#include <cutils/log.h>
+#include "utils/LogSocket.h"
+#include "utils/logger.h"
+#include "cutils/hashmap.h"
+
+// defined in //device/data/etc/event-log-tags
+#define SOCKET_CLOSE_LOG 51000
+
+static Hashmap* statsMap = NULL;
+
+#define LOG_LIST_NUMBER 5
+
+typedef struct SocketStats {
+    int fd;
+    unsigned int send;
+    unsigned int recv;
+    unsigned int ip;
+    unsigned short port;
+    short reason;
+}SocketStats;
+
+SocketStats *get_socket_stats(int fd) {
+    if (statsMap == NULL) {
+        statsMap = hashmapCreate(8, &hashmapIntHash, &hashmapIntEquals);
+    }
+
+    SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd);
+    if (s == NULL) {
+        // LOGD("create SocketStats for fd %d", fd);
+        s = (SocketStats*) malloc(sizeof(SocketStats));
+        memset(s, 0, sizeof(SocketStats));
+        s->fd = fd;
+        hashmapPut(statsMap, &s->fd, s);
+    }
+    return s;
+}
+
+void log_socket_connect(int fd, unsigned int ip, unsigned short port) {
+    // LOGD("log_socket_connect for fd %d ip %d port%d", fd, ip, port);
+    SocketStats *s = get_socket_stats(fd);
+    s->ip = ip;
+    s->port = port;
+}
+
+void add_send_stats(int fd, int send) {
+    if (send <=0) {
+        LOGE("add_send_stats send %d", send);
+        return;
+    }
+    SocketStats *s = get_socket_stats(fd);
+    s->send += send;
+    // LOGD("add_send_stats for fd %d ip %d port%d", fd, s->ip, s->port);
+}
+
+void add_recv_stats(int fd, int recv) {
+    if (recv <=0) {
+        LOGE("add_recv_stats recv %d", recv);
+        return;
+    }
+    SocketStats *s = get_socket_stats(fd);
+    s->recv += recv;
+    // LOGD("add_recv_stats for fd %d ip %d port%d", fd, s->ip, s->port);
+}
+
+char* put_int(char* buf, int value) {
+    *buf = EVENT_TYPE_INT;
+    buf++;
+    memcpy(buf, &value, sizeof(int));
+    return buf + sizeof(int);
+}
+
+void log_socket_close(int fd, short reason) {
+    if (statsMap) {
+        SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd);
+        if (s != NULL) {
+            if (s->send != 0 || s->recv != 0) {
+                s->reason = reason;
+                // 5 int + list type need 2 bytes
+                char buf[LOG_LIST_NUMBER * 5 + 2];
+                buf[0] = EVENT_TYPE_LIST;
+                buf[1] = LOG_LIST_NUMBER;
+                char* writePos = buf + 2;
+                writePos = put_int(writePos, s->send);
+                writePos = put_int(writePos, s->recv);
+                writePos = put_int(writePos, s->ip);
+                writePos = put_int(writePos, s->port);
+                writePos = put_int(writePos, s->reason);
+                
+                android_bWriteLog(SOCKET_CLOSE_LOG, buf, sizeof(buf));
+                // LOGD("send %d recv %d reason %d", s->send, s->recv, s->reason);
+            }
+            hashmapRemove(statsMap, &s->fd);
+            free(s);
+        }
+    }
+}
+
+#else
+void add_send_stats(int fd, int send) {} 
+void add_recv_stats(int fd, int recv) {}
+void log_socket_close(int fd, short reason) {}
+void log_socket_connect(int fd, unsigned int ip, unsigned short port) {}
+#endif
diff --git a/libs/utils/MODULE_LICENSE_APACHE2 b/libs/utils/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/utils/MODULE_LICENSE_APACHE2
diff --git a/libs/utils/MemoryBase.cpp b/libs/utils/MemoryBase.cpp
new file mode 100644
index 0000000..f25e11c
--- /dev/null
+++ b/libs/utils/MemoryBase.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 <stdlib.h>
+#include <stdint.h>
+
+#include <utils/MemoryBase.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+MemoryBase::MemoryBase(const sp<IMemoryHeap>& heap,
+        ssize_t offset, size_t size)
+    : mSize(size), mOffset(offset), mHeap(heap)
+{
+}
+
+sp<IMemoryHeap> MemoryBase::getMemory(ssize_t* offset, size_t* size) const
+{
+    if (offset) *offset = mOffset;
+    if (size)   *size = mSize;
+    return mHeap;
+}
+
+MemoryBase::~MemoryBase()
+{
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/utils/MemoryDealer.cpp b/libs/utils/MemoryDealer.cpp
new file mode 100644
index 0000000..cf8201b
--- /dev/null
+++ b/libs/utils/MemoryDealer.cpp
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "MemoryDealer"
+
+#include <utils/MemoryDealer.h>
+
+#include <utils/Log.h>
+#include <utils/IPCThreadState.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+#include <utils/MemoryBase.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/file.h>
+
+namespace android {
+
+
+// ----------------------------------------------------------------------------
+
+class SimpleMemory : public MemoryBase {
+public:
+    SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
+    virtual ~SimpleMemory();
+};
+
+
+// ----------------------------------------------------------------------------
+
+MemoryDealer::Allocation::Allocation(
+        const sp<MemoryDealer>& dealer, ssize_t offset, size_t size,
+        const sp<IMemory>& memory)
+    : mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory) 
+{
+}
+
+MemoryDealer::Allocation::~Allocation()
+{
+    if (mSize) {
+        /* NOTE: it's VERY important to not free allocations of size 0 because
+         * they're special as they don't have any record in the allocator
+         * and could alias some real allocation (their offset is zero). */
+        mDealer->deallocate(mOffset);
+    }
+}
+
+sp<IMemoryHeap> MemoryDealer::Allocation::getMemory(
+    ssize_t* offset, size_t* size) const
+{
+    return mMemory->getMemory(offset, size);
+}
+
+// ----------------------------------------------------------------------------
+
+MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name)
+    : mHeap(new SharedHeap(size, flags, name)),
+    mAllocator(new SimpleBestFitAllocator(size))
+{    
+}
+
+MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap)
+    : mHeap(heap),
+    mAllocator(new SimpleBestFitAllocator(heap->virtualSize()))
+{
+}
+
+MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap,
+        const sp<AllocatorInterface>& allocator)
+    : mHeap(heap), mAllocator(allocator)
+{
+}
+
+MemoryDealer::~MemoryDealer()
+{
+}
+
+sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags)
+{
+    sp<IMemory> memory;
+    const ssize_t offset = allocator()->allocate(size, flags);
+    if (offset >= 0) {
+        sp<IMemory> new_memory = heap()->mapMemory(offset, size);
+        if (new_memory != 0) {
+            memory = new Allocation(this, offset, size, new_memory);
+        } else {
+            LOGE("couldn't map [%8x, %d]", offset, size);
+            if (size) {
+                /* NOTE: it's VERY important to not free allocations of size 0
+                 * because they're special as they don't have any record in the 
+                 * allocator and could alias some real allocation 
+                 * (their offset is zero). */
+                allocator()->deallocate(offset);
+            }
+        }        
+    }
+    return memory;
+}
+
+void MemoryDealer::deallocate(size_t offset)
+{
+    allocator()->deallocate(offset);
+}
+
+void MemoryDealer::dump(const char* what, uint32_t flags) const
+{
+    allocator()->dump(what, flags);
+}
+
+const sp<HeapInterface>& MemoryDealer::heap() const {
+    return mHeap;
+}
+
+const sp<AllocatorInterface>& MemoryDealer::allocator() const {
+    return mAllocator;
+}
+
+// ----------------------------------------------------------------------------
+
+// align all the memory blocks on a cache-line boundary
+const int SimpleBestFitAllocator::kMemoryAlign = 32;
+
+SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
+{
+    size_t pagesize = getpagesize();
+    mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
+
+    chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
+    mList.insertHead(node);
+}
+
+SimpleBestFitAllocator::~SimpleBestFitAllocator()
+{
+    while(!mList.isEmpty()) {
+        delete mList.remove(mList.head());
+    }
+}
+
+size_t SimpleBestFitAllocator::size() const
+{
+    return mHeapSize;
+}
+
+size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
+{
+    Mutex::Autolock _l(mLock);
+    ssize_t offset = alloc(size, flags);
+    return offset;
+}
+
+status_t SimpleBestFitAllocator::deallocate(size_t offset)
+{
+    Mutex::Autolock _l(mLock);
+    chunk_t const * const freed = dealloc(offset);
+    if (freed) {
+        return NO_ERROR;
+    }
+    return NAME_NOT_FOUND;
+}
+
+ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
+{
+    if (size == 0) {
+        return 0;
+    }
+    size = (size + kMemoryAlign-1) / kMemoryAlign;
+    chunk_t* free_chunk = 0;
+    chunk_t* cur = mList.head();
+
+    size_t pagesize = getpagesize();
+    while (cur) {
+        int extra = 0;
+        if (flags & PAGE_ALIGNED)
+            extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
+
+        // best fit
+        if (cur->free && (cur->size >= (size+extra))) {
+            if ((!free_chunk) || (cur->size < free_chunk->size)) {
+                free_chunk = cur;
+            }
+            if (cur->size == size) {
+                break;
+            }
+        }
+        cur = cur->next;
+    }
+
+    if (free_chunk) {
+        const size_t free_size = free_chunk->size;
+        free_chunk->free = 0;
+        free_chunk->size = size;
+        if (free_size > size) {
+            int extra = 0;
+            if (flags & PAGE_ALIGNED)
+                extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
+            if (extra) {
+                chunk_t* split = new chunk_t(free_chunk->start, extra);
+                free_chunk->start += extra;
+                mList.insertBefore(free_chunk, split);
+            }
+
+            LOGE_IF((flags&PAGE_ALIGNED) && 
+                    ((free_chunk->start*kMemoryAlign)&(pagesize-1)),
+                    "PAGE_ALIGNED requested, but page is not aligned!!!");
+
+            const ssize_t tail_free = free_size - (size+extra);
+            if (tail_free > 0) {
+                chunk_t* split = new chunk_t(
+                        free_chunk->start + free_chunk->size, tail_free);
+                mList.insertAfter(free_chunk, split);
+            }
+        }
+        return (free_chunk->start)*kMemoryAlign;
+    }
+    return NO_MEMORY;
+}
+
+SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
+{
+    start = start / kMemoryAlign;
+    chunk_t* cur = mList.head();
+    while (cur) {
+        if (cur->start == start) {
+            LOG_FATAL_IF(cur->free,
+                "block at offset 0x%08lX of size 0x%08lX already freed",
+                cur->start*kMemoryAlign, cur->size*kMemoryAlign);
+
+            // merge freed blocks together
+            chunk_t* freed = cur;
+            cur->free = 1;
+            do {
+                chunk_t* const p = cur->prev;
+                chunk_t* const n = cur->next;
+                if (p && (p->free || !cur->size)) {
+                    freed = p;
+                    p->size += cur->size;
+                    mList.remove(cur);
+                    delete cur;
+                }
+                cur = n;
+            } while (cur && cur->free);
+
+            #ifndef NDEBUG
+                if (!freed->free) {
+                    dump_l("dealloc (!freed->free)");
+                }
+            #endif
+            LOG_FATAL_IF(!freed->free,
+                "freed block at offset 0x%08lX of size 0x%08lX is not free!",
+                freed->start * kMemoryAlign, freed->size * kMemoryAlign);
+
+            return freed;
+        }
+        cur = cur->next;
+    }
+    return 0;
+}
+
+void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const
+{
+    Mutex::Autolock _l(mLock);
+    dump_l(what, flags);
+}
+
+void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const
+{
+    String8 result;
+    dump_l(result, what, flags);
+    LOGD("%s", result.string());
+}
+
+void SimpleBestFitAllocator::dump(String8& result,
+        const char* what, uint32_t flags) const
+{
+    Mutex::Autolock _l(mLock);
+    dump_l(result, what, flags);
+}
+
+void SimpleBestFitAllocator::dump_l(String8& result,
+        const char* what, uint32_t flags) const
+{
+    size_t size = 0;
+    int32_t i = 0;
+    chunk_t const* cur = mList.head();
+    
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    snprintf(buffer, SIZE, "  %s (%p, size=%u)\n",
+            what, this, (unsigned int)mHeapSize);
+    
+    result.append(buffer);
+            
+    while (cur) {
+        const char* errs[] = {"", "| link bogus NP",
+                            "| link bogus PN", "| link bogus NP+PN" };
+        int np = ((cur->next) && cur->next->prev != cur) ? 1 : 0;
+        int pn = ((cur->prev) && cur->prev->next != cur) ? 2 : 0;
+
+        snprintf(buffer, SIZE, "  %3u: %08x | 0x%08X | 0x%08X | %s %s\n",
+            i, int(cur), int(cur->start*kMemoryAlign),
+            int(cur->size*kMemoryAlign),
+                    int(cur->free) ? "F" : "A",
+                    errs[np|pn]);
+        
+        result.append(buffer);
+
+        if (!cur->free)
+            size += cur->size*kMemoryAlign;
+
+        i++;
+        cur = cur->next;
+    }
+    snprintf(buffer, SIZE, "  size allocated: %u (%u KB)\n", int(size), int(size/1024));
+    result.append(buffer);
+}
+        
+// ----------------------------------------------------------------------------
+
+
+SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name)
+    : MemoryHeapBase(size, flags, name)
+{
+}
+
+SharedHeap::~SharedHeap()
+{
+}
+
+sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size)
+{
+    return new SimpleMemory(this, offset, size);
+}
+ 
+
+SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap,
+        ssize_t offset, size_t size)
+    : MemoryBase(heap, offset, size)
+{
+#ifndef NDEBUG
+    void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
+    memset(start_ptr, 0xda, size);
+#endif
+}
+
+SimpleMemory::~SimpleMemory()
+{
+    size_t freedOffset = getOffset();
+    size_t freedSize   = getSize();
+
+    // keep the size to unmap in excess
+    size_t pagesize = getpagesize();
+    size_t start = freedOffset;
+    size_t end = start + freedSize;
+    start &= ~(pagesize-1);
+    end = (end + pagesize-1) & ~(pagesize-1);
+
+    // give back to the kernel the pages we don't need
+    size_t free_start = freedOffset;
+    size_t free_end = free_start + freedSize;
+    if (start < free_start)
+        start = free_start;
+    if (end > free_end)
+        end = free_end;
+    start = (start + pagesize-1) & ~(pagesize-1);
+    end &= ~(pagesize-1);    
+
+    if (start < end) {
+        void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
+        size_t size = end-start;
+
+#ifndef NDEBUG
+        memset(start_ptr, 0xdf, size);
+#endif
+
+        // MADV_REMOVE is not defined on Dapper based Goobuntu 
+#ifdef MADV_REMOVE 
+        if (size) {
+            int err = madvise(start_ptr, size, MADV_REMOVE);
+            LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
+                    start_ptr, size, err<0 ? strerror(errno) : "Ok");
+        }
+#endif
+    }
+}
+
+}; // namespace android
diff --git a/libs/utils/MemoryHeapBase.cpp b/libs/utils/MemoryHeapBase.cpp
new file mode 100644
index 0000000..8251728
--- /dev/null
+++ b/libs/utils/MemoryHeapBase.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MemoryHeapBase"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/ashmem.h>
+#include <cutils/atomic.h>
+
+#include <utils/MemoryHeapBase.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapBase::MemoryHeapBase() 
+    : mFD(-1), mSize(0), mBase(MAP_FAILED),
+      mDevice(NULL), mNeedUnmap(false) 
+{
+}
+
+MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
+    : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
+      mDevice(0), mNeedUnmap(false)
+{
+    const size_t pagesize = getpagesize();
+    size = ((size + pagesize-1) & ~(pagesize-1));
+    int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
+    LOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
+    if (fd >= 0) {
+        if (mapfd(fd, size) == NO_ERROR) {
+            if (flags & READ_ONLY) {
+                ashmem_set_prot_region(fd, PROT_READ);
+            }
+        }
+    }
+}
+
+MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
+    : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
+      mDevice(0), mNeedUnmap(false)
+{
+    int fd = open(device, O_RDWR);
+    LOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
+    if (fd >= 0) {
+        const size_t pagesize = getpagesize();
+        size = ((size + pagesize-1) & ~(pagesize-1));
+        if (mapfd(fd, size) == NO_ERROR) {
+            mDevice = device;
+        }
+    }
+}
+
+MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags)
+    : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
+      mDevice(0), mNeedUnmap(false)
+{
+    const size_t pagesize = getpagesize();
+    size = ((size + pagesize-1) & ~(pagesize-1));
+    mapfd(dup(fd), size);
+}
+
+status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
+{
+    if (mFD != -1) {
+        return INVALID_OPERATION;
+    }
+    mFD = fd;
+    mBase = base;
+    mSize = size;
+    mFlags = flags;
+    mDevice = device;
+    return NO_ERROR;
+}
+
+status_t MemoryHeapBase::mapfd(int fd, size_t size)
+{
+    if (size == 0) {
+        // try to figure out the size automatically
+#if HAVE_ANDROID_OS
+        // first try the PMEM ioctl
+        pmem_region reg;
+        int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, &reg);
+        if (err == 0)
+            size = reg.len;
+#endif
+        if (size == 0) { // try fstat
+            struct stat sb;
+            if (fstat(fd, &sb) == 0)
+                size = sb.st_size;
+        }
+        // if it didn't work, let mmap() fail.
+    }
+
+    if ((mFlags & DONT_MAP_LOCALLY) == 0) {
+        void* base = (uint8_t*)mmap(0, size,
+                PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+        if (base == MAP_FAILED) {
+            LOGE("mmap(fd=%d, size=%u) failed (%s)",
+                    fd, uint32_t(size), strerror(errno));
+            close(fd);
+            return -errno;
+        }
+        //LOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
+        mBase = base;
+        mNeedUnmap = true;
+    } else  {
+        mBase = 0; // not MAP_FAILED
+        mNeedUnmap = false;
+    }
+    mFD = fd;
+    mSize = size;
+    return NO_ERROR;
+}
+
+MemoryHeapBase::~MemoryHeapBase()
+{
+    dispose();
+}
+
+void MemoryHeapBase::dispose()
+{
+    int fd = android_atomic_or(-1, &mFD);
+    if (fd >= 0) {
+        if (mNeedUnmap) {
+            //LOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
+            munmap(mBase, mSize);
+        }
+        mBase = 0;
+        mSize = 0;
+        close(fd);
+    }
+}
+
+int MemoryHeapBase::getHeapID() const {
+    return mFD;
+}
+
+void* MemoryHeapBase::getBase() const {
+    return mBase;
+}
+
+size_t MemoryHeapBase::getSize() const {
+    return mSize;
+}
+
+uint32_t MemoryHeapBase::getFlags() const {
+    return mFlags;
+}
+
+const char* MemoryHeapBase::getDevice() const {
+    return mDevice;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/utils/MemoryHeapPmem.cpp b/libs/utils/MemoryHeapPmem.cpp
new file mode 100644
index 0000000..eba2b30
--- /dev/null
+++ b/libs/utils/MemoryHeapPmem.cpp
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MemoryHeapPmem"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+
+#include <utils/MemoryHeapPmem.h>
+#include <utils/MemoryHeapBase.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap)
+    : BnMemory(), mClientHeap(heap)
+{
+}
+
+MemoryHeapPmem::MemoryPmem::~MemoryPmem() {
+    if (mClientHeap != NULL) {
+        mClientHeap->remove(this);
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+class SubRegionMemory : public MemoryHeapPmem::MemoryPmem {
+public:
+    SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
+    virtual ~SubRegionMemory();
+    virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+private:
+    friend class MemoryHeapPmem;
+    void revoke();
+    size_t              mSize;
+    ssize_t             mOffset;
+};
+
+SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
+        ssize_t offset, size_t size)
+    : MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset)
+{
+#ifndef NDEBUG
+    void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset);
+    memset(start_ptr, 0xda, size);
+#endif
+
+#if HAVE_ANDROID_OS
+    if (size > 0) {
+        const size_t pagesize = getpagesize();
+        size = (size + pagesize-1) & ~(pagesize-1);
+        int our_fd = heap->heapID();
+        struct pmem_region sub = { offset, size };
+        int err = ioctl(our_fd, PMEM_MAP, &sub);
+        LOGE_IF(err<0, "PMEM_MAP failed (%s), "
+                "mFD=%d, sub.offset=%lu, sub.size=%lu",
+                strerror(errno), our_fd, sub.offset, sub.len);
+}
+#endif
+}
+
+sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const
+{
+    if (offset) *offset = mOffset;
+    if (size)   *size = mSize;
+    return getHeap();
+}
+
+SubRegionMemory::~SubRegionMemory()
+{
+    revoke();
+}
+
+
+void SubRegionMemory::revoke()
+{
+    // NOTE: revoke() doesn't need to be protected by a lock because it
+    // can only be called from MemoryHeapPmem::revoke(), which means
+    // that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(),
+    // which means MemoryHeapPmem::revoke() wouldn't have been able to 
+    // promote() it.
+    
+#if HAVE_ANDROID_OS
+    if (mSize != NULL) {
+        const sp<MemoryHeapPmem>& heap(getHeap());
+        int our_fd = heap->heapID();
+        struct pmem_region sub;
+        sub.offset = mOffset;
+        sub.len = mSize;
+        int err = ioctl(our_fd, PMEM_UNMAP, &sub);
+        LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
+                "mFD=%d, sub.offset=%lu, sub.size=%lu",
+                strerror(errno), our_fd, sub.offset, sub.len);
+        mSize = 0;
+    }
+#endif
+}
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
+        uint32_t flags)
+    : HeapInterface(), MemoryHeapBase()
+{
+    char const * const device = pmemHeap->getDevice();
+#if HAVE_ANDROID_OS
+    if (device) {
+        int fd = open(device, O_RDWR);
+        LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
+        if (fd >= 0) {
+            int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID());
+            if (err < 0) {
+                LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d",
+                        strerror(errno), fd, pmemHeap->heapID());
+                close(fd);
+            } else {
+                // everything went well...
+                mParentHeap = pmemHeap;
+                MemoryHeapBase::init(fd, 
+                        pmemHeap->getBase(),
+                        pmemHeap->getSize(),
+                        pmemHeap->getFlags() | flags,
+                        device);
+            }
+        }
+    }
+#else
+    mParentHeap = pmemHeap;
+    MemoryHeapBase::init( 
+            dup(pmemHeap->heapID()),
+            pmemHeap->getBase(),
+            pmemHeap->getSize(),
+            pmemHeap->getFlags() | flags,
+            device);
+#endif
+}
+
+MemoryHeapPmem::~MemoryHeapPmem()
+{
+}
+
+sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
+{
+    sp<MemoryPmem> memory = createMemory(offset, size);
+    if (memory != 0) {
+        Mutex::Autolock _l(mLock);
+        mAllocations.add(memory);
+    }
+    return memory;
+}
+
+sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory(
+        size_t offset, size_t size)
+{
+    sp<SubRegionMemory> memory;
+    if (heapID() > 0) 
+        memory = new SubRegionMemory(this, offset, size);
+    return memory;
+}
+
+status_t MemoryHeapPmem::slap()
+{
+#if HAVE_ANDROID_OS
+    size_t size = getSize();
+    const size_t pagesize = getpagesize();
+    size = (size + pagesize-1) & ~(pagesize-1);
+    int our_fd = getHeapID();
+    struct pmem_region sub = { 0, size };
+    int err = ioctl(our_fd, PMEM_MAP, &sub);
+    LOGE_IF(err<0, "PMEM_MAP failed (%s), "
+            "mFD=%d, sub.offset=%lu, sub.size=%lu",
+            strerror(errno), our_fd, sub.offset, sub.len);
+    return -errno;
+#else
+    return NO_ERROR;
+#endif
+}
+
+status_t MemoryHeapPmem::unslap()
+{
+#if HAVE_ANDROID_OS
+    size_t size = getSize();
+    const size_t pagesize = getpagesize();
+    size = (size + pagesize-1) & ~(pagesize-1);
+    int our_fd = getHeapID();
+    struct pmem_region sub = { 0, size };
+    int err = ioctl(our_fd, PMEM_UNMAP, &sub);
+    LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
+            "mFD=%d, sub.offset=%lu, sub.size=%lu",
+            strerror(errno), our_fd, sub.offset, sub.len);
+    return -errno;
+#else
+    return NO_ERROR;
+#endif
+}
+
+void MemoryHeapPmem::revoke()
+{
+    SortedVector< wp<MemoryPmem> > allocations;
+
+    { // scope for lock
+        Mutex::Autolock _l(mLock);
+        allocations = mAllocations;
+    }
+    
+    ssize_t count = allocations.size();
+    for (ssize_t i=0 ; i<count ; i++) {
+        sp<MemoryPmem> memory(allocations[i].promote());
+        if (memory != 0)
+            memory->revoke();
+    }
+}
+
+void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory)
+{
+    Mutex::Autolock _l(mLock);
+    mAllocations.remove(memory);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/utils/NOTICE b/libs/utils/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libs/utils/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/libs/utils/Parcel.cpp b/libs/utils/Parcel.cpp
new file mode 100644
index 0000000..0f4b647
--- /dev/null
+++ b/libs/utils/Parcel.cpp
@@ -0,0 +1,1377 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "Parcel"
+//#define LOG_NDEBUG 0
+
+#include <utils/Parcel.h>
+
+#include <utils/Binder.h>
+#include <utils/BpBinder.h>
+#include <utils/Debug.h>
+#include <utils/ProcessState.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/TextOutput.h>
+#include <utils/misc.h>
+
+#include <private/utils/binder_module.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#ifndef INT32_MAX
+#define INT32_MAX ((int32_t)(2147483647))
+#endif
+
+#define LOG_REFS(...)
+//#define LOG_REFS(...) LOG(LOG_DEBUG, "Parcel", __VA_ARGS__)
+
+// ---------------------------------------------------------------------------
+
+#define PAD_SIZE(s) (((s)+3)&~3)
+
+// XXX This can be made public if we want to provide
+// support for typed data.
+struct small_flat_data
+{
+    uint32_t type;
+    uint32_t data;
+};
+
+namespace android {
+
+void acquire_object(const sp<ProcessState>& proc,
+    const flat_binder_object& obj, const void* who)
+{
+    switch (obj.type) {
+        case BINDER_TYPE_BINDER:
+            if (obj.binder) {
+                LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);
+                static_cast<IBinder*>(obj.cookie)->incStrong(who);
+            }
+            return;
+        case BINDER_TYPE_WEAK_BINDER:
+            if (obj.binder)
+                static_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who);
+            return;
+        case BINDER_TYPE_HANDLE: {
+            const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
+            if (b != NULL) {
+                LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get());
+                b->incStrong(who);
+            }
+            return;
+        }
+        case BINDER_TYPE_WEAK_HANDLE: {
+            const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
+            if (b != NULL) b.get_refs()->incWeak(who);
+            return;
+        }
+        case BINDER_TYPE_FD: {
+            // intentionally blank -- nothing to do to acquire this, but we do
+            // recognize it as a legitimate object type.
+            return;
+        }
+    }
+
+    LOGD("Invalid object type 0x%08lx", obj.type);
+}
+
+void release_object(const sp<ProcessState>& proc,
+    const flat_binder_object& obj, const void* who)
+{
+    switch (obj.type) {
+        case BINDER_TYPE_BINDER:
+            if (obj.binder) {
+                LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie);
+                static_cast<IBinder*>(obj.cookie)->decStrong(who);
+            }
+            return;
+        case BINDER_TYPE_WEAK_BINDER:
+            if (obj.binder)
+                static_cast<RefBase::weakref_type*>(obj.binder)->decWeak(who);
+            return;
+        case BINDER_TYPE_HANDLE: {
+            const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
+            if (b != NULL) {
+                LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get());
+                b->decStrong(who);
+            }
+            return;
+        }
+        case BINDER_TYPE_WEAK_HANDLE: {
+            const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
+            if (b != NULL) b.get_refs()->decWeak(who);
+            return;
+        }
+        case BINDER_TYPE_FD: {
+            if (obj.cookie != (void*)0) close(obj.handle);
+            return;
+        }
+    }
+
+    LOGE("Invalid object type 0x%08lx", obj.type);
+}
+
+inline static status_t finish_flatten_binder(
+    const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out)
+{
+    return out->writeObject(flat, false);
+}
+
+status_t flatten_binder(const sp<ProcessState>& proc,
+    const sp<IBinder>& binder, Parcel* out)
+{
+    flat_binder_object obj;
+    
+    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+    if (binder != NULL) {
+        IBinder *local = binder->localBinder();
+        if (!local) {
+            BpBinder *proxy = binder->remoteBinder();
+            if (proxy == NULL) {
+                LOGE("null proxy");
+            }
+            const int32_t handle = proxy ? proxy->handle() : 0;
+            obj.type = BINDER_TYPE_HANDLE;
+            obj.handle = handle;
+            obj.cookie = NULL;
+        } else {
+            obj.type = BINDER_TYPE_BINDER;
+            obj.binder = local->getWeakRefs();
+            obj.cookie = local;
+        }
+    } else {
+        obj.type = BINDER_TYPE_BINDER;
+        obj.binder = NULL;
+        obj.cookie = NULL;
+    }
+    
+    return finish_flatten_binder(binder, obj, out);
+}
+
+status_t flatten_binder(const sp<ProcessState>& proc,
+    const wp<IBinder>& binder, Parcel* out)
+{
+    flat_binder_object obj;
+    
+    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+    if (binder != NULL) {
+        sp<IBinder> real = binder.promote();
+        if (real != NULL) {
+            IBinder *local = real->localBinder();
+            if (!local) {
+                BpBinder *proxy = real->remoteBinder();
+                if (proxy == NULL) {
+                    LOGE("null proxy");
+                }
+                const int32_t handle = proxy ? proxy->handle() : 0;
+                obj.type = BINDER_TYPE_WEAK_HANDLE;
+                obj.handle = handle;
+                obj.cookie = NULL;
+            } else {
+                obj.type = BINDER_TYPE_WEAK_BINDER;
+                obj.binder = binder.get_refs();
+                obj.cookie = binder.unsafe_get();
+            }
+            return finish_flatten_binder(real, obj, out);
+        }
+        
+        // XXX How to deal?  In order to flatten the given binder,
+        // we need to probe it for information, which requires a primary
+        // reference...  but we don't have one.
+        //
+        // The OpenBinder implementation uses a dynamic_cast<> here,
+        // but we can't do that with the different reference counting
+        // implementation we are using.
+        LOGE("Unable to unflatten Binder weak reference!");
+        obj.type = BINDER_TYPE_BINDER;
+        obj.binder = NULL;
+        obj.cookie = NULL;
+        return finish_flatten_binder(NULL, obj, out);
+    
+    } else {
+        obj.type = BINDER_TYPE_BINDER;
+        obj.binder = NULL;
+        obj.cookie = NULL;
+        return finish_flatten_binder(NULL, obj, out);
+    }
+}
+
+inline static status_t finish_unflatten_binder(
+    BpBinder* proxy, const flat_binder_object& flat, const Parcel& in)
+{
+    return NO_ERROR;
+}
+    
+status_t unflatten_binder(const sp<ProcessState>& proc,
+    const Parcel& in, sp<IBinder>* out)
+{
+    const flat_binder_object* flat = in.readObject(false);
+    
+    if (flat) {
+        switch (flat->type) {
+            case BINDER_TYPE_BINDER:
+                *out = static_cast<IBinder*>(flat->cookie);
+                return finish_unflatten_binder(NULL, *flat, in);
+            case BINDER_TYPE_HANDLE:
+                *out = proc->getStrongProxyForHandle(flat->handle);
+                return finish_unflatten_binder(
+                    static_cast<BpBinder*>(out->get()), *flat, in);
+        }        
+    }
+    return BAD_TYPE;
+}
+
+status_t unflatten_binder(const sp<ProcessState>& proc,
+    const Parcel& in, wp<IBinder>* out)
+{
+    const flat_binder_object* flat = in.readObject(false);
+    
+    if (flat) {
+        switch (flat->type) {
+            case BINDER_TYPE_BINDER:
+                *out = static_cast<IBinder*>(flat->cookie);
+                return finish_unflatten_binder(NULL, *flat, in);
+            case BINDER_TYPE_WEAK_BINDER:
+                if (flat->binder != NULL) {
+                    out->set_object_and_refs(
+                        static_cast<IBinder*>(flat->cookie),
+                        static_cast<RefBase::weakref_type*>(flat->binder));
+                } else {
+                    *out = NULL;
+                }
+                return finish_unflatten_binder(NULL, *flat, in);
+            case BINDER_TYPE_HANDLE:
+            case BINDER_TYPE_WEAK_HANDLE:
+                *out = proc->getWeakProxyForHandle(flat->handle);
+                return finish_unflatten_binder(
+                    static_cast<BpBinder*>(out->unsafe_get()), *flat, in);
+        }
+    }
+    return BAD_TYPE;
+}
+
+// ---------------------------------------------------------------------------
+
+Parcel::Parcel()
+{
+    initState();
+}
+
+Parcel::~Parcel()
+{
+    freeDataNoInit();
+}
+
+const uint8_t* Parcel::data() const
+{
+    return mData;
+}
+
+size_t Parcel::dataSize() const
+{
+    return (mDataSize > mDataPos ? mDataSize : mDataPos);
+}
+
+size_t Parcel::dataAvail() const
+{
+    // TODO: decide what to do about the possibility that this can
+    // report an available-data size that exceeds a Java int's max
+    // positive value, causing havoc.  Fortunately this will only
+    // happen if someone constructs a Parcel containing more than two
+    // gigabytes of data, which on typical phone hardware is simply
+    // not possible.
+    return dataSize() - dataPosition();
+}
+
+size_t Parcel::dataPosition() const
+{
+    return mDataPos;
+}
+
+size_t Parcel::dataCapacity() const
+{
+    return mDataCapacity;
+}
+
+status_t Parcel::setDataSize(size_t size)
+{
+    status_t err;
+    err = continueWrite(size);
+    if (err == NO_ERROR) {
+        mDataSize = size;
+        LOGV("setDataSize Setting data size of %p to %d\n", this, mDataSize);
+    }
+    return err;
+}
+
+void Parcel::setDataPosition(size_t pos) const
+{
+    mDataPos = pos;
+    mNextObjectHint = 0;
+}
+
+status_t Parcel::setDataCapacity(size_t size)
+{
+    if (size > mDataSize) return continueWrite(size);
+    return NO_ERROR;
+}
+
+status_t Parcel::setData(const uint8_t* buffer, size_t len)
+{
+    status_t err = restartWrite(len);
+    if (err == NO_ERROR) {
+        memcpy(const_cast<uint8_t*>(data()), buffer, len);
+        mDataSize = len;
+        mFdsKnown = false;
+    }
+    return err;
+}
+
+status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len)
+{
+    const sp<ProcessState> proc(ProcessState::self());
+    status_t err;
+    uint8_t *data = parcel->mData;
+    size_t *objects = parcel->mObjects;
+    size_t size = parcel->mObjectsSize;
+    int startPos = mDataPos;
+    int firstIndex = -1, lastIndex = -2;
+
+    if (len == 0) {
+        return NO_ERROR;
+    }
+
+    // range checks against the source parcel size
+    if ((offset > parcel->mDataSize)
+            || (len > parcel->mDataSize)
+            || (offset + len > parcel->mDataSize)) {
+        return BAD_VALUE;
+    }
+
+    // Count objects in range
+    for (int i = 0; i < (int) size; i++) {
+        size_t off = objects[i];
+        if ((off >= offset) && (off < offset + len)) {
+            if (firstIndex == -1) {
+                firstIndex = i;
+            }
+            lastIndex = i;
+        }
+    }
+    int numObjects = lastIndex - firstIndex + 1;
+
+    // grow data
+    err = growData(len);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    // append data
+    memcpy(mData + mDataPos, data + offset, len);
+    mDataPos += len;
+    mDataSize += len;
+
+    if (numObjects > 0) {
+        // grow objects
+        if (mObjectsCapacity < mObjectsSize + numObjects) {
+            int newSize = ((mObjectsSize + numObjects)*3)/2;
+            size_t *objects =
+                (size_t*)realloc(mObjects, newSize*sizeof(size_t));
+            if (objects == (size_t*)0) {
+                return NO_MEMORY;
+            }
+            mObjects = objects;
+            mObjectsCapacity = newSize;
+        }
+        
+        // append and acquire objects
+        int idx = mObjectsSize;
+        for (int i = firstIndex; i <= lastIndex; i++) {
+            size_t off = objects[i] - offset + startPos;
+            mObjects[idx++] = off;
+            mObjectsSize++;
+
+            const flat_binder_object* flat
+                = reinterpret_cast<flat_binder_object*>(mData + off);
+            acquire_object(proc, *flat, this);
+
+            // take note if the object is a file descriptor
+            if (flat->type == BINDER_TYPE_FD) {
+                mHasFds = mFdsKnown = true;
+            }
+        }
+    }
+
+    return NO_ERROR;
+}
+
+bool Parcel::hasFileDescriptors() const
+{
+    if (!mFdsKnown) {
+        scanForFds();
+    }
+    return mHasFds;
+}
+
+status_t Parcel::writeInterfaceToken(const String16& interface)
+{
+    // currently the interface identification token is just its name as a string
+    return writeString16(interface);
+}
+
+bool Parcel::enforceInterface(const String16& interface) const
+{
+    String16 str = readString16();
+    if (str == interface) {
+        return true;
+    } else {
+        LOGW("**** enforceInterface() expected '%s' but read '%s'\n",
+                String8(interface).string(), String8(str).string());
+        return false;
+    }
+} 
+
+const size_t* Parcel::objects() const
+{
+    return mObjects;
+}
+
+size_t Parcel::objectsCount() const
+{
+    return mObjectsSize;
+}
+
+status_t Parcel::errorCheck() const
+{
+    return mError;
+}
+
+void Parcel::setError(status_t err)
+{
+    mError = err;
+}
+
+status_t Parcel::finishWrite(size_t len)
+{
+    //printf("Finish write of %d\n", len);
+    mDataPos += len;
+    LOGV("finishWrite Setting data pos of %p to %d\n", this, mDataPos);
+    if (mDataPos > mDataSize) {
+        mDataSize = mDataPos;
+        LOGV("finishWrite Setting data size of %p to %d\n", this, mDataSize);
+    }
+    //printf("New pos=%d, size=%d\n", mDataPos, mDataSize);
+    return NO_ERROR;
+}
+
+status_t Parcel::writeUnpadded(const void* data, size_t len)
+{
+    size_t end = mDataPos + len;
+    if (end < mDataPos) {
+        // integer overflow
+        return BAD_VALUE;
+    }
+
+    if (end <= mDataCapacity) {
+restart_write:
+        memcpy(mData+mDataPos, data, len);
+        return finishWrite(len);
+    }
+
+    status_t err = growData(len);
+    if (err == NO_ERROR) goto restart_write;
+    return err;
+}
+
+status_t Parcel::write(const void* data, size_t len)
+{
+    void* const d = writeInplace(len);
+    if (d) {
+        memcpy(d, data, len);
+        return NO_ERROR;
+    }
+    return mError;
+}
+
+void* Parcel::writeInplace(size_t len)
+{
+    const size_t padded = PAD_SIZE(len);
+
+    // sanity check for integer overflow
+    if (mDataPos+padded < mDataPos) {
+        return NULL;
+    }
+
+    if ((mDataPos+padded) <= mDataCapacity) {
+restart_write:
+        //printf("Writing %ld bytes, padded to %ld\n", len, padded);
+        uint8_t* const data = mData+mDataPos;
+
+        // Need to pad at end?
+        if (padded != len) {
+#if BYTE_ORDER == BIG_ENDIAN
+            static const uint32_t mask[4] = {
+                0x00000000, 0xffffff00, 0xffff0000, 0xff000000
+            };
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+            static const uint32_t mask[4] = {
+                0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff
+            };
+#endif
+            //printf("Applying pad mask: %p to %p\n", (void*)mask[padded-len],
+            //    *reinterpret_cast<void**>(data+padded-4));
+            *reinterpret_cast<uint32_t*>(data+padded-4) &= mask[padded-len];
+        }
+
+        finishWrite(padded);
+        return data;
+    }
+
+    status_t err = growData(padded);
+    if (err == NO_ERROR) goto restart_write;
+    return NULL;
+}
+
+status_t Parcel::writeInt32(int32_t val)
+{
+    if ((mDataPos+sizeof(val)) <= mDataCapacity) {
+restart_write:
+        *reinterpret_cast<int32_t*>(mData+mDataPos) = val;
+        return finishWrite(sizeof(val));
+    }
+
+    status_t err = growData(sizeof(val));
+    if (err == NO_ERROR) goto restart_write;
+    return err;
+}
+
+status_t Parcel::writeInt64(int64_t val)
+{
+    if ((mDataPos+sizeof(val)) <= mDataCapacity) {
+restart_write:
+        *reinterpret_cast<int64_t*>(mData+mDataPos) = val;
+        return finishWrite(sizeof(val));
+    }
+
+    status_t err = growData(sizeof(val));
+    if (err == NO_ERROR) goto restart_write;
+    return err;
+}
+
+status_t Parcel::writeFloat(float val)
+{
+    if ((mDataPos+sizeof(val)) <= mDataCapacity) {
+restart_write:
+        *reinterpret_cast<float*>(mData+mDataPos) = val;
+        return finishWrite(sizeof(val));
+    }
+
+    status_t err = growData(sizeof(val));
+    if (err == NO_ERROR) goto restart_write;
+    return err;
+}
+
+status_t Parcel::writeDouble(double val)
+{
+    if ((mDataPos+sizeof(val)) <= mDataCapacity) {
+restart_write:
+        *reinterpret_cast<double*>(mData+mDataPos) = val;
+        return finishWrite(sizeof(val));
+    }
+
+    status_t err = growData(sizeof(val));
+    if (err == NO_ERROR) goto restart_write;
+    return err;
+}
+
+status_t Parcel::writeCString(const char* str)
+{
+    return write(str, strlen(str)+1);
+}
+
+status_t Parcel::writeString8(const String8& str)
+{
+    status_t err = writeInt32(str.bytes());
+    if (err == NO_ERROR) {
+        err = write(str.string(), str.bytes()+1);
+    }
+    return err;
+}
+
+status_t Parcel::writeString16(const String16& str)
+{
+    return writeString16(str.string(), str.size());
+}
+
+status_t Parcel::writeString16(const char16_t* str, size_t len)
+{
+    if (str == NULL) return writeInt32(-1);
+    
+    status_t err = writeInt32(len);
+    if (err == NO_ERROR) {
+        len *= sizeof(char16_t);
+        uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
+        if (data) {
+            memcpy(data, str, len);
+            *reinterpret_cast<char16_t*>(data+len) = 0;
+            return NO_ERROR;
+        }
+        err = mError;
+    }
+    return err;
+}
+
+status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
+{
+    return flatten_binder(ProcessState::self(), val, this);
+}
+
+status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
+{
+    return flatten_binder(ProcessState::self(), val, this);
+}
+
+status_t Parcel::writeNativeHandle(const native_handle& handle)
+{
+    if (handle.version != sizeof(native_handle))
+        return BAD_TYPE;
+
+    status_t err;
+    err = writeInt32(handle.numFds);
+    if (err != NO_ERROR) return err;
+
+    err = writeInt32(handle.numInts);
+    if (err != NO_ERROR) return err;
+
+    for (int i=0 ; err==NO_ERROR && i<handle.numFds ; i++)
+        err = writeDupFileDescriptor(handle.data[i]);
+
+    if (err != NO_ERROR) {
+        LOGD("write native handle, write dup fd failed");
+        return err;
+    }
+
+    err = write(handle.data + handle.numFds, sizeof(int)*handle.numInts);
+
+    return err;
+}
+
+status_t Parcel::writeFileDescriptor(int fd)
+{
+    flat_binder_object obj;
+    obj.type = BINDER_TYPE_FD;
+    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+    obj.handle = fd;
+    obj.cookie = (void*)0;
+    return writeObject(obj, true);
+}
+
+status_t Parcel::writeDupFileDescriptor(int fd)
+{
+    flat_binder_object obj;
+    obj.type = BINDER_TYPE_FD;
+    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+    obj.handle = dup(fd);
+    obj.cookie = (void*)1;
+    return writeObject(obj, true);
+}
+
+status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
+{
+    const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
+    const bool enoughObjects = mObjectsSize < mObjectsCapacity;
+    if (enoughData && enoughObjects) {
+restart_write:
+        *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
+        
+        // Need to write meta-data?
+        if (nullMetaData || val.binder != NULL) {
+            mObjects[mObjectsSize] = mDataPos;
+            acquire_object(ProcessState::self(), val, this);
+            mObjectsSize++;
+        }
+        
+        // remember if it's a file descriptor
+        if (val.type == BINDER_TYPE_FD) {
+            mHasFds = mFdsKnown = true;
+        }
+
+        return finishWrite(sizeof(flat_binder_object));
+    }
+
+    if (!enoughData) {
+        const status_t err = growData(sizeof(val));
+        if (err != NO_ERROR) return err;
+    }
+    if (!enoughObjects) {
+        size_t newSize = ((mObjectsSize+2)*3)/2;
+        size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));
+        if (objects == NULL) return NO_MEMORY;
+        mObjects = objects;
+        mObjectsCapacity = newSize;
+    }
+    
+    goto restart_write;
+}
+
+
+void Parcel::remove(size_t start, size_t amt)
+{
+    LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
+}
+
+status_t Parcel::read(void* outData, size_t len) const
+{
+    if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
+        memcpy(outData, mData+mDataPos, len);
+        mDataPos += PAD_SIZE(len);
+        LOGV("read Setting data pos of %p to %d\n", this, mDataPos);
+        return NO_ERROR;
+    }
+    return NOT_ENOUGH_DATA;
+}
+
+const void* Parcel::readInplace(size_t len) const
+{
+    if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
+        const void* data = mData+mDataPos;
+        mDataPos += PAD_SIZE(len);
+        LOGV("readInplace Setting data pos of %p to %d\n", this, mDataPos);
+        return data;
+    }
+    return NULL;
+}
+
+status_t Parcel::readInt32(int32_t *pArg) const
+{
+    if ((mDataPos+sizeof(int32_t)) <= mDataSize) {
+        const void* data = mData+mDataPos;
+        mDataPos += sizeof(int32_t);
+        *pArg =  *reinterpret_cast<const int32_t*>(data);
+        return NO_ERROR;
+    } else {
+        return NOT_ENOUGH_DATA;
+    }
+}
+
+int32_t Parcel::readInt32() const
+{
+    if ((mDataPos+sizeof(int32_t)) <= mDataSize) {
+        const void* data = mData+mDataPos;
+        mDataPos += sizeof(int32_t);
+        LOGV("readInt32 Setting data pos of %p to %d\n", this, mDataPos);
+        return *reinterpret_cast<const int32_t*>(data);
+    }
+    return 0;
+}
+
+
+status_t Parcel::readInt64(int64_t *pArg) const
+{
+    if ((mDataPos+sizeof(int64_t)) <= mDataSize) {
+        const void* data = mData+mDataPos;
+        mDataPos += sizeof(int64_t);
+        *pArg = *reinterpret_cast<const int64_t*>(data);
+        LOGV("readInt64 Setting data pos of %p to %d\n", this, mDataPos);
+        return NO_ERROR;
+    } else {
+        return NOT_ENOUGH_DATA;
+    }
+}
+
+
+int64_t Parcel::readInt64() const
+{
+    if ((mDataPos+sizeof(int64_t)) <= mDataSize) {
+        const void* data = mData+mDataPos;
+        mDataPos += sizeof(int64_t);
+        LOGV("readInt64 Setting data pos of %p to %d\n", this, mDataPos);
+        return *reinterpret_cast<const int64_t*>(data);
+    }
+    return 0;
+}
+
+status_t Parcel::readFloat(float *pArg) const
+{
+    if ((mDataPos+sizeof(float)) <= mDataSize) {
+        const void* data = mData+mDataPos;
+        mDataPos += sizeof(float);
+        LOGV("readFloat Setting data pos of %p to %d\n", this, mDataPos);
+        *pArg = *reinterpret_cast<const float*>(data);
+        return NO_ERROR;
+    } else {
+        return NOT_ENOUGH_DATA;
+    }
+}
+
+
+float Parcel::readFloat() const
+{
+    if ((mDataPos+sizeof(float)) <= mDataSize) {
+        const void* data = mData+mDataPos;
+        mDataPos += sizeof(float);
+        LOGV("readFloat Setting data pos of %p to %d\n", this, mDataPos);
+        return *reinterpret_cast<const float*>(data);
+    }
+    return 0;
+}
+
+status_t Parcel::readDouble(double *pArg) const
+{
+    if ((mDataPos+sizeof(double)) <= mDataSize) {
+        const void* data = mData+mDataPos;
+        mDataPos += sizeof(double);
+        LOGV("readDouble Setting data pos of %p to %d\n", this, mDataPos);
+        *pArg = *reinterpret_cast<const double*>(data);
+        return NO_ERROR;
+    } else {
+        return NOT_ENOUGH_DATA;
+    }
+}
+
+
+double Parcel::readDouble() const
+{
+    if ((mDataPos+sizeof(double)) <= mDataSize) {
+        const void* data = mData+mDataPos;
+        mDataPos += sizeof(double);
+        LOGV("readDouble Setting data pos of %p to %d\n", this, mDataPos);
+        return *reinterpret_cast<const double*>(data);
+    }
+    return 0;
+}
+
+
+const char* Parcel::readCString() const
+{
+    const size_t avail = mDataSize-mDataPos;
+    if (avail > 0) {
+        const char* str = reinterpret_cast<const char*>(mData+mDataPos);
+        // is the string's trailing NUL within the parcel's valid bounds?
+        const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail));
+        if (eos) {
+            const size_t len = eos - str;
+            mDataPos += PAD_SIZE(len+1);
+            LOGV("readCString Setting data pos of %p to %d\n", this, mDataPos);
+            return str;
+        }
+    }
+    return NULL;
+}
+
+String8 Parcel::readString8() const
+{
+    int32_t size = readInt32();
+    // watch for potential int overflow adding 1 for trailing NUL
+    if (size > 0 && size < INT32_MAX) {
+        const char* str = (const char*)readInplace(size+1);
+        if (str) return String8(str, size);
+    }
+    return String8();
+}
+
+String16 Parcel::readString16() const
+{
+    size_t len;
+    const char16_t* str = readString16Inplace(&len);
+    if (str) return String16(str, len);
+    LOGE("Reading a NULL string not supported here.");
+    return String16();
+}
+
+const char16_t* Parcel::readString16Inplace(size_t* outLen) const
+{
+    int32_t size = readInt32();
+    // watch for potential int overflow from size+1
+    if (size >= 0 && size < INT32_MAX) {
+        *outLen = size;
+        const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t));
+        if (str != NULL) {
+            return str;
+        }
+    }
+    *outLen = 0;
+    return NULL;
+}
+
+sp<IBinder> Parcel::readStrongBinder() const
+{
+    sp<IBinder> val;
+    unflatten_binder(ProcessState::self(), *this, &val);
+    return val;
+}
+
+wp<IBinder> Parcel::readWeakBinder() const
+{
+    wp<IBinder> val;
+    unflatten_binder(ProcessState::self(), *this, &val);
+    return val;
+}
+
+
+native_handle* Parcel::readNativeHandle(native_handle* (*alloc)(void*, int, int), void* cookie) const
+{
+    int numFds, numInts;
+    status_t err;
+    err = readInt32(&numFds);
+    if (err != NO_ERROR) return 0;
+    err = readInt32(&numInts);
+    if (err != NO_ERROR) return 0;
+
+    native_handle* h;
+    if (alloc == 0) {
+        size_t size = sizeof(native_handle) + sizeof(int)*(numFds + numInts);
+        h = (native_handle*)malloc(size); 
+        h->version = sizeof(native_handle);
+        h->numFds = numFds;
+        h->numInts = numInts;
+    } else {
+        h = alloc(cookie, numFds, numInts);
+        if (h->version != sizeof(native_handle)) {
+            return 0;
+        }
+    }
+    
+    for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
+        h->data[i] = dup(readFileDescriptor());
+        if (h->data[i] < 0) err = BAD_VALUE;
+    }
+    
+    err = read(h->data + numFds, sizeof(int)*numInts);
+    
+    if (err != NO_ERROR) {
+        if (alloc == 0) {
+            free(h);
+        }
+        h = 0;
+    }
+    return h;
+}
+
+
+int Parcel::readFileDescriptor() const
+{
+    const flat_binder_object* flat = readObject(true);
+    if (flat) {
+        switch (flat->type) {
+            case BINDER_TYPE_FD:
+                //LOGI("Returning file descriptor %ld from parcel %p\n", flat->handle, this);
+                return flat->handle;
+        }        
+    }
+    return BAD_TYPE;
+}
+
+const flat_binder_object* Parcel::readObject(bool nullMetaData) const
+{
+    const size_t DPOS = mDataPos;
+    if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {
+        const flat_binder_object* obj
+                = reinterpret_cast<const flat_binder_object*>(mData+DPOS);
+        mDataPos = DPOS + sizeof(flat_binder_object);
+        if (!nullMetaData && (obj->cookie == NULL && obj->binder == NULL)) {
+            // When transferring a NULL object, we don't write it into
+            // the object list, so we don't want to check for it when
+            // reading.
+            LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
+            return obj;
+        }
+        
+        // Ensure that this object is valid...
+        size_t* const OBJS = mObjects;
+        const size_t N = mObjectsSize;
+        size_t opos = mNextObjectHint;
+        
+        if (N > 0) {
+            LOGV("Parcel %p looking for obj at %d, hint=%d\n",
+                 this, DPOS, opos);
+            
+            // Start at the current hint position, looking for an object at
+            // the current data position.
+            if (opos < N) {
+                while (opos < (N-1) && OBJS[opos] < DPOS) {
+                    opos++;
+                }
+            } else {
+                opos = N-1;
+            }
+            if (OBJS[opos] == DPOS) {
+                // Found it!
+                LOGV("Parcel found obj %d at index %d with forward search",
+                     this, DPOS, opos);
+                mNextObjectHint = opos+1;
+                LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
+                return obj;
+            }
+        
+            // Look backwards for it...
+            while (opos > 0 && OBJS[opos] > DPOS) {
+                opos--;
+            }
+            if (OBJS[opos] == DPOS) {
+                // Found it!
+                LOGV("Parcel found obj %d at index %d with backward search",
+                     this, DPOS, opos);
+                mNextObjectHint = opos+1;
+                LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
+                return obj;
+            }
+        }
+        LOGW("Attempt to read object from Parcel %p at offset %d that is not in the object list",
+             this, DPOS);
+    }
+    return NULL;
+}
+
+void Parcel::closeFileDescriptors()
+{
+    size_t i = mObjectsSize;
+    if (i > 0) {
+        //LOGI("Closing file descriptors for %d objects...", mObjectsSize);
+    }
+    while (i > 0) {
+        i--;
+        const flat_binder_object* flat
+            = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
+        if (flat->type == BINDER_TYPE_FD) {
+            //LOGI("Closing fd: %ld\n", flat->handle);
+            close(flat->handle);
+        }
+    }
+}
+
+const uint8_t* Parcel::ipcData() const
+{
+    return mData;
+}
+
+size_t Parcel::ipcDataSize() const
+{
+    return (mDataSize > mDataPos ? mDataSize : mDataPos);
+}
+
+const size_t* Parcel::ipcObjects() const
+{
+    return mObjects;
+}
+
+size_t Parcel::ipcObjectsCount() const
+{
+    return mObjectsSize;
+}
+
+void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
+    const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie)
+{
+    freeDataNoInit();
+    mError = NO_ERROR;
+    mData = const_cast<uint8_t*>(data);
+    mDataSize = mDataCapacity = dataSize;
+    //LOGI("setDataReference Setting data size of %p to %lu (pid=%d)\n", this, mDataSize, getpid());
+    mDataPos = 0;
+    LOGV("setDataReference Setting data pos of %p to %d\n", this, mDataPos);
+    mObjects = const_cast<size_t*>(objects);
+    mObjectsSize = mObjectsCapacity = objectsCount;
+    mNextObjectHint = 0;
+    mOwner = relFunc;
+    mOwnerCookie = relCookie;
+    scanForFds();
+}
+
+void Parcel::print(TextOutput& to, uint32_t flags) const
+{
+    to << "Parcel(";
+    
+    if (errorCheck() != NO_ERROR) {
+        const status_t err = errorCheck();
+        to << "Error: " << (void*)err << " \"" << strerror(-err) << "\"";
+    } else if (dataSize() > 0) {
+        const uint8_t* DATA = data();
+        to << indent << HexDump(DATA, dataSize()) << dedent;
+        const size_t* OBJS = objects();
+        const size_t N = objectsCount();
+        for (size_t i=0; i<N; i++) {
+            const flat_binder_object* flat
+                = reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]);
+            to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
+                << TypeCode(flat->type & 0x7f7f7f00)
+                << " = " << flat->binder;
+        }
+    } else {
+        to << "NULL";
+    }
+    
+    to << ")";
+}
+
+void Parcel::releaseObjects()
+{
+    const sp<ProcessState> proc(ProcessState::self());
+    size_t i = mObjectsSize;
+    uint8_t* const data = mData;
+    size_t* const objects = mObjects;
+    while (i > 0) {
+        i--;
+        const flat_binder_object* flat
+            = reinterpret_cast<flat_binder_object*>(data+objects[i]);
+        release_object(proc, *flat, this);
+    }
+}
+
+void Parcel::acquireObjects()
+{
+    const sp<ProcessState> proc(ProcessState::self());
+    size_t i = mObjectsSize;
+    uint8_t* const data = mData;
+    size_t* const objects = mObjects;
+    while (i > 0) {
+        i--;
+        const flat_binder_object* flat
+            = reinterpret_cast<flat_binder_object*>(data+objects[i]);
+        acquire_object(proc, *flat, this);
+    }
+}
+
+void Parcel::freeData()
+{
+    freeDataNoInit();
+    initState();
+}
+
+void Parcel::freeDataNoInit()
+{
+    if (mOwner) {
+        //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
+        mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
+    } else {
+        releaseObjects();
+        if (mData) free(mData);
+        if (mObjects) free(mObjects);
+    }
+}
+
+status_t Parcel::growData(size_t len)
+{
+    size_t newSize = ((mDataSize+len)*3)/2;
+    return (newSize <= mDataSize)
+            ? (status_t) NO_MEMORY
+            : continueWrite(newSize);
+}
+
+status_t Parcel::restartWrite(size_t desired)
+{
+    if (mOwner) {
+        freeData();
+        return continueWrite(desired);
+    }
+    
+    uint8_t* data = (uint8_t*)realloc(mData, desired);
+    if (!data && desired > mDataCapacity) {
+        mError = NO_MEMORY;
+        return NO_MEMORY;
+    }
+    
+    releaseObjects();
+    
+    if (data) {
+        mData = data;
+        mDataCapacity = desired;
+    }
+    
+    mDataSize = mDataPos = 0;
+    LOGV("restartWrite Setting data size of %p to %d\n", this, mDataSize);
+    LOGV("restartWrite Setting data pos of %p to %d\n", this, mDataPos);
+        
+    free(mObjects);
+    mObjects = NULL;
+    mObjectsSize = mObjectsCapacity = 0;
+    mNextObjectHint = 0;
+    mHasFds = false;
+    mFdsKnown = true;
+    
+    return NO_ERROR;
+}
+
+status_t Parcel::continueWrite(size_t desired)
+{
+    // If shrinking, first adjust for any objects that appear
+    // after the new data size.
+    size_t objectsSize = mObjectsSize;
+    if (desired < mDataSize) {
+        if (desired == 0) {
+            objectsSize = 0;
+        } else {
+            while (objectsSize > 0) {
+                if (mObjects[objectsSize-1] < desired)
+                    break;
+                objectsSize--;
+            }
+        }
+    }
+    
+    if (mOwner) {
+        // If the size is going to zero, just release the owner's data.
+        if (desired == 0) {
+            freeData();
+            return NO_ERROR;
+        }
+
+        // If there is a different owner, we need to take
+        // posession.
+        uint8_t* data = (uint8_t*)malloc(desired);
+        if (!data) {
+            mError = NO_MEMORY;
+            return NO_MEMORY;
+        }
+        size_t* objects = NULL;
+        
+        if (objectsSize) {
+            objects = (size_t*)malloc(objectsSize*sizeof(size_t));
+            if (!objects) {
+                mError = NO_MEMORY;
+                return NO_MEMORY;
+            }
+
+            // Little hack to only acquire references on objects
+            // we will be keeping.
+            size_t oldObjectsSize = mObjectsSize;
+            mObjectsSize = objectsSize;
+            acquireObjects();
+            mObjectsSize = oldObjectsSize;
+        }
+        
+        if (mData) {
+            memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
+        }
+        if (objects && mObjects) {
+            memcpy(objects, mObjects, objectsSize*sizeof(size_t));
+        }
+        //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
+        mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
+        mOwner = NULL;
+
+        mData = data;
+        mObjects = objects;
+        mDataSize = (mDataSize < desired) ? mDataSize : desired;
+        LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+        mDataCapacity = desired;
+        mObjectsSize = mObjectsCapacity = objectsSize;
+        mNextObjectHint = 0;
+
+    } else if (mData) {
+        if (objectsSize < mObjectsSize) {
+            // Need to release refs on any objects we are dropping.
+            const sp<ProcessState> proc(ProcessState::self());
+            for (size_t i=objectsSize; i<mObjectsSize; i++) {
+                const flat_binder_object* flat
+                    = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
+                if (flat->type == BINDER_TYPE_FD) {
+                    // will need to rescan because we may have lopped off the only FDs
+                    mFdsKnown = false;
+                }
+                release_object(proc, *flat, this);
+            }
+            size_t* objects =
+                (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));
+            if (objects) {
+                mObjects = objects;
+            }
+            mObjectsSize = objectsSize;
+            mNextObjectHint = 0;
+        }
+
+        // We own the data, so we can just do a realloc().
+        if (desired > mDataCapacity) {
+            uint8_t* data = (uint8_t*)realloc(mData, desired);
+            if (data) {
+                mData = data;
+                mDataCapacity = desired;
+            } else if (desired > mDataCapacity) {
+                mError = NO_MEMORY;
+                return NO_MEMORY;
+            }
+        } else {
+            mDataSize = desired;
+            LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+            if (mDataPos > desired) {
+                mDataPos = desired;
+                LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
+            }
+        }
+        
+    } else {
+        // This is the first data.  Easy!
+        uint8_t* data = (uint8_t*)malloc(desired);
+        if (!data) {
+            mError = NO_MEMORY;
+            return NO_MEMORY;
+        }
+        
+        if(!(mDataCapacity == 0 && mObjects == NULL
+             && mObjectsCapacity == 0)) {
+            LOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);
+        }
+        
+        mData = data;
+        mDataSize = mDataPos = 0;
+        LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+        LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
+        mDataCapacity = desired;
+    }
+
+    return NO_ERROR;
+}
+
+void Parcel::initState()
+{
+    mError = NO_ERROR;
+    mData = 0;
+    mDataSize = 0;
+    mDataCapacity = 0;
+    mDataPos = 0;
+    LOGV("initState Setting data size of %p to %d\n", this, mDataSize);
+    LOGV("initState Setting data pos of %p to %d\n", this, mDataPos);
+    mObjects = NULL;
+    mObjectsSize = 0;
+    mObjectsCapacity = 0;
+    mNextObjectHint = 0;
+    mHasFds = false;
+    mFdsKnown = true;
+    mOwner = NULL;
+}
+
+void Parcel::scanForFds() const
+{
+    bool hasFds = false;
+    for (size_t i=0; i<mObjectsSize; i++) {
+        const flat_binder_object* flat
+            = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
+        if (flat->type == BINDER_TYPE_FD) {
+            hasFds = true;
+            break;
+        }
+    }
+    mHasFds = hasFds;
+    mFdsKnown = true;
+}
+
+}; // namespace android
diff --git a/libs/utils/Pipe.cpp b/libs/utils/Pipe.cpp
new file mode 100644
index 0000000..613906b
--- /dev/null
+++ b/libs/utils/Pipe.cpp
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Unidirectional pipe.
+//
+
+#include <utils/Pipe.h>
+#include <utils/Log.h>
+
+#if defined(HAVE_WIN32_IPC)
+# include <windows.h>
+#else
+# include <fcntl.h>
+# include <unistd.h>
+# include <errno.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+using namespace android;
+
+const unsigned long kInvalidHandle = (unsigned long) -1;
+
+
+/*
+ * Constructor.  Do little.
+ */
+Pipe::Pipe(void)
+    : mReadNonBlocking(false), mReadHandle(kInvalidHandle),
+      mWriteHandle(kInvalidHandle)
+{
+}
+
+/*
+ * Destructor.  Use the system-appropriate close call.
+ */
+Pipe::~Pipe(void)
+{
+#if defined(HAVE_WIN32_IPC)
+    if (mReadHandle != kInvalidHandle) {
+        if (!CloseHandle((HANDLE)mReadHandle))
+            LOG(LOG_WARN, "pipe", "failed closing read handle (%ld)\n",
+                mReadHandle);
+    }
+    if (mWriteHandle != kInvalidHandle) {
+        FlushFileBuffers((HANDLE)mWriteHandle);
+        if (!CloseHandle((HANDLE)mWriteHandle))
+            LOG(LOG_WARN, "pipe", "failed closing write handle (%ld)\n",
+                mWriteHandle);
+    }
+#else
+    if (mReadHandle != kInvalidHandle) {
+        if (close((int) mReadHandle) != 0)
+            LOG(LOG_WARN, "pipe", "failed closing read fd (%d)\n",
+                (int) mReadHandle);
+    }
+    if (mWriteHandle != kInvalidHandle) {
+        if (close((int) mWriteHandle) != 0)
+            LOG(LOG_WARN, "pipe", "failed closing write fd (%d)\n",
+                (int) mWriteHandle);
+    }
+#endif
+}
+
+/*
+ * Create the pipe.
+ *
+ * Use the POSIX stuff for everything but Windows.
+ */
+bool Pipe::create(void)
+{
+    assert(mReadHandle == kInvalidHandle);
+    assert(mWriteHandle == kInvalidHandle);
+
+#if defined(HAVE_WIN32_IPC)
+    /* we use this across processes, so they need to be inheritable */
+    HANDLE handles[2];
+    SECURITY_ATTRIBUTES saAttr;
+
+    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+    saAttr.bInheritHandle = TRUE;
+    saAttr.lpSecurityDescriptor = NULL;
+
+    if (!CreatePipe(&handles[0], &handles[1], &saAttr, 0)) {
+        LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
+        return false;
+    }
+    mReadHandle = (unsigned long) handles[0];
+    mWriteHandle = (unsigned long) handles[1];
+    return true;
+#else
+    int fds[2];
+
+    if (pipe(fds) != 0) {
+        LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
+        return false;
+    }
+    mReadHandle = fds[0];
+    mWriteHandle = fds[1];
+    return true;
+#endif
+}
+
+/*
+ * Create a "half pipe".  Please, no Segway riding.
+ */
+bool Pipe::createReader(unsigned long handle)
+{
+    mReadHandle = handle;
+    assert(mWriteHandle == kInvalidHandle);
+    return true;
+}
+
+/*
+ * Create a "half pipe" for writing.
+ */
+bool Pipe::createWriter(unsigned long handle)
+{
+    mWriteHandle = handle;
+    assert(mReadHandle == kInvalidHandle);
+    return true;
+}
+
+/*
+ * Return "true" if create() has been called successfully.
+ */
+bool Pipe::isCreated(void)
+{
+    // one or the other should be open
+    return (mReadHandle != kInvalidHandle || mWriteHandle != kInvalidHandle);
+}
+
+
+/*
+ * Read data from the pipe.
+ *
+ * For Linux and Darwin, just call read().  For Windows, implement
+ * non-blocking reads by calling PeekNamedPipe first.
+ */
+int Pipe::read(void* buf, int count)
+{
+    assert(mReadHandle != kInvalidHandle);
+
+#if defined(HAVE_WIN32_IPC)
+    DWORD totalBytesAvail = count;
+    DWORD bytesRead;
+
+    if (mReadNonBlocking) {
+        // use PeekNamedPipe to adjust read count expectations
+        if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
+                &totalBytesAvail, NULL))
+        {
+            LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
+            return -1;
+        }
+
+        if (totalBytesAvail == 0)
+            return 0;
+    }
+
+    if (!ReadFile((HANDLE) mReadHandle, buf, totalBytesAvail, &bytesRead,
+            NULL))
+    {
+        DWORD err = GetLastError();
+        if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE)
+            return 0;
+        LOG(LOG_ERROR, "pipe", "ReadFile failed (err=%ld)\n", err);
+        return -1;
+    }
+
+    return (int) bytesRead;
+#else
+    int cc;
+    cc = ::read(mReadHandle, buf, count);
+    if (cc < 0 && errno == EAGAIN)
+        return 0;
+    return cc;
+#endif
+}
+
+/*
+ * Write data to the pipe.
+ *
+ * POSIX systems are trivial, Windows uses a different call and doesn't
+ * handle non-blocking writes.
+ *
+ * If we add non-blocking support here, we probably want to make it an
+ * all-or-nothing write.
+ *
+ * DO NOT use LOG() here, we could be writing a log message.
+ */
+int Pipe::write(const void* buf, int count)
+{
+    assert(mWriteHandle != kInvalidHandle);
+
+#if defined(HAVE_WIN32_IPC)
+    DWORD bytesWritten;
+
+    if (mWriteNonBlocking) {
+        // BUG: can't use PeekNamedPipe() to get the amount of space
+        // left.  Looks like we need to use "overlapped I/O" functions.
+        // I just don't care that much.
+    }
+
+    if (!WriteFile((HANDLE) mWriteHandle, buf, count, &bytesWritten, NULL)) {
+        // can't LOG, use stderr
+        fprintf(stderr, "WriteFile failed (err=%ld)\n", GetLastError());
+        return -1;
+    }
+
+    return (int) bytesWritten;
+#else
+    int cc;
+    cc = ::write(mWriteHandle, buf, count);
+    if (cc < 0 && errno == EAGAIN)
+        return 0;
+    return cc;
+#endif
+}
+
+/*
+ * Figure out if there is data available on the read fd.
+ *
+ * We return "true" on error because we want the caller to try to read
+ * from the pipe.  They'll notice the read failure and do something
+ * appropriate.
+ */
+bool Pipe::readReady(void)
+{
+    assert(mReadHandle != kInvalidHandle);
+
+#if defined(HAVE_WIN32_IPC)
+    DWORD totalBytesAvail;
+
+    if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
+            &totalBytesAvail, NULL))
+    {
+        LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
+        return true;
+    }
+
+    return (totalBytesAvail != 0);
+#else
+    errno = 0;
+    fd_set readfds;
+    struct timeval tv = { 0, 0 };
+    int cc;
+
+    FD_ZERO(&readfds);
+    FD_SET(mReadHandle, &readfds);
+
+    cc = select(mReadHandle+1, &readfds, NULL, NULL, &tv);
+    if (cc < 0) {
+        LOG(LOG_ERROR, "pipe", "select() failed\n");
+        return true;
+    } else if (cc == 0) {
+        /* timed out, nothing available */
+        return false;
+    } else if (cc == 1) {
+        /* our fd is ready */
+        return true;
+    } else {
+        LOG(LOG_ERROR, "pipe", "HUH? select() returned > 1\n");
+        return true;
+    }
+#endif
+}
+
+/*
+ * Enable or disable non-blocking mode for the read descriptor.
+ *
+ * NOTE: the calls succeed under Mac OS X, but the pipe doesn't appear to
+ * actually be in non-blocking mode.  If this matters -- i.e. you're not
+ * using a select() call -- put a call to readReady() in front of the
+ * ::read() call, with a PIPE_NONBLOCK_BROKEN #ifdef in the Makefile for
+ * Darwin.
+ */
+bool Pipe::setReadNonBlocking(bool val)
+{
+    assert(mReadHandle != kInvalidHandle);
+
+#if defined(HAVE_WIN32_IPC)
+    // nothing to do
+#else
+    int flags;
+
+    if (fcntl(mReadHandle, F_GETFL, &flags) == -1) {
+        LOG(LOG_ERROR, "pipe", "couldn't get flags for pipe read fd\n");
+        return false;
+    }
+    if (val)
+        flags |= O_NONBLOCK;
+    else
+        flags &= ~(O_NONBLOCK);
+    if (fcntl(mReadHandle, F_SETFL, &flags) == -1) {
+        LOG(LOG_ERROR, "pipe", "couldn't set flags for pipe read fd\n");
+        return false;
+    }
+#endif
+
+    mReadNonBlocking = val;
+    return true;
+}
+
+/*
+ * Enable or disable non-blocking mode for the write descriptor.
+ *
+ * As with setReadNonBlocking(), this does not work on the Mac.
+ */
+bool Pipe::setWriteNonBlocking(bool val)
+{
+    assert(mWriteHandle != kInvalidHandle);
+
+#if defined(HAVE_WIN32_IPC)
+    // nothing to do
+#else
+    int flags;
+
+    if (fcntl(mWriteHandle, F_GETFL, &flags) == -1) {
+        LOG(LOG_WARN, "pipe",
+            "Warning: couldn't get flags for pipe write fd (errno=%d)\n",
+            errno);
+        return false;
+    }
+    if (val)
+        flags |= O_NONBLOCK;
+    else
+        flags &= ~(O_NONBLOCK);
+    if (fcntl(mWriteHandle, F_SETFL, &flags) == -1) {
+        LOG(LOG_WARN, "pipe",
+            "Warning: couldn't set flags for pipe write fd (errno=%d)\n",
+            errno);
+        return false;
+    }
+#endif
+
+    mWriteNonBlocking = val;
+    return true;
+}
+
+/*
+ * Specify whether a file descriptor can be inherited by a child process.
+ * Under Linux this means setting the close-on-exec flag, under Windows
+ * this is SetHandleInformation(HANDLE_FLAG_INHERIT).
+ */
+bool Pipe::disallowReadInherit(void)
+{
+    if (mReadHandle == kInvalidHandle)
+        return false;
+
+#if defined(HAVE_WIN32_IPC)
+    if (SetHandleInformation((HANDLE) mReadHandle, HANDLE_FLAG_INHERIT, 0) == 0)
+        return false;
+#else
+    if (fcntl((int) mReadHandle, F_SETFD, FD_CLOEXEC) != 0)
+        return false;
+#endif
+    return true;
+}
+bool Pipe::disallowWriteInherit(void)
+{
+    if (mWriteHandle == kInvalidHandle)
+        return false;
+
+#if defined(HAVE_WIN32_IPC)
+    if (SetHandleInformation((HANDLE) mWriteHandle, HANDLE_FLAG_INHERIT, 0) == 0)
+        return false;
+#else
+    if (fcntl((int) mWriteHandle, F_SETFD, FD_CLOEXEC) != 0)
+        return false;
+#endif
+    return true;
+}
+
+/*
+ * Close read descriptor.
+ */
+bool Pipe::closeRead(void)
+{
+    if (mReadHandle == kInvalidHandle)
+        return false;
+
+#if defined(HAVE_WIN32_IPC)
+    if (mReadHandle != kInvalidHandle) {
+        if (!CloseHandle((HANDLE)mReadHandle)) {
+            LOG(LOG_WARN, "pipe", "failed closing read handle\n");
+            return false;
+        }
+    }
+#else
+    if (mReadHandle != kInvalidHandle) {
+        if (close((int) mReadHandle) != 0) {
+            LOG(LOG_WARN, "pipe", "failed closing read fd\n");
+            return false;
+        }
+    }
+#endif
+    mReadHandle = kInvalidHandle;
+    return true;
+}
+
+/*
+ * Close write descriptor.
+ */
+bool Pipe::closeWrite(void)
+{
+    if (mWriteHandle == kInvalidHandle)
+        return false;
+
+#if defined(HAVE_WIN32_IPC)
+    if (mWriteHandle != kInvalidHandle) {
+        if (!CloseHandle((HANDLE)mWriteHandle)) {
+            LOG(LOG_WARN, "pipe", "failed closing write handle\n");
+            return false;
+        }
+    }
+#else
+    if (mWriteHandle != kInvalidHandle) {
+        if (close((int) mWriteHandle) != 0) {
+            LOG(LOG_WARN, "pipe", "failed closing write fd\n");
+            return false;
+        }
+    }
+#endif
+    mWriteHandle = kInvalidHandle;
+    return true;
+}
+
+/*
+ * Get the read handle.
+ */
+unsigned long Pipe::getReadHandle(void)
+{
+    assert(mReadHandle != kInvalidHandle);
+
+    return mReadHandle;
+}
+
+/*
+ * Get the write handle.
+ */
+unsigned long Pipe::getWriteHandle(void)
+{
+    assert(mWriteHandle != kInvalidHandle);
+
+    return mWriteHandle;
+}
+
diff --git a/libs/utils/ProcessState.cpp b/libs/utils/ProcessState.cpp
new file mode 100644
index 0000000..4567df6
--- /dev/null
+++ b/libs/utils/ProcessState.cpp
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "ProcessState"
+
+#include <cutils/process_name.h>
+
+#include <utils/ProcessState.h>
+
+#include <utils/Atomic.h>
+#include <utils/BpBinder.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/IServiceManager.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+
+#include <private/utils/binder_module.h>
+#include <private/utils/Static.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#define BINDER_VM_SIZE (1*1024*1024)
+
+static bool gSingleProcess = false;
+
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+ 
+// Global variables
+int                 mArgC;
+const char* const*  mArgV;
+int                 mArgLen;
+
+class PoolThread : public Thread
+{
+public:
+    PoolThread(bool isMain)
+        : mIsMain(isMain)
+    {
+    }
+    
+protected:
+    virtual bool threadLoop()
+    {
+        IPCThreadState::self()->joinThreadPool(mIsMain);
+        return false;
+    }
+    
+    const bool mIsMain;
+};
+
+sp<ProcessState> ProcessState::self()
+{
+    if (gProcess != NULL) return gProcess;
+    
+    AutoMutex _l(gProcessMutex);
+    if (gProcess == NULL) gProcess = new ProcessState;
+    return gProcess;
+}
+
+void ProcessState::setSingleProcess(bool singleProcess)
+{
+    gSingleProcess = singleProcess;
+}
+
+
+void ProcessState::setContextObject(const sp<IBinder>& object)
+{
+    setContextObject(object, String16("default"));
+}
+
+sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
+{
+    if (supportsProcesses()) {
+        return getStrongProxyForHandle(0);
+    } else {
+        return getContextObject(String16("default"), caller);
+    }
+}
+
+void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name)
+{
+    AutoMutex _l(mLock);
+    mContexts.add(name, object);
+}
+
+sp<IBinder> ProcessState::getContextObject(const String16& name, const sp<IBinder>& caller)
+{
+    mLock.lock();
+    sp<IBinder> object(
+        mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : NULL);
+    mLock.unlock();
+    
+    //printf("Getting context object %s for %p\n", String8(name).string(), caller.get());
+    
+    if (object != NULL) return object;
+
+    // Don't attempt to retrieve contexts if we manage them
+    if (mManagesContexts) {
+        LOGE("getContextObject(%s) failed, but we manage the contexts!\n",
+            String8(name).string());
+        return NULL;
+    }
+    
+    IPCThreadState* ipc = IPCThreadState::self();
+    {
+        Parcel data, reply;
+        // no interface token on this magic transaction
+        data.writeString16(name);
+        data.writeStrongBinder(caller);
+        status_t result = ipc->transact(0 /*magic*/, 0, data, &reply, 0);
+        if (result == NO_ERROR) {
+            object = reply.readStrongBinder();
+        }
+    }
+    
+    ipc->flushCommands();
+    
+    if (object != NULL) setContextObject(object, name);
+    return object;
+}
+
+bool ProcessState::supportsProcesses() const
+{
+    return mDriverFD >= 0;
+}
+
+void ProcessState::startThreadPool()
+{
+    AutoMutex _l(mLock);
+    if (!mThreadPoolStarted) {
+        mThreadPoolStarted = true;
+        spawnPooledThread(true);
+    }
+}
+
+bool ProcessState::isContextManager(void) const
+{
+    return mManagesContexts;
+}
+
+bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData)
+{
+    if (!mManagesContexts) {
+        AutoMutex _l(mLock);
+        mBinderContextCheckFunc = checkFunc;
+        mBinderContextUserData = userData;
+        if (mDriverFD >= 0) {
+            int dummy = 0;
+#if defined(HAVE_ANDROID_OS)
+            status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+#else
+            status_t result = INVALID_OPERATION;
+#endif
+            if (result == 0) {
+                mManagesContexts = true;
+            } else if (result == -1) {
+                mBinderContextCheckFunc = NULL;
+                mBinderContextUserData = NULL;
+                LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
+            }
+        } else {
+            // If there is no driver, our only world is the local
+            // process so we can always become the context manager there.
+            mManagesContexts = true;
+        }
+    }
+    return mManagesContexts;
+}
+
+ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
+{
+    const size_t N=mHandleToObject.size();
+    if (N <= (size_t)handle) {
+        handle_entry e;
+        e.binder = NULL;
+        e.refs = NULL;
+        status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
+        if (err < NO_ERROR) return NULL;
+    }
+    return &mHandleToObject.editItemAt(handle);
+}
+
+sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
+{
+    sp<IBinder> result;
+
+    AutoMutex _l(mLock);
+
+    handle_entry* e = lookupHandleLocked(handle);
+
+    if (e != NULL) {
+        // We need to create a new BpBinder if there isn't currently one, OR we
+        // are unable to acquire a weak reference on this current one.  See comment
+        // in getWeakProxyForHandle() for more info about this.
+        IBinder* b = e->binder;
+        if (b == NULL || !e->refs->attemptIncWeak(this)) {
+            b = new BpBinder(handle); 
+            e->binder = b;
+            if (b) e->refs = b->getWeakRefs();
+            result = b;
+        } else {
+            // This little bit of nastyness is to allow us to add a primary
+            // reference to the remote proxy when this team doesn't have one
+            // but another team is sending the handle to us.
+            result.force_set(b);
+            e->refs->decWeak(this);
+        }
+    }
+
+    return result;
+}
+
+wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle)
+{
+    wp<IBinder> result;
+
+    AutoMutex _l(mLock);
+
+    handle_entry* e = lookupHandleLocked(handle);
+
+    if (e != NULL) {        
+        // We need to create a new BpBinder if there isn't currently one, OR we
+        // are unable to acquire a weak reference on this current one.  The
+        // attemptIncWeak() is safe because we know the BpBinder destructor will always
+        // call expungeHandle(), which acquires the same lock we are holding now.
+        // We need to do this because there is a race condition between someone
+        // releasing a reference on this BpBinder, and a new reference on its handle
+        // arriving from the driver.
+        IBinder* b = e->binder;
+        if (b == NULL || !e->refs->attemptIncWeak(this)) {
+            b = new BpBinder(handle);
+            result = b;
+            e->binder = b;
+            if (b) e->refs = b->getWeakRefs();
+        } else {
+            result = b;
+            e->refs->decWeak(this);
+        }
+    }
+
+    return result;
+}
+
+void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
+{
+    AutoMutex _l(mLock);
+    
+    handle_entry* e = lookupHandleLocked(handle);
+
+    // This handle may have already been replaced with a new BpBinder
+    // (if someone failed the AttemptIncWeak() above); we don't want
+    // to overwrite it.
+    if (e && e->binder == binder) e->binder = NULL;
+}
+
+void ProcessState::setArgs(int argc, const char* const argv[])
+{
+    mArgC = argc;
+    mArgV = (const char **)argv;
+
+    mArgLen = 0;
+    for (int i=0; i<argc; i++) {
+        mArgLen += strlen(argv[i]) + 1;
+    }
+    mArgLen--;
+}
+
+int ProcessState::getArgC() const
+{
+    return mArgC;
+}
+
+const char* const* ProcessState::getArgV() const
+{
+    return mArgV;
+}
+
+void ProcessState::setArgV0(const char* txt)
+{
+    if (mArgV != NULL) {
+        strncpy((char*)mArgV[0], txt, mArgLen);
+        set_process_name(txt);
+    }
+}
+
+void ProcessState::spawnPooledThread(bool isMain)
+{
+    if (mThreadPoolStarted) {
+        int32_t s = android_atomic_add(1, &mThreadPoolSeq);
+        char buf[32];
+        sprintf(buf, "Binder Thread #%d", s);
+        LOGV("Spawning new pooled thread, name=%s\n", buf);
+        sp<Thread> t = new PoolThread(isMain);
+        t->run(buf);
+    }
+}
+
+static int open_driver()
+{
+    if (gSingleProcess) {
+        return -1;
+    }
+
+    int fd = open("/dev/binder", O_RDWR);
+    if (fd >= 0) {
+        fcntl(fd, F_SETFD, FD_CLOEXEC);
+        int vers;
+#if defined(HAVE_ANDROID_OS)
+        status_t result = ioctl(fd, BINDER_VERSION, &vers);
+#else
+        status_t result = -1;
+        errno = EPERM;
+#endif
+        if (result == -1) {
+            LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
+            close(fd);
+            fd = -1;
+        }
+        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
+            LOGE("Binder driver protocol does not match user space protocol!");
+            close(fd);
+            fd = -1;
+        }
+#if defined(HAVE_ANDROID_OS)
+        size_t maxThreads = 15;
+        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
+        if (result == -1) {
+            LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
+        }
+#endif
+        
+    } else {
+        LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
+    }
+    return fd;
+}
+
+ProcessState::ProcessState()
+    : mDriverFD(open_driver())
+    , mVMStart(MAP_FAILED)
+    , mManagesContexts(false)
+    , mBinderContextCheckFunc(NULL)
+    , mBinderContextUserData(NULL)
+    , mThreadPoolStarted(false)
+    , mThreadPoolSeq(1)
+{
+    if (mDriverFD >= 0) {
+        // XXX Ideally, there should be a specific define for whether we
+        // have mmap (or whether we could possibly have the kernel module
+        // availabla).
+#if !defined(HAVE_WIN32_IPC)
+        // mmap the binder, providing a chunk of virtual address space to receive transactions.
+        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
+        if (mVMStart == MAP_FAILED) {
+            // *sigh*
+            LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
+            close(mDriverFD);
+            mDriverFD = -1;
+        }
+#else
+        mDriverFD = -1;
+#endif
+    }
+    if (mDriverFD < 0) {
+        // Need to run without the driver, starting our own thread pool.
+    }
+}
+
+ProcessState::~ProcessState()
+{
+}
+        
+}; // namespace android
diff --git a/libs/utils/README b/libs/utils/README
new file mode 100644
index 0000000..36a706d
--- /dev/null
+++ b/libs/utils/README
@@ -0,0 +1,14 @@
+Android Utility Function Library
+
+If you need a feature that is native to Linux but not present on other
+platforms, construct a platform-dependent implementation that shares
+the Linux interface.  That way the actual device runs as "light" as
+possible.
+
+If that isn't feasible, create a system-independent interface and hide
+the details.
+
+The ultimate goal is *not* to create a super-duper platform abstraction
+layer.  The goal is to provide an optimized solution for Linux with
+reasonable implementations for other platforms.
+
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
new file mode 100644
index 0000000..0bd1af4
--- /dev/null
+++ b/libs/utils/RefBase.cpp
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "RefBase"
+
+#include <utils/RefBase.h>
+
+#include <utils/Atomic.h>
+#include <utils/CallStack.h>
+#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <typeinfo>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+// compile with refcounting debugging enabled
+#define DEBUG_REFS                      0
+#define DEBUG_REFS_ENABLED_BY_DEFAULT   1
+#define DEBUG_REFS_CALLSTACK_ENABLED    1
+
+// log all reference counting operations
+#define PRINT_REFS                      0
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+#define INITIAL_STRONG_VALUE (1<<28)
+
+// ---------------------------------------------------------------------------
+
+class RefBase::weakref_impl : public RefBase::weakref_type
+{
+public:
+    volatile int32_t    mStrong;
+    volatile int32_t    mWeak;
+    RefBase* const      mBase;
+    volatile int32_t    mFlags;
+
+
+#if !DEBUG_REFS
+
+    weakref_impl(RefBase* base)
+        : mStrong(INITIAL_STRONG_VALUE)
+        , mWeak(0)
+        , mBase(base)
+        , mFlags(0)
+    {
+    }
+
+    void addStrongRef(const void* /*id*/) { }
+    void removeStrongRef(const void* /*id*/) { }
+    void addWeakRef(const void* /*id*/) { }
+    void removeWeakRef(const void* /*id*/) { }
+    void printRefs() const { }
+    void trackMe(bool, bool) { }
+
+#else
+
+    weakref_impl(RefBase* base)
+        : mStrong(INITIAL_STRONG_VALUE)
+        , mWeak(0)
+        , mBase(base)
+        , mFlags(0)
+        , mStrongRefs(NULL)
+        , mWeakRefs(NULL)
+        , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
+        , mRetain(false)
+    {
+        //LOGI("NEW weakref_impl %p for RefBase %p", this, base);
+    }
+    
+    ~weakref_impl()
+    {
+        LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");
+        LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");
+    }
+
+    void addStrongRef(const void* id)
+    {
+        addRef(&mStrongRefs, id, mStrong);
+    }
+
+    void removeStrongRef(const void* id)
+    {
+        if (!mRetain)
+            removeRef(&mStrongRefs, id);
+        else
+            addRef(&mStrongRefs, id, -mStrong);
+    }
+
+    void addWeakRef(const void* id)
+    {
+        addRef(&mWeakRefs, id, mWeak);
+    }
+
+    void removeWeakRef(const void* id)
+    {
+        if (!mRetain)
+            removeRef(&mWeakRefs, id);
+        else
+            addRef(&mWeakRefs, id, -mWeak);
+    }
+
+    void trackMe(bool track, bool retain)
+    { 
+        mTrackEnabled = track;
+        mRetain = retain;
+    }
+
+    void printRefs() const
+    {
+        String8 text;
+
+        {
+            AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex);
+    
+            char buf[128];
+            sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
+            text.append(buf);
+            printRefsLocked(&text, mStrongRefs);
+            sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
+            text.append(buf);
+            printRefsLocked(&text, mWeakRefs);
+        }
+
+        {
+            char name[100];
+            snprintf(name, 100, "/data/%p.stack", this);
+            int rc = open(name, O_RDWR | O_CREAT | O_APPEND);
+            if (rc >= 0) {
+                write(rc, text.string(), text.length());
+                close(rc);
+                LOGD("STACK TRACE for %p saved in %s", this, name);
+            }
+            else LOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
+                      name, strerror(errno));
+        }
+    }
+
+private:
+    struct ref_entry
+    {
+        ref_entry* next;
+        const void* id;
+#if DEBUG_REFS_CALLSTACK_ENABLED
+        CallStack stack;
+#endif
+        int32_t ref;
+    };
+
+    void addRef(ref_entry** refs, const void* id, int32_t mRef)
+    {
+        if (mTrackEnabled) {
+            AutoMutex _l(mMutex);
+            ref_entry* ref = new ref_entry;
+            // Reference count at the time of the snapshot, but before the
+            // update.  Positive value means we increment, negative--we
+            // decrement the reference count.
+            ref->ref = mRef;
+            ref->id = id;
+#if DEBUG_REFS_CALLSTACK_ENABLED
+            ref->stack.update(2);
+#endif
+            
+            ref->next = *refs;
+            *refs = ref;
+        }
+    }
+
+    void removeRef(ref_entry** refs, const void* id)
+    {
+        if (mTrackEnabled) {
+            AutoMutex _l(mMutex);
+            
+            ref_entry* ref = *refs;
+            while (ref != NULL) {
+                if (ref->id == id) {
+                    *refs = ref->next;
+                    delete ref;
+                    return;
+                }
+                
+                refs = &ref->next;
+                ref = *refs;
+            }
+            
+            LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",
+                             id, mBase, this);
+        }
+    }
+
+    void printRefsLocked(String8* out, const ref_entry* refs) const
+    {
+        char buf[128];
+        while (refs) {
+            char inc = refs->ref >= 0 ? '+' : '-';
+            sprintf(buf, "\t%c ID %p (ref %d):\n", 
+                    inc, refs->id, refs->ref);
+            out->append(buf);
+#if DEBUG_REFS_CALLSTACK_ENABLED
+            out->append(refs->stack.toString("\t\t"));
+#else
+            out->append("\t\t(call stacks disabled)");
+#endif
+            refs = refs->next;
+        }
+    }
+
+    Mutex mMutex;
+    ref_entry* mStrongRefs;
+    ref_entry* mWeakRefs;
+
+    bool mTrackEnabled;
+    // Collect stack traces on addref and removeref, instead of deleting the stack references
+    // on removeref that match the address ones.
+    bool mRetain;
+
+#if 0
+    void addRef(KeyedVector<const void*, int32_t>* refs, const void* id)
+    {
+        AutoMutex _l(mMutex);
+        ssize_t i = refs->indexOfKey(id);
+        if (i >= 0) {
+            ++(refs->editValueAt(i));
+        } else {
+            i = refs->add(id, 1);
+        }
+    }
+
+    void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id)
+    {
+        AutoMutex _l(mMutex);
+        ssize_t i = refs->indexOfKey(id);
+        LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id);
+        if (i >= 0) {
+            int32_t val = --(refs->editValueAt(i));
+            if (val == 0) {
+                refs->removeItemsAt(i);
+            }
+        }
+    }
+
+    void printRefs(const KeyedVector<const void*, int32_t>& refs)
+    {
+        const size_t N=refs.size();
+        for (size_t i=0; i<N; i++) {
+            printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i));
+        }
+    }
+
+    mutable Mutex mMutex;
+    KeyedVector<const void*, int32_t> mStrongRefs;
+    KeyedVector<const void*, int32_t> mWeakRefs;
+#endif
+
+#endif
+};
+
+// ---------------------------------------------------------------------------
+
+void RefBase::incStrong(const void* id) const
+{
+    weakref_impl* const refs = mRefs;
+    refs->addWeakRef(id);
+    refs->incWeak(id);
+    
+    refs->addStrongRef(id);
+    const int32_t c = android_atomic_inc(&refs->mStrong);
+    LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
+#if PRINT_REFS
+    LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
+#endif
+    if (c != INITIAL_STRONG_VALUE)  {
+        return;
+    }
+
+    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
+    const_cast<RefBase*>(this)->onFirstRef();
+}
+
+void RefBase::decStrong(const void* id) const
+{
+    weakref_impl* const refs = mRefs;
+    refs->removeStrongRef(id);
+    const int32_t c = android_atomic_dec(&refs->mStrong);
+#if PRINT_REFS
+    LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
+#endif
+    LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
+    if (c == 1) {
+        const_cast<RefBase*>(this)->onLastStrongRef(id);
+        if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
+            delete this;
+        }
+    }
+    refs->removeWeakRef(id);
+    refs->decWeak(id);
+}
+
+void RefBase::forceIncStrong(const void* id) const
+{
+    weakref_impl* const refs = mRefs;
+    refs->addWeakRef(id);
+    refs->incWeak(id);
+    
+    refs->addStrongRef(id);
+    const int32_t c = android_atomic_inc(&refs->mStrong);
+    LOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
+               refs);
+#if PRINT_REFS
+    LOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
+#endif
+
+    switch (c) {
+    case INITIAL_STRONG_VALUE:
+        android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
+        // fall through...
+    case 0:
+        const_cast<RefBase*>(this)->onFirstRef();
+    }
+}
+
+int32_t RefBase::getStrongCount() const
+{
+    return mRefs->mStrong;
+}
+
+
+
+RefBase* RefBase::weakref_type::refBase() const
+{
+    return static_cast<const weakref_impl*>(this)->mBase;
+}
+
+void RefBase::weakref_type::incWeak(const void* id)
+{
+    weakref_impl* const impl = static_cast<weakref_impl*>(this);
+    impl->addWeakRef(id);
+    const int32_t c = android_atomic_inc(&impl->mWeak);
+    LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
+}
+
+void RefBase::weakref_type::decWeak(const void* id)
+{
+    weakref_impl* const impl = static_cast<weakref_impl*>(this);
+    impl->removeWeakRef(id);
+    const int32_t c = android_atomic_dec(&impl->mWeak);
+    LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
+    if (c != 1) return;
+    
+    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
+        if (impl->mStrong == INITIAL_STRONG_VALUE)
+            delete impl->mBase;
+        else {
+//            LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
+            delete impl;
+        }
+    } else {
+        impl->mBase->onLastWeakRef(id);
+        if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
+            delete impl->mBase;
+        }
+    }
+}
+
+bool RefBase::weakref_type::attemptIncStrong(const void* id)
+{
+    incWeak(id);
+    
+    weakref_impl* const impl = static_cast<weakref_impl*>(this);
+    
+    int32_t curCount = impl->mStrong;
+    LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
+               this);
+    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
+        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
+            break;
+        }
+        curCount = impl->mStrong;
+    }
+    
+    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
+        bool allow;
+        if (curCount == INITIAL_STRONG_VALUE) {
+            // Attempting to acquire first strong reference...  this is allowed
+            // if the object does NOT have a longer lifetime (meaning the
+            // implementation doesn't need to see this), or if the implementation
+            // allows it to happen.
+            allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
+                  || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
+        } else {
+            // Attempting to revive the object...  this is allowed
+            // if the object DOES have a longer lifetime (so we can safely
+            // call the object with only a weak ref) and the implementation
+            // allows it to happen.
+            allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
+                  && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
+        }
+        if (!allow) {
+            decWeak(id);
+            return false;
+        }
+        curCount = android_atomic_inc(&impl->mStrong);
+
+        // If the strong reference count has already been incremented by
+        // someone else, the implementor of onIncStrongAttempted() is holding
+        // an unneeded reference.  So call onLastStrongRef() here to remove it.
+        // (No, this is not pretty.)  Note that we MUST NOT do this if we
+        // are in fact acquiring the first reference.
+        if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
+            impl->mBase->onLastStrongRef(id);
+        }
+    }
+    
+    impl->addWeakRef(id);
+    impl->addStrongRef(id);
+
+#if PRINT_REFS
+    LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
+#endif
+
+    if (curCount == INITIAL_STRONG_VALUE) {
+        android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
+        impl->mBase->onFirstRef();
+    }
+    
+    return true;
+}
+
+bool RefBase::weakref_type::attemptIncWeak(const void* id)
+{
+    weakref_impl* const impl = static_cast<weakref_impl*>(this);
+    
+    int32_t curCount = impl->mWeak;
+    LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
+               this);
+    while (curCount > 0) {
+        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
+            break;
+        }
+        curCount = impl->mWeak;
+    }
+
+    if (curCount > 0) {
+        impl->addWeakRef(id);
+    }
+
+    return curCount > 0;
+}
+
+int32_t RefBase::weakref_type::getWeakCount() const
+{
+    return static_cast<const weakref_impl*>(this)->mWeak;
+}
+
+void RefBase::weakref_type::printRefs() const
+{
+    static_cast<const weakref_impl*>(this)->printRefs();
+}
+
+void RefBase::weakref_type::trackMe(bool enable, bool retain)
+{
+    static_cast<const weakref_impl*>(this)->trackMe(enable, retain);
+}
+
+RefBase::weakref_type* RefBase::createWeak(const void* id) const
+{
+    mRefs->incWeak(id);
+    return mRefs;
+}
+
+RefBase::weakref_type* RefBase::getWeakRefs() const
+{
+    return mRefs;
+}
+
+RefBase::RefBase()
+    : mRefs(new weakref_impl(this))
+{
+//    LOGV("Creating refs %p with RefBase %p\n", mRefs, this);
+}
+
+RefBase::~RefBase()
+{
+//    LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);
+    if (mRefs->mWeak == 0) {
+//        LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);
+        delete mRefs;
+    }
+}
+
+void RefBase::extendObjectLifetime(int32_t mode)
+{
+    android_atomic_or(mode, &mRefs->mFlags);
+}
+
+void RefBase::onFirstRef()
+{
+}
+
+void RefBase::onLastStrongRef(const void* /*id*/)
+{
+}
+
+bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
+{
+    return (flags&FIRST_INC_STRONG) ? true : false;
+}
+
+void RefBase::onLastWeakRef(const void* /*id*/)
+{
+}
+        
+}; // namespace android
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
new file mode 100644
index 0000000..71e7cd7
--- /dev/null
+++ b/libs/utils/ResourceTypes.cpp
@@ -0,0 +1,3983 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ResourceType"
+//#define LOG_NDEBUG 0
+
+#include <utils/Atomic.h>
+#include <utils/ByteOrder.h>
+#include <utils/Debug.h>
+#include <utils/ResourceTypes.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/TextOutput.h>
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#ifndef INT32_MAX
+#define INT32_MAX ((int32_t)(2147483647))
+#endif
+
+#define POOL_NOISY(x) //x
+#define XML_NOISY(x) //x
+#define TABLE_NOISY(x) //x
+#define TABLE_GETENTRY(x) //x
+#define TABLE_SUPER_NOISY(x) //x
+#define LOAD_TABLE_NOISY(x) //x
+
+namespace android {
+
+#ifdef HAVE_WINSOCK
+#undef  nhtol
+#undef  htonl
+
+#ifdef HAVE_LITTLE_ENDIAN
+#define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
+#define htonl(x)    ntohl(x)
+#define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
+#define htons(x)    ntohs(x)
+#else
+#define ntohl(x)    (x)
+#define htonl(x)    (x)
+#define ntohs(x)    (x)
+#define htons(x)    (x)
+#endif
+#endif
+
+static void printToLogFunc(void* cookie, const char* txt)
+{
+    LOGV("%s", txt);
+}
+
+// Standard C isspace() is only required to look at the low byte of its input, so
+// produces incorrect results for UTF-16 characters.  For safety's sake, assume that
+// any high-byte UTF-16 code point is not whitespace.
+inline int isspace16(char16_t c) {
+    return (c < 0x0080 && isspace(c));
+}
+
+// range checked; guaranteed to NUL-terminate within the stated number of available slots
+// NOTE: if this truncates the dst string due to running out of space, no attempt is
+// made to avoid splitting surrogate pairs.
+static void strcpy16_dtoh(uint16_t* dst, const uint16_t* src, size_t avail)
+{
+    uint16_t* last = dst + avail - 1;
+    while (*src && (dst < last)) {
+        char16_t s = dtohs(*src);
+        *dst++ = s;
+        src++;
+    }
+    *dst = 0;
+}
+
+static status_t validate_chunk(const ResChunk_header* chunk,
+                               size_t minSize,
+                               const uint8_t* dataEnd,
+                               const char* name)
+{
+    const uint16_t headerSize = dtohs(chunk->headerSize);
+    const uint32_t size = dtohl(chunk->size);
+
+    if (headerSize >= minSize) {
+        if (headerSize <= size) {
+            if (((headerSize|size)&0x3) == 0) {
+                if ((ssize_t)size <= (dataEnd-((const uint8_t*)chunk))) {
+                    return NO_ERROR;
+                }
+                LOGW("%s data size %p extends beyond resource end %p.",
+                     name, (void*)size,
+                     (void*)(dataEnd-((const uint8_t*)chunk)));
+                return BAD_TYPE;
+            }
+            LOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.",
+                 name, (int)size, (int)headerSize);
+            return BAD_TYPE;
+        }
+        LOGW("%s size %p is smaller than header size %p.",
+             name, (void*)size, (void*)(int)headerSize);
+        return BAD_TYPE;
+    }
+    LOGW("%s header size %p is too small.",
+         name, (void*)(int)headerSize);
+    return BAD_TYPE;
+}
+
+inline void Res_value::copyFrom_dtoh(const Res_value& src)
+{
+    size = dtohs(src.size);
+    res0 = src.res0;
+    dataType = src.dataType;
+    data = dtohl(src.data);
+}
+
+void Res_png_9patch::deviceToFile()
+{
+    for (int i = 0; i < numXDivs; i++) {
+        xDivs[i] = htonl(xDivs[i]);
+    }
+    for (int i = 0; i < numYDivs; i++) {
+        yDivs[i] = htonl(yDivs[i]);
+    }
+    paddingLeft = htonl(paddingLeft);
+    paddingRight = htonl(paddingRight);
+    paddingTop = htonl(paddingTop);
+    paddingBottom = htonl(paddingBottom);
+    for (int i=0; i<numColors; i++) {
+        colors[i] = htonl(colors[i]);
+    }
+}
+
+void Res_png_9patch::fileToDevice()
+{
+    for (int i = 0; i < numXDivs; i++) {
+        xDivs[i] = ntohl(xDivs[i]);
+    }
+    for (int i = 0; i < numYDivs; i++) {
+        yDivs[i] = ntohl(yDivs[i]);
+    }
+    paddingLeft = ntohl(paddingLeft);
+    paddingRight = ntohl(paddingRight);
+    paddingTop = ntohl(paddingTop);
+    paddingBottom = ntohl(paddingBottom);
+    for (int i=0; i<numColors; i++) {
+        colors[i] = ntohl(colors[i]);
+    }
+}
+
+size_t Res_png_9patch::serializedSize()
+{
+    // The size of this struct is 32 bytes on the 32-bit target system
+    // 4 * int8_t
+    // 4 * int32_t
+    // 3 * pointer
+    return 32
+            + numXDivs * sizeof(int32_t)
+            + numYDivs * sizeof(int32_t)
+            + numColors * sizeof(uint32_t);
+}
+
+void* Res_png_9patch::serialize()
+{
+    void* newData = malloc(serializedSize());
+    serialize(newData);
+    return newData;
+}
+
+void Res_png_9patch::serialize(void * outData)
+{
+    char* data = (char*) outData;
+    memmove(data, &wasDeserialized, 4);     // copy  wasDeserialized, numXDivs, numYDivs, numColors
+    memmove(data + 12, &paddingLeft, 16);   // copy paddingXXXX
+    data += 32;
+
+    memmove(data, this->xDivs, numXDivs * sizeof(int32_t));
+    data +=  numXDivs * sizeof(int32_t);
+    memmove(data, this->yDivs, numYDivs * sizeof(int32_t));
+    data +=  numYDivs * sizeof(int32_t);
+    memmove(data, this->colors, numColors * sizeof(uint32_t));
+}
+
+static void deserializeInternal(const void* inData, Res_png_9patch* outData) {
+    char* patch = (char*) inData;
+    if (inData != outData) {
+        memmove(&outData->wasDeserialized, patch, 4);     // copy  wasDeserialized, numXDivs, numYDivs, numColors
+        memmove(&outData->paddingLeft, patch + 12, 4);     // copy  wasDeserialized, numXDivs, numYDivs, numColors
+    }
+    outData->wasDeserialized = true;
+    char* data = (char*)outData;
+    data +=  sizeof(Res_png_9patch);
+    outData->xDivs = (int32_t*) data;
+    data +=  outData->numXDivs * sizeof(int32_t);
+    outData->yDivs = (int32_t*) data;
+    data +=  outData->numYDivs * sizeof(int32_t);
+    outData->colors = (uint32_t*) data;
+}
+
+Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
+{
+    if (sizeof(void*) != sizeof(int32_t)) {
+        LOGE("Cannot deserialize on non 32-bit system\n");
+        return NULL;
+    }
+    deserializeInternal(inData, (Res_png_9patch*) inData);
+    return (Res_png_9patch*) inData;
+}
+
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+
+ResStringPool::ResStringPool()
+    : mError(NO_INIT), mOwnedData(NULL)
+{
+}
+
+ResStringPool::ResStringPool(const void* data, size_t size, bool copyData)
+    : mError(NO_INIT), mOwnedData(NULL)
+{
+    setTo(data, size, copyData);
+}
+
+ResStringPool::~ResStringPool()
+{
+    uninit();
+}
+
+status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
+{
+    if (!data || !size) {
+        return (mError=BAD_TYPE);
+    }
+
+    uninit();
+
+    const bool notDeviceEndian = htods(0xf0) != 0xf0;
+
+    if (copyData || notDeviceEndian) {
+        mOwnedData = malloc(size);
+        if (mOwnedData == NULL) {
+            return (mError=NO_MEMORY);
+        }
+        memcpy(mOwnedData, data, size);
+        data = mOwnedData;
+    }
+
+    mHeader = (const ResStringPool_header*)data;
+
+    if (notDeviceEndian) {
+        ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader);
+        h->header.headerSize = dtohs(mHeader->header.headerSize);
+        h->header.type = dtohs(mHeader->header.type);
+        h->header.size = dtohl(mHeader->header.size);
+        h->stringCount = dtohl(mHeader->stringCount);
+        h->styleCount = dtohl(mHeader->styleCount);
+        h->flags = dtohl(mHeader->flags);
+        h->stringsStart = dtohl(mHeader->stringsStart);
+        h->stylesStart = dtohl(mHeader->stylesStart);
+    }
+
+    if (mHeader->header.headerSize > mHeader->header.size
+            || mHeader->header.size > size) {
+        LOGW("Bad string block: header size %d or total size %d is larger than data size %d\n",
+                (int)mHeader->header.headerSize, (int)mHeader->header.size, (int)size);
+        return (mError=BAD_TYPE);
+    }
+    mSize = mHeader->header.size;
+    mEntries = (const uint32_t*)
+        (((const uint8_t*)data)+mHeader->header.headerSize);
+
+    if (mHeader->stringCount > 0) {
+        if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount)  // uint32 overflow?
+            || (mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t)))
+                > size) {
+            LOGW("Bad string block: entry of %d items extends past data size %d\n",
+                    (int)(mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))),
+                    (int)size);
+            return (mError=BAD_TYPE);
+        }
+        mStrings = (const char16_t*)
+            (((const uint8_t*)data)+mHeader->stringsStart);
+        if (mHeader->stringsStart >= (mHeader->header.size-sizeof(uint16_t))) {
+            LOGW("Bad string block: string pool starts at %d, after total size %d\n",
+                    (int)mHeader->stringsStart, (int)mHeader->header.size);
+            return (mError=BAD_TYPE);
+        }
+        if (mHeader->styleCount == 0) {
+            mStringPoolSize =
+                (mHeader->header.size-mHeader->stringsStart)/sizeof(uint16_t);
+        } else {
+            // check invariant: styles follow the strings
+            if (mHeader->stylesStart <= mHeader->stringsStart) {
+                LOGW("Bad style block: style block starts at %d, before strings at %d\n",
+                    (int)mHeader->stylesStart, (int)mHeader->stringsStart);
+                return (mError=BAD_TYPE);
+            }
+            mStringPoolSize =
+                (mHeader->stylesStart-mHeader->stringsStart)/sizeof(uint16_t);
+        }
+
+        // check invariant: stringCount > 0 requires a string pool to exist
+        if (mStringPoolSize == 0) {
+            LOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader->stringCount);
+            return (mError=BAD_TYPE);
+        }
+
+        if (notDeviceEndian) {
+            size_t i;
+            uint32_t* e = const_cast<uint32_t*>(mEntries);
+            for (i=0; i<mHeader->stringCount; i++) {
+                e[i] = dtohl(mEntries[i]);
+            }
+            char16_t* s = const_cast<char16_t*>(mStrings);
+            for (i=0; i<mStringPoolSize; i++) {
+                s[i] = dtohs(mStrings[i]);
+            }
+        }
+
+        if (mStrings[mStringPoolSize-1] != 0) {
+            LOGW("Bad string block: last string is not 0-terminated\n");
+            return (mError=BAD_TYPE);
+        }
+    } else {
+        mStrings = NULL;
+        mStringPoolSize = 0;
+    }
+
+    if (mHeader->styleCount > 0) {
+        mEntryStyles = mEntries + mHeader->stringCount;
+        // invariant: integer overflow in calculating mEntryStyles
+        if (mEntryStyles < mEntries) {
+            LOGW("Bad string block: integer overflow finding styles\n");
+            return (mError=BAD_TYPE);
+        }
+
+        if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
+            LOGW("Bad string block: entry of %d styles extends past data size %d\n",
+                    (int)((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader),
+                    (int)size);
+            return (mError=BAD_TYPE);
+        }
+        mStyles = (const uint32_t*)
+            (((const uint8_t*)data)+mHeader->stylesStart);
+        if (mHeader->stylesStart >= mHeader->header.size) {
+            LOGW("Bad string block: style pool starts %d, after total size %d\n",
+                    (int)mHeader->stylesStart, (int)mHeader->header.size);
+            return (mError=BAD_TYPE);
+        }
+        mStylePoolSize =
+            (mHeader->header.size-mHeader->stylesStart)/sizeof(uint32_t);
+
+        if (notDeviceEndian) {
+            size_t i;
+            uint32_t* e = const_cast<uint32_t*>(mEntryStyles);
+            for (i=0; i<mHeader->styleCount; i++) {
+                e[i] = dtohl(mEntryStyles[i]);
+            }
+            uint32_t* s = const_cast<uint32_t*>(mStyles);
+            for (i=0; i<mStylePoolSize; i++) {
+                s[i] = dtohl(mStyles[i]);
+            }
+        }
+
+        const ResStringPool_span endSpan = {
+            { htodl(ResStringPool_span::END) },
+            htodl(ResStringPool_span::END), htodl(ResStringPool_span::END)
+        };
+        if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))],
+                   &endSpan, sizeof(endSpan)) != 0) {
+            LOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
+            return (mError=BAD_TYPE);
+        }
+    } else {
+        mEntryStyles = NULL;
+        mStyles = NULL;
+        mStylePoolSize = 0;
+    }
+
+    return (mError=NO_ERROR);
+}
+
+status_t ResStringPool::getError() const
+{
+    return mError;
+}
+
+void ResStringPool::uninit()
+{
+    mError = NO_INIT;
+    if (mOwnedData) {
+        free(mOwnedData);
+        mOwnedData = NULL;
+    }
+}
+
+const uint16_t* ResStringPool::stringAt(size_t idx, size_t* outLen) const
+{
+    if (mError == NO_ERROR && idx < mHeader->stringCount) {
+        const uint32_t off = (mEntries[idx]/sizeof(uint16_t));
+        if (off < (mStringPoolSize-1)) {
+            const char16_t* str = mStrings+off;
+            *outLen = *str;
+            if ((*str)&0x8000) {
+                str++;
+                *outLen = (((*outLen)&0x7fff)<<16) + *str;
+            }
+            if ((uint32_t)(str+1+*outLen-mStrings) < mStringPoolSize) {
+                return str+1;
+            } else {
+                LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
+                        (int)idx, (int)(str+1+*outLen-mStrings), (int)mStringPoolSize);
+            }
+        } else {
+            LOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
+                    (int)idx, (int)(off*sizeof(uint16_t)),
+                    (int)(mStringPoolSize*sizeof(uint16_t)));
+        }
+    }
+    return NULL;
+}
+
+const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
+{
+    return styleAt(ref.index);
+}
+
+const ResStringPool_span* ResStringPool::styleAt(size_t idx) const
+{
+    if (mError == NO_ERROR && idx < mHeader->styleCount) {
+        const uint32_t off = (mEntryStyles[idx]/sizeof(uint32_t));
+        if (off < mStylePoolSize) {
+            return (const ResStringPool_span*)(mStyles+off);
+        } else {
+            LOGW("Bad string block: style #%d entry is at %d, past end at %d\n",
+                    (int)idx, (int)(off*sizeof(uint32_t)),
+                    (int)(mStylePoolSize*sizeof(uint32_t)));
+        }
+    }
+    return NULL;
+}
+
+ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
+{
+    if (mError != NO_ERROR) {
+        return mError;
+    }
+
+    size_t len;
+
+    if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
+        // Do a binary search for the string...
+        ssize_t l = 0;
+        ssize_t h = mHeader->stringCount-1;
+
+        ssize_t mid;
+        while (l <= h) {
+            mid = l + (h - l)/2;
+            const char16_t* s = stringAt(mid, &len);
+            int c = s ? strzcmp16(s, len, str, strLen) : -1;
+            POOL_NOISY(printf("Looking for %s, at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
+                         String8(str).string(),
+                         String8(s).string(),
+                         c, (int)l, (int)mid, (int)h));
+            if (c == 0) {
+                return mid;
+            } else if (c < 0) {
+                l = mid + 1;
+            } else {
+                h = mid - 1;
+            }
+        }
+    } else {
+        // It is unusual to get the ID from an unsorted string block...
+        // most often this happens because we want to get IDs for style
+        // span tags; since those always appear at the end of the string
+        // block, start searching at the back.
+        for (int i=mHeader->stringCount-1; i>=0; i--) {
+            const char16_t* s = stringAt(i, &len);
+            POOL_NOISY(printf("Looking for %s, at %s, i=%d\n",
+                         String8(str, strLen).string(),
+                         String8(s).string(),
+                         i));
+            if (s && strzcmp16(s, len, str, strLen) == 0) {
+                return i;
+            }
+        }
+    }
+
+    return NAME_NOT_FOUND;
+}
+
+size_t ResStringPool::size() const
+{
+    return (mError == NO_ERROR) ? mHeader->stringCount : 0;
+}
+
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+
+ResXMLParser::ResXMLParser(const ResXMLTree& tree)
+    : mTree(tree), mEventCode(BAD_DOCUMENT)
+{
+}
+
+void ResXMLParser::restart()
+{
+    mCurNode = NULL;
+    mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT;
+}
+
+ResXMLParser::event_code_t ResXMLParser::getEventType() const
+{
+    return mEventCode;
+}
+
+ResXMLParser::event_code_t ResXMLParser::next()
+{
+    if (mEventCode == START_DOCUMENT) {
+        mCurNode = mTree.mRootNode;
+        mCurExt = mTree.mRootExt;
+        return (mEventCode=mTree.mRootCode);
+    } else if (mEventCode >= FIRST_CHUNK_CODE) {
+        return nextNode();
+    }
+    return mEventCode;
+}
+
+const int32_t ResXMLParser::getCommentID() const
+{
+    return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1;
+}
+
+const uint16_t* ResXMLParser::getComment(size_t* outLen) const
+{
+    int32_t id = getCommentID();
+    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+const uint32_t ResXMLParser::getLineNumber() const
+{
+    return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1;
+}
+
+const int32_t ResXMLParser::getTextID() const
+{
+    if (mEventCode == TEXT) {
+        return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index);
+    }
+    return -1;
+}
+
+const uint16_t* ResXMLParser::getText(size_t* outLen) const
+{
+    int32_t id = getTextID();
+    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+ssize_t ResXMLParser::getTextValue(Res_value* outValue) const
+{
+    if (mEventCode == TEXT) {
+        outValue->copyFrom_dtoh(((const ResXMLTree_cdataExt*)mCurExt)->typedData);
+        return sizeof(Res_value);
+    }
+    return BAD_TYPE;
+}
+
+const int32_t ResXMLParser::getNamespacePrefixID() const
+{
+    if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
+        return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index);
+    }
+    return -1;
+}
+
+const uint16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const
+{
+    int32_t id = getNamespacePrefixID();
+    //printf("prefix=%d  event=%p\n", id, mEventCode);
+    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+const int32_t ResXMLParser::getNamespaceUriID() const
+{
+    if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
+        return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index);
+    }
+    return -1;
+}
+
+const uint16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const
+{
+    int32_t id = getNamespaceUriID();
+    //printf("uri=%d  event=%p\n", id, mEventCode);
+    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+const int32_t ResXMLParser::getElementNamespaceID() const
+{
+    if (mEventCode == START_TAG) {
+        return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index);
+    }
+    if (mEventCode == END_TAG) {
+        return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->ns.index);
+    }
+    return -1;
+}
+
+const uint16_t* ResXMLParser::getElementNamespace(size_t* outLen) const
+{
+    int32_t id = getElementNamespaceID();
+    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+const int32_t ResXMLParser::getElementNameID() const
+{
+    if (mEventCode == START_TAG) {
+        return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index);
+    }
+    if (mEventCode == END_TAG) {
+        return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->name.index);
+    }
+    return -1;
+}
+
+const uint16_t* ResXMLParser::getElementName(size_t* outLen) const
+{
+    int32_t id = getElementNameID();
+    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+size_t ResXMLParser::getAttributeCount() const
+{
+    if (mEventCode == START_TAG) {
+        return dtohs(((const ResXMLTree_attrExt*)mCurExt)->attributeCount);
+    }
+    return 0;
+}
+
+const int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
+{
+    if (mEventCode == START_TAG) {
+        const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
+        if (idx < dtohs(tag->attributeCount)) {
+            const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
+                (((const uint8_t*)tag)
+                 + dtohs(tag->attributeStart)
+                 + (dtohs(tag->attributeSize)*idx));
+            return dtohl(attr->ns.index);
+        }
+    }
+    return -2;
+}
+
+const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) const
+{
+    int32_t id = getAttributeNamespaceID(idx);
+    //printf("attribute namespace=%d  idx=%d  event=%p\n", id, idx, mEventCode);
+    //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id));
+    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+const int32_t ResXMLParser::getAttributeNameID(size_t idx) const
+{
+    if (mEventCode == START_TAG) {
+        const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
+        if (idx < dtohs(tag->attributeCount)) {
+            const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
+                (((const uint8_t*)tag)
+                 + dtohs(tag->attributeStart)
+                 + (dtohs(tag->attributeSize)*idx));
+            return dtohl(attr->name.index);
+        }
+    }
+    return -1;
+}
+
+const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const
+{
+    int32_t id = getAttributeNameID(idx);
+    //printf("attribute name=%d  idx=%d  event=%p\n", id, idx, mEventCode);
+    //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id));
+    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+const uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
+{
+    int32_t id = getAttributeNameID(idx);
+    if (id >= 0 && (size_t)id < mTree.mNumResIds) {
+        return dtohl(mTree.mResIds[id]);
+    }
+    return 0;
+}
+
+const int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
+{
+    if (mEventCode == START_TAG) {
+        const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
+        if (idx < dtohs(tag->attributeCount)) {
+            const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
+                (((const uint8_t*)tag)
+                 + dtohs(tag->attributeStart)
+                 + (dtohs(tag->attributeSize)*idx));
+            return dtohl(attr->rawValue.index);
+        }
+    }
+    return -1;
+}
+
+const uint16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const
+{
+    int32_t id = getAttributeValueStringID(idx);
+    //XML_NOISY(printf("getAttributeValue 0x%x=0x%x\n", idx, id));
+    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+int32_t ResXMLParser::getAttributeDataType(size_t idx) const
+{
+    if (mEventCode == START_TAG) {
+        const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
+        if (idx < dtohs(tag->attributeCount)) {
+            const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
+                (((const uint8_t*)tag)
+                 + dtohs(tag->attributeStart)
+                 + (dtohs(tag->attributeSize)*idx));
+            return attr->typedValue.dataType;
+        }
+    }
+    return Res_value::TYPE_NULL;
+}
+
+int32_t ResXMLParser::getAttributeData(size_t idx) const
+{
+    if (mEventCode == START_TAG) {
+        const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
+        if (idx < dtohs(tag->attributeCount)) {
+            const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
+                (((const uint8_t*)tag)
+                 + dtohs(tag->attributeStart)
+                 + (dtohs(tag->attributeSize)*idx));
+            return dtohl(attr->typedValue.data);
+        }
+    }
+    return 0;
+}
+
+ssize_t ResXMLParser::getAttributeValue(size_t idx, Res_value* outValue) const
+{
+    if (mEventCode == START_TAG) {
+        const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
+        if (idx < dtohs(tag->attributeCount)) {
+            const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
+                (((const uint8_t*)tag)
+                 + dtohs(tag->attributeStart)
+                 + (dtohs(tag->attributeSize)*idx));
+            outValue->copyFrom_dtoh(attr->typedValue);
+            return sizeof(Res_value);
+        }
+    }
+    return BAD_TYPE;
+}
+
+ssize_t ResXMLParser::indexOfAttribute(const char* ns, const char* attr) const
+{
+    String16 nsStr(ns != NULL ? ns : "");
+    String16 attrStr(attr);
+    return indexOfAttribute(ns ? nsStr.string() : NULL, ns ? nsStr.size() : 0,
+                            attrStr.string(), attrStr.size());
+}
+
+ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
+                                       const char16_t* attr, size_t attrLen) const
+{
+    if (mEventCode == START_TAG) {
+        const size_t N = getAttributeCount();
+        for (size_t i=0; i<N; i++) {
+            size_t curNsLen, curAttrLen;
+            const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
+            const char16_t* curAttr = getAttributeName(i, &curAttrLen);
+            //printf("%d: ns=%p attr=%p curNs=%p curAttr=%p\n",
+            //       i, ns, attr, curNs, curAttr);
+            //printf(" --> attr=%s, curAttr=%s\n",
+            //       String8(attr).string(), String8(curAttr).string());
+            if (attr && curAttr && (strzcmp16(attr, attrLen, curAttr, curAttrLen) == 0)) {
+                if (ns == NULL) {
+                    if (curNs == NULL) return i;
+                } else if (curNs != NULL) {
+                    //printf(" --> ns=%s, curNs=%s\n",
+                    //       String8(ns).string(), String8(curNs).string());
+                    if (strzcmp16(ns, nsLen, curNs, curNsLen) == 0) return i;
+                }
+            }
+        }
+    }
+
+    return NAME_NOT_FOUND;
+}
+
+ssize_t ResXMLParser::indexOfID() const
+{
+    if (mEventCode == START_TAG) {
+        const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->idIndex);
+        if (idx > 0) return (idx-1);
+    }
+    return NAME_NOT_FOUND;
+}
+
+ssize_t ResXMLParser::indexOfClass() const
+{
+    if (mEventCode == START_TAG) {
+        const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->classIndex);
+        if (idx > 0) return (idx-1);
+    }
+    return NAME_NOT_FOUND;
+}
+
+ssize_t ResXMLParser::indexOfStyle() const
+{
+    if (mEventCode == START_TAG) {
+        const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->styleIndex);
+        if (idx > 0) return (idx-1);
+    }
+    return NAME_NOT_FOUND;
+}
+
+ResXMLParser::event_code_t ResXMLParser::nextNode()
+{
+    if (mEventCode < 0) {
+        return mEventCode;
+    }
+
+    do {
+        const ResXMLTree_node* next = (const ResXMLTree_node*)
+            (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size));
+        //LOGW("Next node: prev=%p, next=%p\n", mCurNode, next);
+        
+        if (((const uint8_t*)next) >= mTree.mDataEnd) {
+            mCurNode = NULL;
+            return (mEventCode=END_DOCUMENT);
+        }
+
+        if (mTree.validateNode(next) != NO_ERROR) {
+            mCurNode = NULL;
+            return (mEventCode=BAD_DOCUMENT);
+        }
+
+        mCurNode = next;
+        const uint16_t headerSize = dtohs(next->header.headerSize);
+        const uint32_t totalSize = dtohl(next->header.size);
+        mCurExt = ((const uint8_t*)next) + headerSize;
+        size_t minExtSize = 0;
+        event_code_t eventCode = (event_code_t)dtohs(next->header.type);
+        switch ((mEventCode=eventCode)) {
+            case RES_XML_START_NAMESPACE_TYPE:
+            case RES_XML_END_NAMESPACE_TYPE:
+                minExtSize = sizeof(ResXMLTree_namespaceExt);
+                break;
+            case RES_XML_START_ELEMENT_TYPE:
+                minExtSize = sizeof(ResXMLTree_attrExt);
+                break;
+            case RES_XML_END_ELEMENT_TYPE:
+                minExtSize = sizeof(ResXMLTree_endElementExt);
+                break;
+            case RES_XML_CDATA_TYPE:
+                minExtSize = sizeof(ResXMLTree_cdataExt);
+                break;
+            default:
+                LOGW("Unknown XML block: header type %d in node at %d\n",
+                     (int)dtohs(next->header.type),
+                     (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)));
+                continue;
+        }
+        
+        if ((totalSize-headerSize) < minExtSize) {
+            LOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n",
+                 (int)dtohs(next->header.type),
+                 (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)),
+                 (int)(totalSize-headerSize), (int)minExtSize);
+            return (mEventCode=BAD_DOCUMENT);
+        }
+        
+        //printf("CurNode=%p, CurExt=%p, headerSize=%d, minExtSize=%d\n",
+        //       mCurNode, mCurExt, headerSize, minExtSize);
+        
+        return eventCode;
+    } while (true);
+}
+
+void ResXMLParser::getPosition(ResXMLParser::ResXMLPosition* pos) const
+{
+    pos->eventCode = mEventCode;
+    pos->curNode = mCurNode;
+    pos->curExt = mCurExt;
+}
+
+void ResXMLParser::setPosition(const ResXMLParser::ResXMLPosition& pos)
+{
+    mEventCode = pos.eventCode;
+    mCurNode = pos.curNode;
+    mCurExt = pos.curExt;
+}
+
+
+// --------------------------------------------------------------------
+
+static volatile int32_t gCount = 0;
+
+ResXMLTree::ResXMLTree()
+    : ResXMLParser(*this)
+    , mError(NO_INIT), mOwnedData(NULL)
+{
+    //LOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
+    restart();
+}
+
+ResXMLTree::ResXMLTree(const void* data, size_t size, bool copyData)
+    : ResXMLParser(*this)
+    , mError(NO_INIT), mOwnedData(NULL)
+{
+    //LOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
+    setTo(data, size, copyData);
+}
+
+ResXMLTree::~ResXMLTree()
+{
+    //LOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1);
+    uninit();
+}
+
+status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
+{
+    uninit();
+    mEventCode = START_DOCUMENT;
+
+    if (copyData) {
+        mOwnedData = malloc(size);
+        if (mOwnedData == NULL) {
+            return (mError=NO_MEMORY);
+        }
+        memcpy(mOwnedData, data, size);
+        data = mOwnedData;
+    }
+
+    mHeader = (const ResXMLTree_header*)data;
+    mSize = dtohl(mHeader->header.size);
+    if (dtohs(mHeader->header.headerSize) > mSize || mSize > size) {
+        LOGW("Bad XML block: header size %d or total size %d is larger than data size %d\n",
+             (int)dtohs(mHeader->header.headerSize),
+             (int)dtohl(mHeader->header.size), (int)size);
+        mError = BAD_TYPE;
+        restart();
+        return mError;
+    }
+    mDataEnd = ((const uint8_t*)mHeader) + mSize;
+
+    mStrings.uninit();
+    mRootNode = NULL;
+    mResIds = NULL;
+    mNumResIds = 0;
+
+    // First look for a couple interesting chunks: the string block
+    // and first XML node.
+    const ResChunk_header* chunk =
+        (const ResChunk_header*)(((const uint8_t*)mHeader) + dtohs(mHeader->header.headerSize));
+    const ResChunk_header* lastChunk = chunk;
+    while (((const uint8_t*)chunk) < (mDataEnd-sizeof(ResChunk_header)) &&
+           ((const uint8_t*)chunk) < (mDataEnd-dtohl(chunk->size))) {
+        status_t err = validate_chunk(chunk, sizeof(ResChunk_header), mDataEnd, "XML");
+        if (err != NO_ERROR) {
+            mError = err;
+            goto done;
+        }
+        const uint16_t type = dtohs(chunk->type);
+        const size_t size = dtohl(chunk->size);
+        XML_NOISY(printf("Scanning @ %p: type=0x%x, size=0x%x\n",
+                     (void*)(((uint32_t)chunk)-((uint32_t)mHeader)), type, size));
+        if (type == RES_STRING_POOL_TYPE) {
+            mStrings.setTo(chunk, size);
+        } else if (type == RES_XML_RESOURCE_MAP_TYPE) {
+            mResIds = (const uint32_t*)
+                (((const uint8_t*)chunk)+dtohs(chunk->headerSize));
+            mNumResIds = (dtohl(chunk->size)-dtohs(chunk->headerSize))/sizeof(uint32_t);
+        } else if (type >= RES_XML_FIRST_CHUNK_TYPE
+                   && type <= RES_XML_LAST_CHUNK_TYPE) {
+            if (validateNode((const ResXMLTree_node*)chunk) != NO_ERROR) {
+                mError = BAD_TYPE;
+                goto done;
+            }
+            mCurNode = (const ResXMLTree_node*)lastChunk;
+            if (nextNode() == BAD_DOCUMENT) {
+                mError = BAD_TYPE;
+                goto done;
+            }
+            mRootNode = mCurNode;
+            mRootExt = mCurExt;
+            mRootCode = mEventCode;
+            break;
+        } else {
+            XML_NOISY(printf("Skipping unknown chunk!\n"));
+        }
+        lastChunk = chunk;
+        chunk = (const ResChunk_header*)
+            (((const uint8_t*)chunk) + size);
+    }
+
+    if (mRootNode == NULL) {
+        LOGW("Bad XML block: no root element node found\n");
+        mError = BAD_TYPE;
+        goto done;
+    }
+
+    mError = mStrings.getError();
+
+done:
+    restart();
+    return mError;
+}
+
+status_t ResXMLTree::getError() const
+{
+    return mError;
+}
+
+void ResXMLTree::uninit()
+{
+    mError = NO_INIT;
+    if (mOwnedData) {
+        free(mOwnedData);
+        mOwnedData = NULL;
+    }
+    restart();
+}
+
+const ResStringPool& ResXMLTree::getStrings() const
+{
+    return mStrings;
+}
+
+status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const
+{
+    const uint16_t eventCode = dtohs(node->header.type);
+
+    status_t err = validate_chunk(
+        &node->header, sizeof(ResXMLTree_node),
+        mDataEnd, "ResXMLTree_node");
+
+    if (err >= NO_ERROR) {
+        // Only perform additional validation on START nodes
+        if (eventCode != RES_XML_START_ELEMENT_TYPE) {
+            return NO_ERROR;
+        }
+
+        const uint16_t headerSize = dtohs(node->header.headerSize);
+        const uint32_t size = dtohl(node->header.size);
+        const ResXMLTree_attrExt* attrExt = (const ResXMLTree_attrExt*)
+            (((const uint8_t*)node) + headerSize);
+        // check for sensical values pulled out of the stream so far...
+        if ((size >= headerSize + sizeof(ResXMLTree_attrExt))
+                && ((void*)attrExt > (void*)node)) {
+            const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize))
+                * dtohs(attrExt->attributeCount);
+            if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) {
+                return NO_ERROR;
+            }
+            LOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
+                    (unsigned int)(dtohs(attrExt->attributeStart)+attrSize),
+                    (unsigned int)(size-headerSize));
+        }
+        else {
+            LOGW("Bad XML start block: node header size 0x%x, size 0x%x\n",
+                (unsigned int)headerSize, (unsigned int)size);
+        }
+        return BAD_TYPE;
+    }
+
+    return err;
+
+#if 0
+    const bool isStart = dtohs(node->header.type) == RES_XML_START_ELEMENT_TYPE;
+
+    const uint16_t headerSize = dtohs(node->header.headerSize);
+    const uint32_t size = dtohl(node->header.size);
+
+    if (headerSize >= (isStart ? sizeof(ResXMLTree_attrNode) : sizeof(ResXMLTree_node))) {
+        if (size >= headerSize) {
+            if (((const uint8_t*)node) <= (mDataEnd-size)) {
+                if (!isStart) {
+                    return NO_ERROR;
+                }
+                if ((((size_t)dtohs(node->attributeSize))*dtohs(node->attributeCount))
+                        <= (size-headerSize)) {
+                    return NO_ERROR;
+                }
+                LOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
+                        ((int)dtohs(node->attributeSize))*dtohs(node->attributeCount),
+                        (int)(size-headerSize));
+                return BAD_TYPE;
+            }
+            LOGW("Bad XML block: node at 0x%x extends beyond data end 0x%x\n",
+                    (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), (int)mSize);
+            return BAD_TYPE;
+        }
+        LOGW("Bad XML block: node at 0x%x header size 0x%x smaller than total size 0x%x\n",
+                (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
+                (int)headerSize, (int)size);
+        return BAD_TYPE;
+    }
+    LOGW("Bad XML block: node at 0x%x header size 0x%x too small\n",
+            (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
+            (int)headerSize);
+    return BAD_TYPE;
+#endif
+}
+
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+
+struct ResTable::Header
+{
+    Header() : ownedData(NULL), header(NULL) { }
+
+    void*                           ownedData;
+    const ResTable_header*          header;
+    size_t                          size;
+    const uint8_t*                  dataEnd;
+    size_t                          index;
+    void*                           cookie;
+
+    ResStringPool                   values;
+};
+
+struct ResTable::Type
+{
+    Type(const Header* _header, const Package* _package, size_t count)
+        : header(_header), package(_package), entryCount(count),
+          typeSpec(NULL), typeSpecFlags(NULL) { }
+    const Header* const             header;
+    const Package* const            package;
+    const size_t                    entryCount;
+    const ResTable_typeSpec*        typeSpec;
+    const uint32_t*                 typeSpecFlags;
+    Vector<const ResTable_type*>    configs;
+};
+
+struct ResTable::Package
+{
+    Package(const Header* _header, const ResTable_package* _package)
+        : header(_header), package(_package) { }
+    ~Package()
+    {
+        size_t i = types.size();
+        while (i > 0) {
+            i--;
+            delete types[i];
+        }
+    }
+    
+    const Header* const             header;
+    const ResTable_package* const   package;
+    Vector<Type*>                   types;
+
+    const Type* getType(size_t idx) const {
+        return idx < types.size() ? types[idx] : NULL;
+    }
+};
+
+// A group of objects describing a particular resource package.
+// The first in 'package' is always the root object (from the resource
+// table that defined the package); the ones after are skins on top of it.
+struct ResTable::PackageGroup
+{
+    PackageGroup(const String16& _name, uint32_t _id)
+        : name(_name), id(_id), typeCount(0), bags(NULL) { }
+    ~PackageGroup() {
+        clearBagCache();
+        const size_t N = packages.size();
+        for (size_t i=0; i<N; i++) {
+            delete packages[i];
+        }
+    }
+
+    void clearBagCache() {
+        if (bags) {
+            TABLE_NOISY(printf("bags=%p\n", bags));
+            Package* pkg = packages[0];
+            TABLE_NOISY(printf("typeCount=%x\n", typeCount));
+            for (size_t i=0; i<typeCount; i++) {
+                TABLE_NOISY(printf("type=%d\n", i));
+                const Type* type = pkg->getType(i);
+                if (type != NULL) {
+                    bag_set** typeBags = bags[i];
+                    TABLE_NOISY(printf("typeBags=%p\n", typeBags));
+                    if (typeBags) {
+                        TABLE_NOISY(printf("type->entryCount=%x\n", type->entryCount));
+                        const size_t N = type->entryCount;
+                        for (size_t j=0; j<N; j++) {
+                            if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF)
+                                free(typeBags[j]);
+                        }
+                        free(typeBags);
+                    }
+                }
+            }
+            free(bags);
+            bags = NULL;
+        }
+    }
+    
+    String16 const                  name;
+    uint32_t const                  id;
+    Vector<Package*>                packages;
+
+    // Taken from the root package.
+    ResStringPool                   typeStrings;
+    ResStringPool                   keyStrings;
+    size_t                          typeCount;
+
+    // Computed attribute bags, first indexed by the type and second
+    // by the entry in that type.
+    bag_set***                      bags;
+};
+
+struct ResTable::bag_set
+{
+    size_t numAttrs;    // number in array
+    size_t availAttrs;  // total space in array
+    uint32_t typeSpecFlags;
+    // Followed by 'numAttr' bag_entry structures.
+};
+
+ResTable::Theme::Theme(const ResTable& table)
+    : mTable(table)
+{
+    memset(mPackages, 0, sizeof(mPackages));
+}
+
+ResTable::Theme::~Theme()
+{
+    for (size_t i=0; i<Res_MAXPACKAGE; i++) {
+        package_info* pi = mPackages[i];
+        if (pi != NULL) {
+            free_package(pi);
+        }
+    }
+}
+
+void ResTable::Theme::free_package(package_info* pi)
+{
+    for (size_t j=0; j<pi->numTypes; j++) {
+        theme_entry* te = pi->types[j].entries;
+        if (te != NULL) {
+            free(te);
+        }
+    }
+    free(pi);
+}
+
+ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi)
+{
+    package_info* newpi = (package_info*)malloc(
+        sizeof(package_info) + (pi->numTypes*sizeof(type_info)));
+    newpi->numTypes = pi->numTypes;
+    for (size_t j=0; j<newpi->numTypes; j++) {
+        size_t cnt = pi->types[j].numEntries;
+        newpi->types[j].numEntries = cnt;
+        theme_entry* te = pi->types[j].entries;
+        if (te != NULL) {
+            theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry));
+            newpi->types[j].entries = newte;
+            memcpy(newte, te, cnt*sizeof(theme_entry));
+        } else {
+            newpi->types[j].entries = NULL;
+        }
+    }
+    return newpi;
+}
+
+status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
+{
+    const bag_entry* bag;
+    uint32_t bagTypeSpecFlags = 0;
+    mTable.lock();
+    const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags);
+    TABLE_NOISY(LOGV("Applying style 0x%08x to theme %p, count=%d", resID, this, N));
+    if (N < 0) {
+        mTable.unlock();
+        return N;
+    }
+
+    uint32_t curPackage = 0xffffffff;
+    ssize_t curPackageIndex = 0;
+    package_info* curPI = NULL;
+    uint32_t curType = 0xffffffff;
+    size_t numEntries = 0;
+    theme_entry* curEntries = NULL;
+
+    const bag_entry* end = bag + N;
+    while (bag < end) {
+        const uint32_t attrRes = bag->map.name.ident;
+        const uint32_t p = Res_GETPACKAGE(attrRes);
+        const uint32_t t = Res_GETTYPE(attrRes);
+        const uint32_t e = Res_GETENTRY(attrRes);
+
+        if (curPackage != p) {
+            const ssize_t pidx = mTable.getResourcePackageIndex(attrRes);
+            if (pidx < 0) {
+                LOGE("Style contains key with bad package: 0x%08x\n", attrRes);
+                bag++;
+                continue;
+            }
+            curPackage = p;
+            curPackageIndex = pidx;
+            curPI = mPackages[pidx];
+            if (curPI == NULL) {
+                PackageGroup* const grp = mTable.mPackageGroups[pidx];
+                int cnt = grp->typeCount;
+                curPI = (package_info*)malloc(
+                    sizeof(package_info) + (cnt*sizeof(type_info)));
+                curPI->numTypes = cnt;
+                memset(curPI->types, 0, cnt*sizeof(type_info));
+                mPackages[pidx] = curPI;
+            }
+            curType = 0xffffffff;
+        }
+        if (curType != t) {
+            if (t >= curPI->numTypes) {
+                LOGE("Style contains key with bad type: 0x%08x\n", attrRes);
+                bag++;
+                continue;
+            }
+            curType = t;
+            curEntries = curPI->types[t].entries;
+            if (curEntries == NULL) {
+                PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex];
+                const Type* type = grp->packages[0]->getType(t);
+                int cnt = type != NULL ? type->entryCount : 0;
+                curEntries = (theme_entry*)malloc(cnt*sizeof(theme_entry));
+                memset(curEntries, Res_value::TYPE_NULL, cnt*sizeof(theme_entry));
+                curPI->types[t].numEntries = cnt;
+                curPI->types[t].entries = curEntries;
+            }
+            numEntries = curPI->types[t].numEntries;
+        }
+        if (e >= numEntries) {
+            LOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
+            bag++;
+            continue;
+        }
+        theme_entry* curEntry = curEntries + e;
+        TABLE_NOISY(LOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
+                   attrRes, bag->map.value.dataType, bag->map.value.data,
+             curEntry->value.dataType));
+        if (force || curEntry->value.dataType == Res_value::TYPE_NULL) {
+            curEntry->stringBlock = bag->stringBlock;
+            curEntry->typeSpecFlags |= bagTypeSpecFlags;
+            curEntry->value = bag->map.value;
+        }
+
+        bag++;
+    }
+
+    mTable.unlock();
+
+    //LOGI("Applying style 0x%08x (force=%d)  theme %p...\n", resID, force, this);
+    //dumpToLog();
+    
+    return NO_ERROR;
+}
+
+status_t ResTable::Theme::setTo(const Theme& other)
+{
+    //LOGI("Setting theme %p from theme %p...\n", this, &other);
+    //dumpToLog();
+    //other.dumpToLog();
+    
+    if (&mTable == &other.mTable) {
+        for (size_t i=0; i<Res_MAXPACKAGE; i++) {
+            if (mPackages[i] != NULL) {
+                free_package(mPackages[i]);
+            }
+            if (other.mPackages[i] != NULL) {
+                mPackages[i] = copy_package(other.mPackages[i]);
+            } else {
+                mPackages[i] = NULL;
+            }
+        }
+    } else {
+        // @todo: need to really implement this, not just copy
+        // the system package (which is still wrong because it isn't
+        // fixing up resource references).
+        for (size_t i=0; i<Res_MAXPACKAGE; i++) {
+            if (mPackages[i] != NULL) {
+                free_package(mPackages[i]);
+            }
+            if (i == 0 && other.mPackages[i] != NULL) {
+                mPackages[i] = copy_package(other.mPackages[i]);
+            } else {
+                mPackages[i] = NULL;
+            }
+        }
+    }
+
+    //LOGI("Final theme:");
+    //dumpToLog();
+    
+    return NO_ERROR;
+}
+
+ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue,
+        uint32_t* outTypeSpecFlags) const
+{
+    int cnt = 20;
+
+    if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0;
+    
+    do {
+        const ssize_t p = mTable.getResourcePackageIndex(resID);
+        const uint32_t t = Res_GETTYPE(resID);
+        const uint32_t e = Res_GETENTRY(resID);
+
+        TABLE_NOISY(LOGV("Looking up attr 0x%08x in theme %p", resID, this));
+
+        if (p >= 0) {
+            const package_info* const pi = mPackages[p];
+            if (pi != NULL) {
+                if (t < pi->numTypes) {
+                    const type_info& ti = pi->types[t];
+                    if (e < ti.numEntries) {
+                        const theme_entry& te = ti.entries[e];
+                            if (outTypeSpecFlags != NULL) {
+                                *outTypeSpecFlags |= te.typeSpecFlags;
+                            }
+                        const uint8_t type = te.value.dataType;
+                        if (type == Res_value::TYPE_ATTRIBUTE) {
+                            if (cnt > 0) {
+                                cnt--;
+                                resID = te.value.data;
+                                continue;
+                            }
+                            LOGW("Too many attribute references, stopped at: 0x%08x\n", resID);
+                            return BAD_INDEX;
+                        } else if (type != Res_value::TYPE_NULL) {
+                            *outValue = te.value;
+                            return te.stringBlock;
+                        }
+                        return BAD_INDEX;
+                    }
+                }
+            }
+        }
+        break;
+
+    } while (true);
+
+    return BAD_INDEX;
+}
+
+ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue,
+        ssize_t blockIndex, uint32_t* outLastRef,
+        uint32_t* inoutTypeSpecFlags) const
+{
+    //printf("Resolving type=0x%x\n", inOutValue->dataType);
+    if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) {
+        uint32_t newTypeSpecFlags;
+        blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags);
+        if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags;
+        //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType);
+        if (blockIndex < 0) {
+            return blockIndex;
+        }
+    }
+    return mTable.resolveReference(inOutValue, blockIndex, outLastRef);
+}
+
+void ResTable::Theme::dumpToLog() const
+{
+    LOGI("Theme %p:\n", this);
+    for (size_t i=0; i<Res_MAXPACKAGE; i++) {
+        package_info* pi = mPackages[i];
+        if (pi == NULL) continue;
+        
+        LOGI("  Package #0x%02x:\n", (int)(i+1));
+        for (size_t j=0; j<pi->numTypes; j++) {
+            type_info& ti = pi->types[j];
+            if (ti.numEntries == 0) continue;
+            
+            LOGI("    Type #0x%02x:\n", (int)(j+1));
+            for (size_t k=0; k<ti.numEntries; k++) {
+                theme_entry& te = ti.entries[k];
+                if (te.value.dataType == Res_value::TYPE_NULL) continue;
+                LOGI("      0x%08x: t=0x%x, d=0x%08x (block=%d)\n",
+                     (int)Res_MAKEID(i, j, k),
+                     te.value.dataType, (int)te.value.data, (int)te.stringBlock);
+            }
+        }
+    }
+}
+
+ResTable::ResTable()
+    : mError(NO_INIT)
+{
+    memset(&mParams, 0, sizeof(mParams));
+    memset(mPackageMap, 0, sizeof(mPackageMap));
+    //LOGI("Creating ResTable %p\n", this);
+}
+
+ResTable::ResTable(const void* data, size_t size, void* cookie, bool copyData)
+    : mError(NO_INIT)
+{
+    memset(&mParams, 0, sizeof(mParams));
+    memset(mPackageMap, 0, sizeof(mPackageMap));
+    add(data, size, cookie, copyData);
+    LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
+    //LOGI("Creating ResTable %p\n", this);
+}
+
+ResTable::~ResTable()
+{
+    //LOGI("Destroying ResTable in %p\n", this);
+    uninit();
+}
+
+inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
+{
+    return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
+}
+
+status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData)
+{
+    return add(data, size, cookie, NULL, copyData);
+}
+
+status_t ResTable::add(Asset* asset, void* cookie, bool copyData)
+{
+    const void* data = asset->getBuffer(true);
+    if (data == NULL) {
+        LOGW("Unable to get buffer of resource asset file");
+        return UNKNOWN_ERROR;
+    }
+    size_t size = (size_t)asset->getLength();
+    return add(data, size, cookie, asset, copyData);
+}
+
+status_t ResTable::add(const void* data, size_t size, void* cookie,
+                       Asset* asset, bool copyData)
+{
+    if (!data) return NO_ERROR;
+    Header* header = new Header;
+    header->index = mHeaders.size();
+    header->cookie = cookie;
+    mHeaders.add(header);
+
+    const bool notDeviceEndian = htods(0xf0) != 0xf0;
+
+    LOAD_TABLE_NOISY(
+        LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d\n",
+             data, size, cookie, asset, copyData));
+    
+    if (copyData || notDeviceEndian) {
+        header->ownedData = malloc(size);
+        if (header->ownedData == NULL) {
+            return (mError=NO_MEMORY);
+        }
+        memcpy(header->ownedData, data, size);
+        data = header->ownedData;
+    }
+
+    header->header = (const ResTable_header*)data;
+    header->size = dtohl(header->header->header.size);
+    //LOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header->size,
+    //     dtohl(header->header->header.size), header->header->header.size);
+    LOAD_TABLE_NOISY(LOGV("Loading ResTable @%p:\n", header->header));
+    LOAD_TABLE_NOISY(printHexData(2, header->header, header->size < 256 ? header->size : 256,
+                                  16, 16, 0, false, printToLogFunc));
+    if (dtohs(header->header->header.headerSize) > header->size
+            || header->size > size) {
+        LOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
+             (int)dtohs(header->header->header.headerSize),
+             (int)header->size, (int)size);
+        return (mError=BAD_TYPE);
+    }
+    if (((dtohs(header->header->header.headerSize)|header->size)&0x3) != 0) {
+        LOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n",
+             (int)dtohs(header->header->header.headerSize),
+             (int)header->size);
+        return (mError=BAD_TYPE);
+    }
+    header->dataEnd = ((const uint8_t*)header->header) + header->size;
+
+    // Iterate through all chunks.
+    size_t curPackage = 0;
+
+    const ResChunk_header* chunk =
+        (const ResChunk_header*)(((const uint8_t*)header->header)
+                                 + dtohs(header->header->header.headerSize));
+    while (((const uint8_t*)chunk) <= (header->dataEnd-sizeof(ResChunk_header)) &&
+           ((const uint8_t*)chunk) <= (header->dataEnd-dtohl(chunk->size))) {
+        status_t err = validate_chunk(chunk, sizeof(ResChunk_header), header->dataEnd, "ResTable");
+        if (err != NO_ERROR) {
+            return (mError=err);
+        }
+        TABLE_NOISY(LOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
+                     dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
+                     (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
+        const size_t csize = dtohl(chunk->size);
+        const uint16_t ctype = dtohs(chunk->type);
+        if (ctype == RES_STRING_POOL_TYPE) {
+            if (header->values.getError() != NO_ERROR) {
+                // Only use the first string chunk; ignore any others that
+                // may appear.
+                status_t err = header->values.setTo(chunk, csize);
+                if (err != NO_ERROR) {
+                    return (mError=err);
+                }
+            } else {
+                LOGW("Multiple string chunks found in resource table.");
+            }
+        } else if (ctype == RES_TABLE_PACKAGE_TYPE) {
+            if (curPackage >= dtohl(header->header->packageCount)) {
+                LOGW("More package chunks were found than the %d declared in the header.",
+                     dtohl(header->header->packageCount));
+                return (mError=BAD_TYPE);
+            }
+            if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
+                return mError;
+            }
+            curPackage++;
+        } else {
+            LOGW("Unknown chunk type %p in table at %p.\n",
+                 (void*)(int)(ctype),
+                 (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
+        }
+        chunk = (const ResChunk_header*)
+            (((const uint8_t*)chunk) + csize);
+    }
+
+    if (curPackage < dtohl(header->header->packageCount)) {
+        LOGW("Fewer package chunks (%d) were found than the %d declared in the header.",
+             (int)curPackage, dtohl(header->header->packageCount));
+        return (mError=BAD_TYPE);
+    }
+    mError = header->values.getError();
+    if (mError != NO_ERROR) {
+        LOGW("No string values found in resource table!");
+    }
+    TABLE_NOISY(LOGV("Returning from add with mError=%d\n", mError));
+    return mError;
+}
+
+status_t ResTable::getError() const
+{
+    return mError;
+}
+
+void ResTable::uninit()
+{
+    mError = NO_INIT;
+    size_t N = mPackageGroups.size();
+    for (size_t i=0; i<N; i++) {
+        PackageGroup* g = mPackageGroups[i];
+        delete g;
+    }
+    N = mHeaders.size();
+    for (size_t i=0; i<N; i++) {
+        Header* header = mHeaders[i];
+        if (header->ownedData) {
+            free(header->ownedData);
+        }
+        delete header;
+    }
+
+    mPackageGroups.clear();
+    mHeaders.clear();
+}
+
+bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const
+{
+    if (mError != NO_ERROR) {
+        return false;
+    }
+
+    const ssize_t p = getResourcePackageIndex(resID);
+    const int t = Res_GETTYPE(resID);
+    const int e = Res_GETENTRY(resID);
+
+    if (p < 0) {
+        LOGW("No package identifier when getting name for resource number 0x%08x", resID);
+        return false;
+    }
+    if (t < 0) {
+        LOGW("No type identifier when getting name for resource number 0x%08x", resID);
+        return false;
+    }
+
+    const PackageGroup* const grp = mPackageGroups[p];
+    if (grp == NULL) {
+        LOGW("Bad identifier when getting name for resource number 0x%08x", resID);
+        return false;
+    }
+    if (grp->packages.size() > 0) {
+        const Package* const package = grp->packages[0];
+
+        const ResTable_type* type;
+        const ResTable_entry* entry;
+        ssize_t offset = getEntry(package, t, e, NULL, &type, &entry, NULL);
+        if (offset <= 0) {
+            return false;
+        }
+
+        outName->package = grp->name.string();
+        outName->packageLen = grp->name.size();
+        outName->type = grp->typeStrings.stringAt(t, &outName->typeLen);
+        outName->name = grp->keyStrings.stringAt(
+            dtohl(entry->key.index), &outName->nameLen);
+        return true;
+    }
+
+    return false;
+}
+
+ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag,
+        uint32_t* outSpecFlags, ResTable_config* outConfig) const
+{
+    if (mError != NO_ERROR) {
+        return mError;
+    }
+
+    const ssize_t p = getResourcePackageIndex(resID);
+    const int t = Res_GETTYPE(resID);
+    const int e = Res_GETENTRY(resID);
+
+    if (p < 0) {
+        LOGW("No package identifier when getting value for resource number 0x%08x", resID);
+        return BAD_INDEX;
+    }
+    if (t < 0) {
+        LOGW("No type identifier when getting value for resource number 0x%08x", resID);
+        return BAD_INDEX;
+    }
+
+    const Res_value* bestValue = NULL;
+    const Package* bestPackage = NULL;
+    ResTable_config bestItem;
+    memset(&bestItem, 0, sizeof(bestItem)); // make the compiler shut up
+
+    if (outSpecFlags != NULL) *outSpecFlags = 0;
+    
+    // Look through all resource packages, starting with the most
+    // recently added.
+    const PackageGroup* const grp = mPackageGroups[p];
+    if (grp == NULL) {
+        LOGW("Bad identifier when getting value for resource number 0x%08x", resID);
+        return false;
+    }
+    size_t ip = grp->packages.size();
+    while (ip > 0) {
+        ip--;
+
+        const Package* const package = grp->packages[ip];
+
+        const ResTable_type* type;
+        const ResTable_entry* entry;
+        const Type* typeClass;
+        ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
+        if (offset <= 0) {
+            if (offset < 0) {
+                LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %d: 0x%08x\n",
+                        resID, t, e, (int)ip, (int)offset);
+                return offset;
+            }
+            continue;
+        }
+
+        if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) != 0) {
+            if (!mayBeBag) {
+                LOGW("Requesting resource %p failed because it is complex\n",
+                     (void*)resID);
+            }
+            continue;
+        }
+
+        TABLE_NOISY(aout << "Resource type data: "
+              << HexDump(type, dtohl(type->header.size)) << endl);
+        
+        if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) {
+            LOGW("ResTable_item at %d is beyond type chunk data %d",
+                 (int)offset, dtohl(type->header.size));
+            return BAD_TYPE;
+        }
+        
+        const Res_value* item =
+            (const Res_value*)(((const uint8_t*)type) + offset);
+        ResTable_config thisConfig;
+        thisConfig.copyFromDtoH(type->config);
+
+        if (outSpecFlags != NULL) {
+            if (typeClass->typeSpecFlags != NULL) {
+                *outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
+            } else {
+                *outSpecFlags = -1;
+            }
+        }
+        
+        if (bestPackage != NULL && bestItem.isBetterThan(thisConfig)) {
+            continue;
+        }
+        
+        bestItem = thisConfig;
+        bestValue = item;
+        bestPackage = package;
+    }
+
+    TABLE_NOISY(printf("Found result: package %p\n", bestPackage));
+
+    if (bestValue) {
+        outValue->size = dtohs(bestValue->size);
+        outValue->res0 = bestValue->res0;
+        outValue->dataType = bestValue->dataType;
+        outValue->data = dtohl(bestValue->data);
+        if (outConfig != NULL) {
+            *outConfig = bestItem;
+        }
+        TABLE_NOISY(size_t len;
+              printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n",
+                     bestPackage->header->index,
+                     outValue->dataType,
+                     outValue->dataType == bestValue->TYPE_STRING
+                     ? String8(bestPackage->header->values.stringAt(
+                         outValue->data, &len)).string()
+                     : "",
+                     outValue->data));
+        return bestPackage->header->index;
+    }
+
+    return BAD_INDEX;
+}
+
+ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
+        uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags) const
+{
+    int count=0;
+    while (blockIndex >= 0 && value->dataType == value->TYPE_REFERENCE
+           && value->data != 0 && count < 20) {
+        if (outLastRef) *outLastRef = value->data;
+        uint32_t lastRef = value->data;
+        uint32_t newFlags = 0;
+        const ssize_t newIndex = getResource(value->data, value, true, &newFlags);
+        //LOGI("Resolving reference d=%p: newIndex=%d, t=0x%02x, d=%p\n",
+        //     (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data);
+        //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
+        if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags;
+        if (newIndex < 0) {
+            // This can fail if the resource being referenced is a style...
+            // in this case, just return the reference, and expect the
+            // caller to deal with.
+            return blockIndex;
+        }
+        blockIndex = newIndex;
+        count++;
+    }
+    return blockIndex;
+}
+
+const char16_t* ResTable::valueToString(
+    const Res_value* value, size_t stringBlock,
+    char16_t tmpBuffer[TMP_BUFFER_SIZE], size_t* outLen)
+{
+    if (!value) {
+        return NULL;
+    }
+    if (value->dataType == value->TYPE_STRING) {
+        return getTableStringBlock(stringBlock)->stringAt(value->data, outLen);
+    }
+    // XXX do int to string conversions.
+    return NULL;
+}
+
+ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const
+{
+    mLock.lock();
+    ssize_t err = getBagLocked(resID, outBag);
+    if (err < NO_ERROR) {
+        //printf("*** get failed!  unlocking\n");
+        mLock.unlock();
+    }
+    return err;
+}
+
+void ResTable::unlockBag(const bag_entry* bag) const
+{
+    //printf("<<< unlockBag %p\n", this);
+    mLock.unlock();
+}
+
+void ResTable::lock() const
+{
+    mLock.lock();
+}
+
+void ResTable::unlock() const
+{
+    mLock.unlock();
+}
+
+ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
+        uint32_t* outTypeSpecFlags) const
+{
+    if (mError != NO_ERROR) {
+        return mError;
+    }
+
+    const ssize_t p = getResourcePackageIndex(resID);
+    const int t = Res_GETTYPE(resID);
+    const int e = Res_GETENTRY(resID);
+
+    if (p < 0) {
+        LOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID);
+        return BAD_INDEX;
+    }
+    if (t < 0) {
+        LOGW("No type identifier when getting bag for resource number 0x%08x", resID);
+        return BAD_INDEX;
+    }
+
+    //printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t);
+    PackageGroup* const grp = mPackageGroups[p];
+    if (grp == NULL) {
+        LOGW("Bad identifier when getting bag for resource number 0x%08x", resID);
+        return false;
+    }
+
+    if (t >= (int)grp->typeCount) {
+        LOGW("Type identifier 0x%x is larger than type count 0x%x",
+             t+1, (int)grp->typeCount);
+        return BAD_INDEX;
+    }
+
+    const Package* const basePackage = grp->packages[0];
+
+    const Type* const typeConfigs = basePackage->getType(t);
+
+    const size_t NENTRY = typeConfigs->entryCount;
+    if (e >= (int)NENTRY) {
+        LOGW("Entry identifier 0x%x is larger than entry count 0x%x",
+             e, (int)typeConfigs->entryCount);
+        return BAD_INDEX;
+    }
+
+    // First see if we've already computed this bag...
+    if (grp->bags) {
+        bag_set** typeSet = grp->bags[t];
+        if (typeSet) {
+            bag_set* set = typeSet[e];
+            if (set) {
+                if (set != (bag_set*)0xFFFFFFFF) {
+                    if (outTypeSpecFlags != NULL) {
+                        *outTypeSpecFlags = set->typeSpecFlags;
+                    }
+                    *outBag = (bag_entry*)(set+1);
+                    //LOGI("Found existing bag for: %p\n", (void*)resID);
+                    return set->numAttrs;
+                }
+                LOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
+                     resID);
+                return BAD_INDEX;
+            }
+        }
+    }
+
+    // Bag not found, we need to compute it!
+    if (!grp->bags) {
+        grp->bags = (bag_set***)malloc(sizeof(bag_set*)*grp->typeCount);
+        if (!grp->bags) return NO_MEMORY;
+        memset(grp->bags, 0, sizeof(bag_set*)*grp->typeCount);
+    }
+
+    bag_set** typeSet = grp->bags[t];
+    if (!typeSet) {
+        typeSet = (bag_set**)malloc(sizeof(bag_set*)*NENTRY);
+        if (!typeSet) return NO_MEMORY;
+        memset(typeSet, 0, sizeof(bag_set*)*NENTRY);
+        grp->bags[t] = typeSet;
+    }
+
+    // Mark that we are currently working on this one.
+    typeSet[e] = (bag_set*)0xFFFFFFFF;
+
+    // This is what we are building.
+    bag_set* set = NULL;
+
+    TABLE_NOISY(LOGI("Building bag: %p\n", (void*)resID));
+    
+    // Now collect all bag attributes from all packages.
+    size_t ip = grp->packages.size();
+    while (ip > 0) {
+        ip--;
+
+        const Package* const package = grp->packages[ip];
+
+        const ResTable_type* type;
+        const ResTable_entry* entry;
+        const Type* typeClass;
+        LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, t, e);
+        ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
+        LOGV("Resulting offset=%d\n", offset);
+        if (offset <= 0) {
+            if (offset < 0) {
+                if (set) free(set);
+                return offset;
+            }
+            continue;
+        }
+
+        if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) == 0) {
+            LOGW("Skipping entry %p in package table %d because it is not complex!\n",
+                 (void*)resID, (int)ip);
+            continue;
+        }
+
+        const uint16_t entrySize = dtohs(entry->size);
+        const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
+            ? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0;
+        const uint32_t count = entrySize >= sizeof(ResTable_map_entry)
+            ? dtohl(((const ResTable_map_entry*)entry)->count) : 0;
+        
+        size_t N = count;
+
+        TABLE_NOISY(LOGI("Found map: size=%p parent=%p count=%d\n",
+                         entrySize, parent, count));
+
+        if (set == NULL) {
+            // If this map inherits from another, we need to start
+            // with its parent's values.  Otherwise start out empty.
+            TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
+                         entrySize, parent));
+            if (parent) {
+                const bag_entry* parentBag;
+                uint32_t parentTypeSpecFlags = 0;
+                const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
+                const size_t NT = ((NP >= 0) ? NP : 0) + N;
+                set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
+                if (set == NULL) {
+                    return NO_MEMORY;
+                }
+                if (NP > 0) {
+                    memcpy(set+1, parentBag, NP*sizeof(bag_entry));
+                    set->numAttrs = NP;
+                    TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));
+                } else {
+                    TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));
+                    set->numAttrs = 0;
+                }
+                set->availAttrs = NT;
+                set->typeSpecFlags = parentTypeSpecFlags;
+            } else {
+                set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
+                if (set == NULL) {
+                    return NO_MEMORY;
+                }
+                set->numAttrs = 0;
+                set->availAttrs = N;
+                set->typeSpecFlags = 0;
+            }
+        }
+
+        if (typeClass->typeSpecFlags != NULL) {
+            set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
+        } else {
+            set->typeSpecFlags = -1;
+        }
+        
+        // Now merge in the new attributes...
+        ssize_t curOff = offset;
+        const ResTable_map* map;
+        bag_entry* entries = (bag_entry*)(set+1);
+        size_t curEntry = 0;
+        uint32_t pos = 0;
+        TABLE_NOISY(LOGI("Starting with set %p, entries=%p, avail=%d\n",
+                     set, entries, set->availAttrs));
+        while (pos < count) {
+            TABLE_NOISY(printf("Now at %p\n", (void*)curOff));
+
+            if ((size_t)curOff > (dtohl(type->header.size)-sizeof(ResTable_map))) {
+                LOGW("ResTable_map at %d is beyond type chunk data %d",
+                     (int)curOff, dtohl(type->header.size));
+                return BAD_TYPE;
+            }
+            map = (const ResTable_map*)(((const uint8_t*)type) + curOff);
+            N++;
+
+            const uint32_t newName = htodl(map->name.ident);
+            bool isInside;
+            uint32_t oldName = 0;
+            while ((isInside=(curEntry < set->numAttrs))
+                    && (oldName=entries[curEntry].map.name.ident) < newName) {
+                TABLE_NOISY(printf("#%d: Keeping existing attribute: 0x%08x\n",
+                             curEntry, entries[curEntry].map.name.ident));
+                curEntry++;
+            }
+
+            if ((!isInside) || oldName != newName) {
+                // This is a new attribute...  figure out what to do with it.
+                if (set->numAttrs >= set->availAttrs) {
+                    // Need to alloc more memory...
+                    const size_t newAvail = set->availAttrs+N;
+                    set = (bag_set*)realloc(set,
+                                            sizeof(bag_set)
+                                            + sizeof(bag_entry)*newAvail);
+                    if (set == NULL) {
+                        return NO_MEMORY;
+                    }
+                    set->availAttrs = newAvail;
+                    entries = (bag_entry*)(set+1);
+                    TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n",
+                                 set, entries, set->availAttrs));
+                }
+                if (isInside) {
+                    // Going in the middle, need to make space.
+                    memmove(entries+curEntry+1, entries+curEntry,
+                            sizeof(bag_entry)*(set->numAttrs-curEntry));
+                    set->numAttrs++;
+                }
+                TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n",
+                             curEntry, newName));
+            } else {
+                TABLE_NOISY(printf("#%d: Replacing existing attribute: 0x%08x\n",
+                             curEntry, oldName));
+            }
+
+            bag_entry* cur = entries+curEntry;
+
+            cur->stringBlock = package->header->index;
+            cur->map.name.ident = newName;
+            cur->map.value.copyFrom_dtoh(map->value);
+            TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n",
+                         curEntry, cur, cur->stringBlock, cur->map.name.ident,
+                         cur->map.value.dataType, cur->map.value.data));
+
+            // On to the next!
+            curEntry++;
+            pos++;
+            const size_t size = dtohs(map->value.size);
+            curOff += size + sizeof(*map)-sizeof(map->value);
+        };
+        if (curEntry > set->numAttrs) {
+            set->numAttrs = curEntry;
+        }
+    }
+
+    // And this is it...
+    typeSet[e] = set;
+    if (set) {
+        if (outTypeSpecFlags != NULL) {
+            *outTypeSpecFlags = set->typeSpecFlags;
+        }
+        *outBag = (bag_entry*)(set+1);
+        TABLE_NOISY(LOGI("Returning %d attrs\n", set->numAttrs));
+        return set->numAttrs;
+    }
+    return BAD_INDEX;
+}
+
+void ResTable::setParameters(const ResTable_config* params)
+{
+    mLock.lock();
+    TABLE_GETENTRY(LOGI("Setting parameters: imsi:%d/%d lang:%c%c cnt:%c%c "
+                        "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n",
+                       params->mcc, params->mnc,
+                       params->language[0] ? params->language[0] : '-',
+                       params->language[1] ? params->language[1] : '-',
+                       params->country[0] ? params->country[0] : '-',
+                       params->country[1] ? params->country[1] : '-',
+                       params->orientation,
+                       params->touchscreen,
+                       params->density,
+                       params->keyboard,
+                       params->inputFlags,
+                       params->navigation,
+                       params->screenWidth,
+                       params->screenHeight));
+    mParams = *params;
+    for (size_t i=0; i<mPackageGroups.size(); i++) {
+        TABLE_NOISY(LOGI("CLEARING BAGS FOR GROUP %d!", i));
+        mPackageGroups[i]->clearBagCache();
+    }
+    mLock.unlock();
+}
+
+void ResTable::getParameters(ResTable_config* params) const
+{
+    mLock.lock();
+    *params = mParams;
+    mLock.unlock();
+}
+
+struct id_name_map {
+    uint32_t id;
+    size_t len;
+    char16_t name[6];
+};
+
+const static id_name_map ID_NAMES[] = {
+    { ResTable_map::ATTR_TYPE,  5, { '^', 't', 'y', 'p', 'e' } },
+    { ResTable_map::ATTR_L10N,  5, { '^', 'l', '1', '0', 'n' } },
+    { ResTable_map::ATTR_MIN,   4, { '^', 'm', 'i', 'n' } },
+    { ResTable_map::ATTR_MAX,   4, { '^', 'm', 'a', 'x' } },
+    { ResTable_map::ATTR_OTHER, 6, { '^', 'o', 't', 'h', 'e', 'r' } },
+    { ResTable_map::ATTR_ZERO,  5, { '^', 'z', 'e', 'r', 'o' } },
+    { ResTable_map::ATTR_ONE,   4, { '^', 'o', 'n', 'e' } },
+    { ResTable_map::ATTR_TWO,   4, { '^', 't', 'w', 'o' } },
+    { ResTable_map::ATTR_FEW,   4, { '^', 'f', 'e', 'w' } },
+    { ResTable_map::ATTR_MANY,  5, { '^', 'm', 'a', 'n', 'y' } },
+};
+
+uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen,
+                                     const char16_t* type, size_t typeLen,
+                                     const char16_t* package,
+                                     size_t packageLen,
+                                     uint32_t* outTypeSpecFlags) const
+{
+    TABLE_SUPER_NOISY(printf("Identifier for name: error=%d\n", mError));
+
+    // Check for internal resource identifier as the very first thing, so
+    // that we will always find them even when there are no resources.
+    if (name[0] == '^') {
+        const int N = (sizeof(ID_NAMES)/sizeof(ID_NAMES[0]));
+        size_t len;
+        for (int i=0; i<N; i++) {
+            const id_name_map* m = ID_NAMES + i;
+            len = m->len;
+            if (len != nameLen) {
+                continue;
+            }
+            for (size_t j=1; j<len; j++) {
+                if (m->name[j] != name[j]) {
+                    goto nope;
+                }
+            }
+            return m->id;
+nope:
+            ;
+        }
+        if (nameLen > 7) {
+            if (name[1] == 'i' && name[2] == 'n'
+                && name[3] == 'd' && name[4] == 'e' && name[5] == 'x'
+                && name[6] == '_') {
+                int index = atoi(String8(name + 7, nameLen - 7).string());
+                if (Res_CHECKID(index)) {
+                    LOGW("Array resource index: %d is too large.",
+                         index);
+                    return 0;
+                }
+                return  Res_MAKEARRAY(index);
+            }
+        }
+        return 0;
+    }
+
+    if (mError != NO_ERROR) {
+        return 0;
+    }
+
+    // Figure out the package and type we are looking in...
+
+    const char16_t* packageEnd = NULL;
+    const char16_t* typeEnd = NULL;
+    const char16_t* const nameEnd = name+nameLen;
+    const char16_t* p = name;
+    while (p < nameEnd) {
+        if (*p == ':') packageEnd = p;
+        else if (*p == '/') typeEnd = p;
+        p++;
+    }
+    if (*name == '@') name++;
+    if (name >= nameEnd) {
+        return 0;
+    }
+
+    if (packageEnd) {
+        package = name;
+        packageLen = packageEnd-name;
+        name = packageEnd+1;
+    } else if (!package) {
+        return 0;
+    }
+
+    if (typeEnd) {
+        type = name;
+        typeLen = typeEnd-name;
+        name = typeEnd+1;
+    } else if (!type) {
+        return 0;
+    }
+
+    if (name >= nameEnd) {
+        return 0;
+    }
+    nameLen = nameEnd-name;
+
+    TABLE_NOISY(printf("Looking for identifier: type=%s, name=%s, package=%s\n",
+                 String8(type, typeLen).string(),
+                 String8(name, nameLen).string(),
+                 String8(package, packageLen).string()));
+
+    const size_t NG = mPackageGroups.size();
+    for (size_t ig=0; ig<NG; ig++) {
+        const PackageGroup* group = mPackageGroups[ig];
+
+        if (strzcmp16(package, packageLen,
+                      group->name.string(), group->name.size())) {
+            TABLE_NOISY(printf("Skipping package group: %s\n", String8(group->name).string()));
+            continue;
+        }
+
+        const ssize_t ti = group->typeStrings.indexOfString(type, typeLen);
+        if (ti < 0) {
+            TABLE_NOISY(printf("Type not found in package %s\n", String8(group->name).string()));
+            continue;
+        }
+
+        const ssize_t ei = group->keyStrings.indexOfString(name, nameLen);
+        if (ei < 0) {
+            TABLE_NOISY(printf("Name not found in package %s\n", String8(group->name).string()));
+            continue;
+        }
+
+        TABLE_NOISY(printf("Search indices: type=%d, name=%d\n", ti, ei));
+
+        const Type* const typeConfigs = group->packages[0]->getType(ti);
+        if (typeConfigs == NULL || typeConfigs->configs.size() <= 0) {
+            TABLE_NOISY(printf("Expected type structure not found in package %s for idnex %d\n",
+                               String8(group->name).string(), ti));
+        }
+        
+        size_t NTC = typeConfigs->configs.size();
+        for (size_t tci=0; tci<NTC; tci++) {
+            const ResTable_type* const ty = typeConfigs->configs[tci];
+            const uint32_t typeOffset = dtohl(ty->entriesStart);
+
+            const uint8_t* const end = ((const uint8_t*)ty) + dtohl(ty->header.size);
+            const uint32_t* const eindex = (const uint32_t*)
+                (((const uint8_t*)ty) + dtohs(ty->header.headerSize));
+
+            const size_t NE = dtohl(ty->entryCount);
+            for (size_t i=0; i<NE; i++) {
+                uint32_t offset = dtohl(eindex[i]);
+                if (offset == ResTable_type::NO_ENTRY) {
+                    continue;
+                }
+                
+                offset += typeOffset;
+                
+                if (offset > (dtohl(ty->header.size)-sizeof(ResTable_entry))) {
+                    LOGW("ResTable_entry at %d is beyond type chunk data %d",
+                         offset, dtohl(ty->header.size));
+                    return 0;
+                }
+                if ((offset&0x3) != 0) {
+                    LOGW("ResTable_entry at %d (pkg=%d type=%d ent=%d) is not on an integer boundary when looking for %s:%s/%s",
+                         (int)offset, (int)group->id, (int)ti+1, (int)i,
+                         String8(package, packageLen).string(),
+                         String8(type, typeLen).string(),
+                         String8(name, nameLen).string());
+                    return 0;
+                }
+                
+                const ResTable_entry* const entry = (const ResTable_entry*)
+                    (((const uint8_t*)ty) + offset);
+                if (dtohs(entry->size) < sizeof(*entry)) {
+                    LOGW("ResTable_entry size %d is too small", dtohs(entry->size));
+                    return BAD_TYPE;
+                }
+
+                TABLE_SUPER_NOISY(printf("Looking at entry #%d: want str %d, have %d\n",
+                                         i, ei, dtohl(entry->key.index)));
+                if (dtohl(entry->key.index) == (size_t)ei) {
+                    if (outTypeSpecFlags) {
+                        *outTypeSpecFlags = typeConfigs->typeSpecFlags[i];
+                    }
+                    return Res_MAKEID(group->id-1, ti, i);
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+bool ResTable::expandResourceRef(const uint16_t* refStr, size_t refLen,
+                                 String16* outPackage,
+                                 String16* outType,
+                                 String16* outName,
+                                 const String16* defType,
+                                 const String16* defPackage,
+                                 const char** outErrorMsg)
+{
+    const char16_t* packageEnd = NULL;
+    const char16_t* typeEnd = NULL;
+    const char16_t* p = refStr;
+    const char16_t* const end = p + refLen;
+    while (p < end) {
+        if (*p == ':') packageEnd = p;
+        else if (*p == '/') {
+            typeEnd = p;
+            break;
+        }
+        p++;
+    }
+    p = refStr;
+    if (*p == '@') p++;
+
+    if (packageEnd) {
+        *outPackage = String16(p, packageEnd-p);
+        p = packageEnd+1;
+    } else {
+        if (!defPackage) {
+            if (outErrorMsg) {
+                *outErrorMsg = "No resource package specified";
+            }
+            return false;
+        }
+        *outPackage = *defPackage;
+    }
+    if (typeEnd) {
+        *outType = String16(p, typeEnd-p);
+        p = typeEnd+1;
+    } else {
+        if (!defType) {
+            if (outErrorMsg) {
+                *outErrorMsg = "No resource type specified";
+            }
+            return false;
+        }
+        *outType = *defType;
+    }
+    *outName = String16(p, end-p);
+    return true;
+}
+
+static uint32_t get_hex(char c, bool* outError)
+{
+    if (c >= '0' && c <= '9') {
+        return c - '0';
+    } else if (c >= 'a' && c <= 'f') {
+        return c - 'a' + 0xa;
+    } else if (c >= 'A' && c <= 'F') {
+        return c - 'A' + 0xa;
+    }
+    *outError = true;
+    return 0;
+}
+
+struct unit_entry
+{
+    const char* name;
+    size_t len;
+    uint8_t type;
+    uint32_t unit;
+    float scale;
+};
+
+static const unit_entry unitNames[] = {
+    { "px", strlen("px"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PX, 1.0f },
+    { "dip", strlen("dip"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
+    { "dp", strlen("dp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
+    { "sp", strlen("sp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_SP, 1.0f },
+    { "pt", strlen("pt"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PT, 1.0f },
+    { "in", strlen("in"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_IN, 1.0f },
+    { "mm", strlen("mm"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_MM, 1.0f },
+    { "%", strlen("%"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION, 1.0f/100 },
+    { "%p", strlen("%p"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100 },
+    { NULL, 0, 0, 0, 0 }
+};
+
+static bool parse_unit(const char* str, Res_value* outValue,
+                       float* outScale, const char** outEnd)
+{
+    const char* end = str;
+    while (*end != 0 && !isspace((unsigned char)*end)) {
+        end++;
+    }
+    const size_t len = end-str;
+
+    const char* realEnd = end;
+    while (*realEnd != 0 && isspace((unsigned char)*realEnd)) {
+        realEnd++;
+    }
+    if (*realEnd != 0) {
+        return false;
+    }
+    
+    const unit_entry* cur = unitNames;
+    while (cur->name) {
+        if (len == cur->len && strncmp(cur->name, str, len) == 0) {
+            outValue->dataType = cur->type;
+            outValue->data = cur->unit << Res_value::COMPLEX_UNIT_SHIFT;
+            *outScale = cur->scale;
+            *outEnd = end;
+            //printf("Found unit %s for %s\n", cur->name, str);
+            return true;
+        }
+        cur++;
+    }
+
+    return false;
+}
+
+
+bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
+{
+    while (len > 0 && isspace16(*s)) {
+        s++;
+        len--;
+    }
+
+    if (len <= 0) {
+        return false;
+    }
+
+    size_t i = 0;
+    int32_t val = 0;
+    bool neg = false;
+
+    if (*s == '-') {
+        neg = true;
+        i++;
+    }
+
+    if (s[i] < '0' || s[i] > '9') {
+        return false;
+    }
+
+    // Decimal or hex?
+    if (s[i] == '0' && s[i+1] == 'x') {
+        if (outValue)
+            outValue->dataType = outValue->TYPE_INT_HEX;
+        i += 2;
+        bool error = false;
+        while (i < len && !error) {
+            val = (val*16) + get_hex(s[i], &error);
+            i++;
+        }
+        if (error) {
+            return false;
+        }
+    } else {
+        if (outValue)
+            outValue->dataType = outValue->TYPE_INT_DEC;
+        while (i < len) {
+            if (s[i] < '0' || s[i] > '9') {
+                return false;
+            }
+            val = (val*10) + s[i]-'0';
+            i++;
+        }
+    }
+
+    if (neg) val = -val;
+
+    while (i < len && isspace16(s[i])) {
+        i++;
+    }
+
+    if (i == len) {
+        if (outValue)
+            outValue->data = val;
+        return true;
+    }
+
+    return false;
+}
+
+bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
+{
+    while (len > 0 && isspace16(*s)) {
+        s++;
+        len--;
+    }
+
+    if (len <= 0) {
+        return false;
+    }
+
+    char buf[128];
+    int i=0;
+    while (len > 0 && *s != 0 && i < 126) {
+        if (*s > 255) {
+            return false;
+        }
+        buf[i++] = *s++;
+        len--;
+    }
+
+    if (len > 0) {
+        return false;
+    }
+    if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
+        return false;
+    }
+
+    buf[i] = 0;
+    const char* end;
+    float f = strtof(buf, (char**)&end);
+
+    if (*end != 0 && !isspace((unsigned char)*end)) {
+        // Might be a unit...
+        float scale;
+        if (parse_unit(end, outValue, &scale, &end)) {
+            f *= scale;
+            const bool neg = f < 0;
+            if (neg) f = -f;
+            uint64_t bits = (uint64_t)(f*(1<<23)+.5f);
+            uint32_t radix;
+            uint32_t shift;
+            if ((bits&0x7fffff) == 0) {
+                // Always use 23p0 if there is no fraction, just to make
+                // things easier to read.
+                radix = Res_value::COMPLEX_RADIX_23p0;
+                shift = 23;
+            } else if ((bits&0xffffffffff800000LL) == 0) {
+                // Magnitude is zero -- can fit in 0 bits of precision.
+                radix = Res_value::COMPLEX_RADIX_0p23;
+                shift = 0;
+            } else if ((bits&0xffffffff80000000LL) == 0) {
+                // Magnitude can fit in 8 bits of precision.
+                radix = Res_value::COMPLEX_RADIX_8p15;
+                shift = 8;
+            } else if ((bits&0xffffff8000000000LL) == 0) {
+                // Magnitude can fit in 16 bits of precision.
+                radix = Res_value::COMPLEX_RADIX_16p7;
+                shift = 16;
+            } else {
+                // Magnitude needs entire range, so no fractional part.
+                radix = Res_value::COMPLEX_RADIX_23p0;
+                shift = 23;
+            }
+            int32_t mantissa = (int32_t)(
+                (bits>>shift) & Res_value::COMPLEX_MANTISSA_MASK);
+            if (neg) {
+                mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK;
+            }
+            outValue->data |= 
+                (radix<<Res_value::COMPLEX_RADIX_SHIFT)
+                | (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT);
+            //printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n",
+            //       f * (neg ? -1 : 1), bits, f*(1<<23),
+            //       radix, shift, outValue->data);
+            return true;
+        }
+        return false;
+    }
+
+    while (*end != 0 && isspace((unsigned char)*end)) {
+        end++;
+    }
+
+    if (*end == 0) {
+        if (outValue) {
+            outValue->dataType = outValue->TYPE_FLOAT;
+            *(float*)(&outValue->data) = f;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool ResTable::stringToValue(Res_value* outValue, String16* outString,
+                             const char16_t* s, size_t len,
+                             bool preserveSpaces, bool coerceType,
+                             uint32_t attrID,
+                             const String16* defType,
+                             const String16* defPackage,
+                             Accessor* accessor,
+                             void* accessorCookie,
+                             uint32_t attrType,
+                             bool enforcePrivate) const
+{
+    bool localizationSetting = accessor != NULL && accessor->getLocalizationSetting();
+    const char* errorMsg = NULL;
+
+    outValue->size = sizeof(Res_value);
+    outValue->res0 = 0;
+
+    // First strip leading/trailing whitespace.  Do this before handling
+    // escapes, so they can be used to force whitespace into the string.
+    if (!preserveSpaces) {
+        while (len > 0 && isspace16(*s)) {
+            s++;
+            len--;
+        }
+        while (len > 0 && isspace16(s[len-1])) {
+            len--;
+        }
+        // If the string ends with '\', then we keep the space after it.
+        if (len > 0 && s[len-1] == '\\' && s[len] != 0) {
+            len++;
+        }
+    }
+
+    //printf("Value for: %s\n", String8(s, len).string());
+
+    uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED;
+    uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff;
+    bool fromAccessor = false;
+    if (attrID != 0 && !Res_INTERNALID(attrID)) {
+        const ssize_t p = getResourcePackageIndex(attrID);
+        const bag_entry* bag;
+        ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
+        //printf("For attr 0x%08x got bag of %d\n", attrID, cnt);
+        if (cnt >= 0) {
+            while (cnt > 0) {
+                //printf("Entry 0x%08x = 0x%08x\n", bag->map.name.ident, bag->map.value.data);
+                switch (bag->map.name.ident) {
+                case ResTable_map::ATTR_TYPE:
+                    attrType = bag->map.value.data;
+                    break;
+                case ResTable_map::ATTR_MIN:
+                    attrMin = bag->map.value.data;
+                    break;
+                case ResTable_map::ATTR_MAX:
+                    attrMax = bag->map.value.data;
+                    break;
+                case ResTable_map::ATTR_L10N:
+                    l10nReq = bag->map.value.data;
+                    break;
+                }
+                bag++;
+                cnt--;
+            }
+            unlockBag(bag);
+        } else if (accessor && accessor->getAttributeType(attrID, &attrType)) {
+            fromAccessor = true;
+            if (attrType == ResTable_map::TYPE_ENUM
+                    || attrType == ResTable_map::TYPE_FLAGS
+                    || attrType == ResTable_map::TYPE_INTEGER) {
+                accessor->getAttributeMin(attrID, &attrMin);
+                accessor->getAttributeMax(attrID, &attrMax);
+            }
+            if (localizationSetting) {
+                l10nReq = accessor->getAttributeL10N(attrID);
+            }
+        }
+    }
+
+    const bool canStringCoerce =
+        coerceType && (attrType&ResTable_map::TYPE_STRING) != 0;
+
+    if (*s == '@') {
+        outValue->dataType = outValue->TYPE_REFERENCE;
+
+        // Note: we don't check attrType here because the reference can
+        // be to any other type; we just need to count on the client making
+        // sure the referenced type is correct.
+        
+        //printf("Looking up ref: %s\n", String8(s, len).string());
+
+        // It's a reference!
+        if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
+            outValue->data = 0;
+            return true;
+        } else {
+            bool createIfNotFound = false;
+            const char16_t* resourceRefName;
+            int resourceNameLen;
+            if (len > 2 && s[1] == '+') {
+                createIfNotFound = true;
+                resourceRefName = s + 2;
+                resourceNameLen = len - 2;
+            } else if (len > 2 && s[1] == '*') {
+                enforcePrivate = false;
+                resourceRefName = s + 2;
+                resourceNameLen = len - 2;
+            } else {
+                createIfNotFound = false;
+                resourceRefName = s + 1;
+                resourceNameLen = len - 1;
+            }
+            String16 package, type, name;
+            if (!expandResourceRef(resourceRefName,resourceNameLen, &package, &type, &name,
+                                   defType, defPackage, &errorMsg)) {
+                if (accessor != NULL) {
+                    accessor->reportError(accessorCookie, errorMsg);
+                }
+                return false;
+            }
+
+            uint32_t specFlags = 0;
+            uint32_t rid = identifierForName(name.string(), name.size(), type.string(),
+                    type.size(), package.string(), package.size(), &specFlags);
+            if (rid != 0) {
+                if (enforcePrivate) {
+                    if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
+                        if (accessor != NULL) {
+                            accessor->reportError(accessorCookie, "Resource is not public.");
+                        }
+                        return false;
+                    }
+                }
+                if (!accessor) {
+                    outValue->data = rid;
+                    return true;
+                }
+                rid = Res_MAKEID(
+                    accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
+                    Res_GETTYPE(rid), Res_GETENTRY(rid));
+                TABLE_NOISY(printf("Incl %s:%s/%s: 0x%08x\n",
+                       String8(package).string(), String8(type).string(),
+                       String8(name).string(), rid));
+                outValue->data = rid;
+                return true;
+            }
+
+            if (accessor) {
+                uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name,
+                                                                       createIfNotFound);
+                if (rid != 0) {
+                    TABLE_NOISY(printf("Pckg %s:%s/%s: 0x%08x\n",
+                           String8(package).string(), String8(type).string(),
+                           String8(name).string(), rid));
+                    outValue->data = rid;
+                    return true;
+                }
+            }
+        }
+
+        if (accessor != NULL) {
+            accessor->reportError(accessorCookie, "No resource found that matches the given name");
+        }
+        return false;
+    }
+
+    // if we got to here, and localization is required and it's not a reference,
+    // complain and bail.
+    if (l10nReq == ResTable_map::L10N_SUGGESTED) {
+        if (localizationSetting) {
+            if (accessor != NULL) {
+                accessor->reportError(accessorCookie, "This attribute must be localized.");
+            }
+        }
+    }
+    
+    if (*s == '#') {
+        // It's a color!  Convert to an integer of the form 0xaarrggbb.
+        uint32_t color = 0;
+        bool error = false;
+        if (len == 4) {
+            outValue->dataType = outValue->TYPE_INT_COLOR_RGB4;
+            color |= 0xFF000000;
+            color |= get_hex(s[1], &error) << 20;
+            color |= get_hex(s[1], &error) << 16;
+            color |= get_hex(s[2], &error) << 12;
+            color |= get_hex(s[2], &error) << 8;
+            color |= get_hex(s[3], &error) << 4;
+            color |= get_hex(s[3], &error);
+        } else if (len == 5) {
+            outValue->dataType = outValue->TYPE_INT_COLOR_ARGB4;
+            color |= get_hex(s[1], &error) << 28;
+            color |= get_hex(s[1], &error) << 24;
+            color |= get_hex(s[2], &error) << 20;
+            color |= get_hex(s[2], &error) << 16;
+            color |= get_hex(s[3], &error) << 12;
+            color |= get_hex(s[3], &error) << 8;
+            color |= get_hex(s[4], &error) << 4;
+            color |= get_hex(s[4], &error);
+        } else if (len == 7) {
+            outValue->dataType = outValue->TYPE_INT_COLOR_RGB8;
+            color |= 0xFF000000;
+            color |= get_hex(s[1], &error) << 20;
+            color |= get_hex(s[2], &error) << 16;
+            color |= get_hex(s[3], &error) << 12;
+            color |= get_hex(s[4], &error) << 8;
+            color |= get_hex(s[5], &error) << 4;
+            color |= get_hex(s[6], &error);
+        } else if (len == 9) {
+            outValue->dataType = outValue->TYPE_INT_COLOR_ARGB8;
+            color |= get_hex(s[1], &error) << 28;
+            color |= get_hex(s[2], &error) << 24;
+            color |= get_hex(s[3], &error) << 20;
+            color |= get_hex(s[4], &error) << 16;
+            color |= get_hex(s[5], &error) << 12;
+            color |= get_hex(s[6], &error) << 8;
+            color |= get_hex(s[7], &error) << 4;
+            color |= get_hex(s[8], &error);
+        } else {
+            error = true;
+        }
+        if (!error) {
+            if ((attrType&ResTable_map::TYPE_COLOR) == 0) {
+                if (!canStringCoerce) {
+                    if (accessor != NULL) {
+                        accessor->reportError(accessorCookie,
+                                "Color types not allowed");
+                    }
+                    return false;
+                }
+            } else {
+                outValue->data = color;
+                //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color);
+                return true;
+            }
+        } else {
+            if ((attrType&ResTable_map::TYPE_COLOR) != 0) {
+                if (accessor != NULL) {
+                    accessor->reportError(accessorCookie, "Color value not valid --"
+                            " must be #rgb, #argb, #rrggbb, or #aarrggbb");
+                }
+                #if 0
+                fprintf(stderr, "%s: Color ID %s value %s is not valid\n",
+                        "Resource File", //(const char*)in->getPrintableSource(),
+                        String8(*curTag).string(),
+                        String8(s, len).string());
+                #endif
+                return false;
+            }
+        }
+    }
+
+    if (*s == '?') {
+        outValue->dataType = outValue->TYPE_ATTRIBUTE;
+
+        // Note: we don't check attrType here because the reference can
+        // be to any other type; we just need to count on the client making
+        // sure the referenced type is correct.
+
+        //printf("Looking up attr: %s\n", String8(s, len).string());
+
+        static const String16 attr16("attr");
+        String16 package, type, name;
+        if (!expandResourceRef(s+1, len-1, &package, &type, &name,
+                               &attr16, defPackage, &errorMsg)) {
+            if (accessor != NULL) {
+                accessor->reportError(accessorCookie, errorMsg);
+            }
+            return false;
+        }
+
+        //printf("Pkg: %s, Type: %s, Name: %s\n",
+        //       String8(package).string(), String8(type).string(),
+        //       String8(name).string());
+        uint32_t specFlags = 0;
+        uint32_t rid = 
+            identifierForName(name.string(), name.size(),
+                              type.string(), type.size(),
+                              package.string(), package.size(), &specFlags);
+        if (rid != 0) {
+            if (enforcePrivate) {
+                if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
+                    if (accessor != NULL) {
+                        accessor->reportError(accessorCookie, "Attribute is not public.");
+                    }
+                    return false;
+                }
+            }
+            if (!accessor) {
+                outValue->data = rid;
+                return true;
+            }
+            rid = Res_MAKEID(
+                accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
+                Res_GETTYPE(rid), Res_GETENTRY(rid));
+            //printf("Incl %s:%s/%s: 0x%08x\n",
+            //       String8(package).string(), String8(type).string(),
+            //       String8(name).string(), rid);
+            outValue->data = rid;
+            return true;
+        }
+
+        if (accessor) {
+            uint32_t rid = accessor->getCustomResource(package, type, name);
+            if (rid != 0) {
+                //printf("Mine %s:%s/%s: 0x%08x\n",
+                //       String8(package).string(), String8(type).string(),
+                //       String8(name).string(), rid);
+                outValue->data = rid;
+                return true;
+            }
+        }
+
+        if (accessor != NULL) {
+            accessor->reportError(accessorCookie, "No resource found that matches the given name");
+        }
+        return false;
+    }
+
+    if (stringToInt(s, len, outValue)) {
+        if ((attrType&ResTable_map::TYPE_INTEGER) == 0) {
+            // If this type does not allow integers, but does allow floats,
+            // fall through on this error case because the float type should
+            // be able to accept any integer value.
+            if (!canStringCoerce && (attrType&ResTable_map::TYPE_FLOAT) == 0) {
+                if (accessor != NULL) {
+                    accessor->reportError(accessorCookie, "Integer types not allowed");
+                }
+                return false;
+            }
+        } else {
+            if (((int32_t)outValue->data) < ((int32_t)attrMin)
+                    || ((int32_t)outValue->data) > ((int32_t)attrMax)) {
+                if (accessor != NULL) {
+                    accessor->reportError(accessorCookie, "Integer value out of range");
+                }
+                return false;
+            }
+            return true;
+        }
+    }
+
+    if (stringToFloat(s, len, outValue)) {
+        if (outValue->dataType == Res_value::TYPE_DIMENSION) {
+            if ((attrType&ResTable_map::TYPE_DIMENSION) != 0) {
+                return true;
+            }
+            if (!canStringCoerce) {
+                if (accessor != NULL) {
+                    accessor->reportError(accessorCookie, "Dimension types not allowed");
+                }
+                return false;
+            }
+        } else if (outValue->dataType == Res_value::TYPE_FRACTION) {
+            if ((attrType&ResTable_map::TYPE_FRACTION) != 0) {
+                return true;
+            }
+            if (!canStringCoerce) {
+                if (accessor != NULL) {
+                    accessor->reportError(accessorCookie, "Fraction types not allowed");
+                }
+                return false;
+            }
+        } else if ((attrType&ResTable_map::TYPE_FLOAT) == 0) {
+            if (!canStringCoerce) {
+                if (accessor != NULL) {
+                    accessor->reportError(accessorCookie, "Float types not allowed");
+                }
+                return false;
+            }
+        } else {
+            return true;
+        }
+    }
+
+    if (len == 4) {
+        if ((s[0] == 't' || s[0] == 'T') &&
+            (s[1] == 'r' || s[1] == 'R') &&
+            (s[2] == 'u' || s[2] == 'U') &&
+            (s[3] == 'e' || s[3] == 'E')) {
+            if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
+                if (!canStringCoerce) {
+                    if (accessor != NULL) {
+                        accessor->reportError(accessorCookie, "Boolean types not allowed");
+                    }
+                    return false;
+                }
+            } else {
+                outValue->dataType = outValue->TYPE_INT_BOOLEAN;
+                outValue->data = (uint32_t)-1;
+                return true;
+            }
+        }
+    }
+
+    if (len == 5) {
+        if ((s[0] == 'f' || s[0] == 'F') &&
+            (s[1] == 'a' || s[1] == 'A') &&
+            (s[2] == 'l' || s[2] == 'L') &&
+            (s[3] == 's' || s[3] == 'S') &&
+            (s[4] == 'e' || s[4] == 'E')) {
+            if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
+                if (!canStringCoerce) {
+                    if (accessor != NULL) {
+                        accessor->reportError(accessorCookie, "Boolean types not allowed");
+                    }
+                    return false;
+                }
+            } else {
+                outValue->dataType = outValue->TYPE_INT_BOOLEAN;
+                outValue->data = 0;
+                return true;
+            }
+        }
+    }
+
+    if ((attrType&ResTable_map::TYPE_ENUM) != 0) {
+        const ssize_t p = getResourcePackageIndex(attrID);
+        const bag_entry* bag;
+        ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
+        //printf("Got %d for enum\n", cnt);
+        if (cnt >= 0) {
+            resource_name rname;
+            while (cnt > 0) {
+                if (!Res_INTERNALID(bag->map.name.ident)) {
+                    //printf("Trying attr #%08x\n", bag->map.name.ident);
+                    if (getResourceName(bag->map.name.ident, &rname)) {
+                        #if 0
+                        printf("Matching %s against %s (0x%08x)\n",
+                               String8(s, len).string(),
+                               String8(rname.name, rname.nameLen).string(),
+                               bag->map.name.ident);
+                        #endif
+                        if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) {
+                            outValue->dataType = bag->map.value.dataType;
+                            outValue->data = bag->map.value.data;
+                            unlockBag(bag);
+                            return true;
+                        }
+                    }
+    
+                }
+                bag++;
+                cnt--;
+            }
+            unlockBag(bag);
+        }
+
+        if (fromAccessor) {
+            if (accessor->getAttributeEnum(attrID, s, len, outValue)) {
+                return true;
+            }
+        }
+    }
+
+    if ((attrType&ResTable_map::TYPE_FLAGS) != 0) {
+        const ssize_t p = getResourcePackageIndex(attrID);
+        const bag_entry* bag;
+        ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
+        //printf("Got %d for flags\n", cnt);
+        if (cnt >= 0) {
+            bool failed = false;
+            resource_name rname;
+            outValue->dataType = Res_value::TYPE_INT_HEX;
+            outValue->data = 0;
+            const char16_t* end = s + len;
+            const char16_t* pos = s;
+            while (pos < end && !failed) {
+                const char16_t* start = pos;
+                end++;
+                while (pos < end && *pos != '|') {
+                    pos++;
+                }
+				//printf("Looking for: %s\n", String8(start, pos-start).string());
+                const bag_entry* bagi = bag;
+				ssize_t i;
+                for (i=0; i<cnt; i++, bagi++) {
+                    if (!Res_INTERNALID(bagi->map.name.ident)) {
+                        //printf("Trying attr #%08x\n", bagi->map.name.ident);
+                        if (getResourceName(bagi->map.name.ident, &rname)) {
+                            #if 0
+                            printf("Matching %s against %s (0x%08x)\n",
+                                   String8(start,pos-start).string(),
+                                   String8(rname.name, rname.nameLen).string(),
+                                   bagi->map.name.ident);
+                            #endif
+                            if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) {
+                                outValue->data |= bagi->map.value.data;
+                                break;
+                            }
+                        }
+                    }
+                }
+                if (i >= cnt) {
+                    // Didn't find this flag identifier.
+                    failed = true;
+                }
+                if (pos < end) {
+                    pos++;
+                }
+            }
+            unlockBag(bag);
+            if (!failed) {
+				//printf("Final flag value: 0x%lx\n", outValue->data);
+                return true;
+            }
+        }
+
+
+        if (fromAccessor) {
+            if (accessor->getAttributeFlags(attrID, s, len, outValue)) {
+				//printf("Final flag value: 0x%lx\n", outValue->data);
+                return true;
+            }
+        }
+    }
+
+    if ((attrType&ResTable_map::TYPE_STRING) == 0) {
+        if (accessor != NULL) {
+            accessor->reportError(accessorCookie, "String types not allowed");
+        }
+        return false;
+    }
+
+    // Generic string handling...
+    outValue->dataType = outValue->TYPE_STRING;
+    if (outString) {
+        bool failed = collectString(outString, s, len, preserveSpaces, &errorMsg);
+        if (accessor != NULL) {
+            accessor->reportError(accessorCookie, errorMsg);
+        }
+        return failed;
+    }
+
+    return true;
+}
+
+bool ResTable::collectString(String16* outString,
+                             const char16_t* s, size_t len,
+                             bool preserveSpaces,
+                             const char** outErrorMsg,
+                             bool append)
+{
+    String16 tmp;
+
+    char quoted = 0;
+    const char16_t* p = s;
+    while (p < (s+len)) {
+        while (p < (s+len)) {
+            const char16_t c = *p;
+            if (c == '\\') {
+                break;
+            }
+            if (!preserveSpaces) {
+                if (quoted == 0 && isspace16(c)
+                    && (c != ' ' || isspace16(*(p+1)))) {
+                    break;
+                }
+                if (c == '"' && (quoted == 0 || quoted == '"')) {
+                    break;
+                }
+                if (c == '\'' && (quoted == 0 || quoted == '\'')) {
+                    break;
+                }
+            }
+            p++;
+        }
+        if (p < (s+len)) {
+            if (p > s) {
+                tmp.append(String16(s, p-s));
+            }
+            if (!preserveSpaces && (*p == '"' || *p == '\'')) {
+                if (quoted == 0) {
+                    quoted = *p;
+                } else {
+                    quoted = 0;
+                }
+                p++;
+            } else if (!preserveSpaces && isspace16(*p)) {
+                // Space outside of a quote -- consume all spaces and
+                // leave a single plain space char.
+                tmp.append(String16(" "));
+                p++;
+                while (p < (s+len) && isspace16(*p)) {
+                    p++;
+                }
+            } else if (*p == '\\') {
+                p++;
+                if (p < (s+len)) {
+                    switch (*p) {
+                    case 't':
+                        tmp.append(String16("\t"));
+                        break;
+                    case 'n':
+                        tmp.append(String16("\n"));
+                        break;
+                    case '#':
+                        tmp.append(String16("#"));
+                        break;
+                    case '@':
+                        tmp.append(String16("@"));
+                        break;
+                    case '?':
+                        tmp.append(String16("?"));
+                        break;
+                    case '"':
+                        tmp.append(String16("\""));
+                        break;
+                    case '\'':
+                        tmp.append(String16("'"));
+                        break;
+                    case '\\':
+                        tmp.append(String16("\\"));
+                        break;
+                    case 'u':
+                    {
+                        char16_t chr = 0;
+                        int i = 0;
+                        while (i < 4 && p[1] != 0) {
+                            p++;
+                            i++;
+                            int c;
+                            if (*p >= '0' && *p <= '9') {
+                                c = *p - '0';
+                            } else if (*p >= 'a' && *p <= 'f') {
+                                c = *p - 'a' + 10;
+                            } else if (*p >= 'A' && *p <= 'F') {
+                                c = *p - 'A' + 10;
+                            } else {
+                                if (outErrorMsg) {
+                                    *outErrorMsg = "Bad character in \\u unicode escape sequence";
+                                }
+                                return false;
+                            }
+                            chr = (chr<<4) | c;
+                        }
+                        tmp.append(String16(&chr, 1));
+                    } break;
+                    default:
+                        // ignore unknown escape chars.
+                        break;
+                    }
+                    p++;
+                }
+            }
+            len -= (p-s);
+            s = p;
+        }
+    }
+
+    if (tmp.size() != 0) {
+        if (len > 0) {
+            tmp.append(String16(s, len));
+        }
+        if (append) {
+            outString->append(tmp);
+        } else {
+            outString->setTo(tmp);
+        }
+    } else {
+        if (append) {
+            outString->append(String16(s, len));
+        } else {
+            outString->setTo(s, len);
+        }
+    }
+
+    return true;
+}
+
+size_t ResTable::getBasePackageCount() const
+{
+    if (mError != NO_ERROR) {
+        return 0;
+    }
+    return mPackageGroups.size();
+}
+
+const char16_t* ResTable::getBasePackageName(size_t idx) const
+{
+    if (mError != NO_ERROR) {
+        return 0;
+    }
+    LOG_FATAL_IF(idx >= mPackageGroups.size(),
+                 "Requested package index %d past package count %d",
+                 (int)idx, (int)mPackageGroups.size());
+    return mPackageGroups[idx]->name.string();
+}
+
+uint32_t ResTable::getBasePackageId(size_t idx) const
+{
+    if (mError != NO_ERROR) {
+        return 0;
+    }
+    LOG_FATAL_IF(idx >= mPackageGroups.size(),
+                 "Requested package index %d past package count %d",
+                 (int)idx, (int)mPackageGroups.size());
+    return mPackageGroups[idx]->id;
+}
+
+size_t ResTable::getTableCount() const
+{
+    return mHeaders.size();
+}
+
+const ResStringPool* ResTable::getTableStringBlock(size_t index) const
+{
+    return &mHeaders[index]->values;
+}
+
+void* ResTable::getTableCookie(size_t index) const
+{
+    return mHeaders[index]->cookie;
+}
+
+void ResTable::getConfigurations(Vector<ResTable_config>* configs) const
+{
+    const size_t I = mPackageGroups.size();
+    for (size_t i=0; i<I; i++) {
+        const PackageGroup* packageGroup = mPackageGroups[i];
+        const size_t J = packageGroup->packages.size();
+        for (size_t j=0; j<J; j++) {
+            const Package* package = packageGroup->packages[j];
+            const size_t K = package->types.size();
+            for (size_t k=0; k<K; k++) {
+                const Type* type = package->types[k];
+                if (type == NULL) continue;
+                const size_t L = type->configs.size();
+                for (size_t l=0; l<L; l++) {
+                    const ResTable_type* config = type->configs[l];
+                    const ResTable_config* cfg = &config->config;
+                    // only insert unique
+                    const size_t M = configs->size();
+                    size_t m;
+                    for (m=0; m<M; m++) {
+                        if (0 == (*configs)[m].compare(*cfg)) {
+                            break;
+                        }
+                    }
+                    // if we didn't find it
+                    if (m == M) {
+                        configs->add(*cfg);
+                    }
+                }
+            }
+        }
+    }
+}
+
+void ResTable::getLocales(Vector<String8>* locales) const
+{
+    Vector<ResTable_config> configs;
+    LOGD("calling getConfigurations");
+    getConfigurations(&configs);
+    LOGD("called getConfigurations size=%d", (int)configs.size());
+    const size_t I = configs.size();
+    for (size_t i=0; i<I; i++) {
+        char locale[6];
+        configs[i].getLocale(locale);
+        const size_t J = locales->size();
+        size_t j;
+        for (j=0; j<J; j++) {
+            if (0 == strcmp(locale, (*locales)[j].string())) {
+                break;
+            }
+        }
+        if (j == J) {
+            locales->add(String8(locale));
+        }
+    }
+}
+
+ssize_t ResTable::getEntry(
+    const Package* package, int typeIndex, int entryIndex,
+    const ResTable_config* config,
+    const ResTable_type** outType, const ResTable_entry** outEntry,
+    const Type** outTypeClass) const
+{
+    LOGV("Getting entry from package %p\n", package);
+    const ResTable_package* const pkg = package->package;
+
+    const Type* allTypes = package->getType(typeIndex);
+    LOGV("allTypes=%p\n", allTypes);
+    if (allTypes == NULL) {
+        LOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex);
+        return 0;
+    }
+
+    if ((size_t)entryIndex >= allTypes->entryCount) {
+        LOGW("getEntry failing because entryIndex %d is beyond type entryCount %d",
+            entryIndex, (int)allTypes->entryCount);
+        return BAD_TYPE;
+    }
+        
+    const ResTable_type* type = NULL;
+    uint32_t offset = ResTable_type::NO_ENTRY;
+    ResTable_config bestConfig;
+    memset(&bestConfig, 0, sizeof(bestConfig)); // make the compiler shut up
+    
+    const size_t NT = allTypes->configs.size();
+    for (size_t i=0; i<NT; i++) {
+        const ResTable_type* const thisType = allTypes->configs[i];
+        if (thisType == NULL) continue;
+        
+        ResTable_config thisConfig;
+        thisConfig.copyFromDtoH(thisType->config);
+
+        TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): imsi:%d/%d=%d/%d lang:%c%c=%c%c cnt:%c%c=%c%c "
+                            "orien:%d=%d touch:%d=%d density:%d=%d key:%d=%d inp:%d=%d nav:%d=%d w:%d=%d h:%d=%d\n",
+                           entryIndex, typeIndex+1, dtohl(thisType->config.size),
+                           thisConfig.mcc, thisConfig.mnc,
+                           config ? config->mcc : 0, config ? config->mnc : 0,
+                           thisConfig.language[0] ? thisConfig.language[0] : '-',
+                           thisConfig.language[1] ? thisConfig.language[1] : '-',
+                           config && config->language[0] ? config->language[0] : '-',
+                           config && config->language[1] ? config->language[1] : '-',
+                           thisConfig.country[0] ? thisConfig.country[0] : '-',
+                           thisConfig.country[1] ? thisConfig.country[1] : '-',
+                           config && config->country[0] ? config->country[0] : '-',
+                           config && config->country[1] ? config->country[1] : '-',
+                           thisConfig.orientation,
+                           config ? config->orientation : 0,
+                           thisConfig.touchscreen,
+                           config ? config->touchscreen : 0,
+                           thisConfig.density,
+                           config ? config->density : 0,
+                           thisConfig.keyboard,
+                           config ? config->keyboard : 0,
+                           thisConfig.inputFlags,
+                           config ? config->inputFlags : 0,
+                           thisConfig.navigation,
+                           config ? config->navigation : 0,
+                           thisConfig.screenWidth,
+                           config ? config->screenWidth : 0,
+                           thisConfig.screenHeight,
+                           config ? config->screenHeight : 0));
+        
+        // Check to make sure this one is valid for the current parameters.
+        if (config && !thisConfig.match(*config)) {
+            TABLE_GETENTRY(LOGI("Does not match config!\n"));
+            continue;
+        }
+        
+        // Check if there is the desired entry in this type.
+        
+        const uint8_t* const end = ((const uint8_t*)thisType)
+            + dtohl(thisType->header.size);
+        const uint32_t* const eindex = (const uint32_t*)
+            (((const uint8_t*)thisType) + dtohs(thisType->header.headerSize));
+        
+        uint32_t thisOffset = dtohl(eindex[entryIndex]);
+        if (thisOffset == ResTable_type::NO_ENTRY) {
+            TABLE_GETENTRY(LOGI("Skipping because it is not defined!\n"));
+            continue;
+        }
+        
+        if (type != NULL) {
+            // Check if this one is less specific than the last found.  If so,
+            // we will skip it.  We check starting with things we most care
+            // about to those we least care about.
+            if (!thisConfig.isBetterThan(bestConfig, config)) {
+                TABLE_GETENTRY(LOGI("This config is worse than last!\n"));
+                continue;
+            }
+        }
+        
+        type = thisType;
+        offset = thisOffset;
+        bestConfig = thisConfig;
+        TABLE_GETENTRY(LOGI("Best entry so far -- using it!\n"));
+        if (!config) break;
+    }
+    
+    if (type == NULL) {
+        TABLE_GETENTRY(LOGI("No value found for requested entry!\n"));
+        return BAD_INDEX;
+    }
+    
+    offset += dtohl(type->entriesStart);
+    TABLE_NOISY(aout << "Looking in resource table " << package->header->header
+          << ", typeOff="
+          << (void*)(((const char*)type)-((const char*)package->header->header))
+          << ", offset=" << (void*)offset << endl);
+
+    if (offset > (dtohl(type->header.size)-sizeof(ResTable_entry))) {
+        LOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x",
+             offset, dtohl(type->header.size));
+        return BAD_TYPE;
+    }
+    if ((offset&0x3) != 0) {
+        LOGW("ResTable_entry at 0x%x is not on an integer boundary",
+             offset);
+        return BAD_TYPE;
+    }
+
+    const ResTable_entry* const entry = (const ResTable_entry*)
+        (((const uint8_t*)type) + offset);
+    if (dtohs(entry->size) < sizeof(*entry)) {
+        LOGW("ResTable_entry size 0x%x is too small", dtohs(entry->size));
+        return BAD_TYPE;
+    }
+
+    *outType = type;
+    *outEntry = entry;
+    if (outTypeClass != NULL) {
+        *outTypeClass = allTypes;
+    }
+    return offset + dtohs(entry->size);
+}
+
+status_t ResTable::parsePackage(const ResTable_package* const pkg,
+                                const Header* const header)
+{
+    const uint8_t* base = (const uint8_t*)pkg;
+    status_t err = validate_chunk(&pkg->header, sizeof(*pkg),
+                                  header->dataEnd, "ResTable_package");
+    if (err != NO_ERROR) {
+        return (mError=err);
+    }
+
+    const size_t pkgSize = dtohl(pkg->header.size);
+
+    if (dtohl(pkg->typeStrings) >= pkgSize) {
+        LOGW("ResTable_package type strings at %p are past chunk size %p.",
+             (void*)dtohl(pkg->typeStrings), (void*)pkgSize);
+        return (mError=BAD_TYPE);
+    }
+    if ((dtohl(pkg->typeStrings)&0x3) != 0) {
+        LOGW("ResTable_package type strings at %p is not on an integer boundary.",
+             (void*)dtohl(pkg->typeStrings));
+        return (mError=BAD_TYPE);
+    }
+    if (dtohl(pkg->keyStrings) >= pkgSize) {
+        LOGW("ResTable_package key strings at %p are past chunk size %p.",
+             (void*)dtohl(pkg->keyStrings), (void*)pkgSize);
+        return (mError=BAD_TYPE);
+    }
+    if ((dtohl(pkg->keyStrings)&0x3) != 0) {
+        LOGW("ResTable_package key strings at %p is not on an integer boundary.",
+             (void*)dtohl(pkg->keyStrings));
+        return (mError=BAD_TYPE);
+    }
+    
+    Package* package = NULL;
+    PackageGroup* group = NULL;
+    uint32_t id = dtohl(pkg->id);
+    if (id != 0 && id < 256) {
+        size_t idx = mPackageMap[id];
+        if (idx == 0) {
+            idx = mPackageGroups.size()+1;
+
+            char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)];
+            strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t));
+            group = new PackageGroup(String16(tmpName), id);
+            if (group == NULL) {
+                return (mError=NO_MEMORY);
+            }
+
+            err = group->typeStrings.setTo(base+dtohl(pkg->typeStrings),
+                                           header->dataEnd-(base+dtohl(pkg->typeStrings)));
+            if (err != NO_ERROR) {
+                return (mError=err);
+            }
+            err = group->keyStrings.setTo(base+dtohl(pkg->keyStrings),
+                                          header->dataEnd-(base+dtohl(pkg->keyStrings)));
+            if (err != NO_ERROR) {
+                return (mError=err);
+            }
+
+            //printf("Adding new package id %d at index %d\n", id, idx);
+            err = mPackageGroups.add(group);
+            if (err < NO_ERROR) {
+                return (mError=err);
+            }
+            mPackageMap[id] = (uint8_t)idx;
+        } else {
+            group = mPackageGroups.itemAt(idx-1);
+            if (group == NULL) {
+                return (mError=UNKNOWN_ERROR);
+            }
+        }
+        package = new Package(header, pkg);
+        if (package == NULL) {
+            return (mError=NO_MEMORY);
+        }
+        err = group->packages.add(package);
+        if (err < NO_ERROR) {
+            return (mError=err);
+        }
+    } else {
+        LOG_ALWAYS_FATAL("Skins not supported!");
+        return NO_ERROR;
+    }
+
+    
+    // Iterate through all chunks.
+    size_t curPackage = 0;
+    
+    const ResChunk_header* chunk =
+        (const ResChunk_header*)(((const uint8_t*)pkg)
+                                 + dtohs(pkg->header.headerSize));
+    const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
+    while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
+           ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
+        TABLE_NOISY(LOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
+                         dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
+                         (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
+        const size_t csize = dtohl(chunk->size);
+        const uint16_t ctype = dtohs(chunk->type);
+        if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
+            const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk);
+            err = validate_chunk(&typeSpec->header, sizeof(*typeSpec),
+                                 endPos, "ResTable_typeSpec");
+            if (err != NO_ERROR) {
+                return (mError=err);
+            }
+            
+            const size_t typeSpecSize = dtohl(typeSpec->header.size);
+            
+            LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
+                                    (void*)(base-(const uint8_t*)chunk),
+                                    dtohs(typeSpec->header.type),
+                                    dtohs(typeSpec->header.headerSize),
+                                    (void*)typeSize));
+            // look for block overrun or int overflow when multiplying by 4
+            if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
+                    || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*dtohl(typeSpec->entryCount))
+                    > typeSpecSize)) {
+                LOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.",
+                     (void*)(dtohs(typeSpec->header.headerSize)
+                             +(sizeof(uint32_t)*dtohl(typeSpec->entryCount))),
+                     (void*)typeSpecSize);
+                return (mError=BAD_TYPE);
+            }
+            
+            if (typeSpec->id == 0) {
+                LOGW("ResTable_type has an id of 0.");
+                return (mError=BAD_TYPE);
+            }
+            
+            while (package->types.size() < typeSpec->id) {
+                package->types.add(NULL);
+            }
+            Type* t = package->types[typeSpec->id-1];
+            if (t == NULL) {
+                t = new Type(header, package, dtohl(typeSpec->entryCount));
+                package->types.editItemAt(typeSpec->id-1) = t;
+            } else if (dtohl(typeSpec->entryCount) != t->entryCount) {
+                LOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
+                    (int)dtohl(typeSpec->entryCount), (int)t->entryCount);
+                return (mError=BAD_TYPE);
+            }
+            t->typeSpecFlags = (const uint32_t*)(
+                    ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
+            t->typeSpec = typeSpec;
+            
+        } else if (ctype == RES_TABLE_TYPE_TYPE) {
+            const ResTable_type* type = (const ResTable_type*)(chunk);
+            err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4,
+                                 endPos, "ResTable_type");
+            if (err != NO_ERROR) {
+                return (mError=err);
+            }
+            
+            const size_t typeSize = dtohl(type->header.size);
+            
+            LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n",
+                                    (void*)(base-(const uint8_t*)chunk),
+                                    dtohs(type->header.type),
+                                    dtohs(type->header.headerSize),
+                                    (void*)typeSize));
+            if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*dtohl(type->entryCount))
+                > typeSize) {
+                LOGW("ResTable_type entry index to %p extends beyond chunk end %p.",
+                     (void*)(dtohs(type->header.headerSize)
+                             +(sizeof(uint32_t)*dtohl(type->entryCount))),
+                     (void*)typeSize);
+                return (mError=BAD_TYPE);
+            }
+            if (dtohl(type->entryCount) != 0
+                && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) {
+                LOGW("ResTable_type entriesStart at %p extends beyond chunk end %p.",
+                     (void*)dtohl(type->entriesStart), (void*)typeSize);
+                return (mError=BAD_TYPE);
+            }
+            if (type->id == 0) {
+                LOGW("ResTable_type has an id of 0.");
+                return (mError=BAD_TYPE);
+            }
+            
+            while (package->types.size() < type->id) {
+                package->types.add(NULL);
+            }
+            Type* t = package->types[type->id-1];
+            if (t == NULL) {
+                t = new Type(header, package, dtohl(type->entryCount));
+                package->types.editItemAt(type->id-1) = t;
+            } else if (dtohl(type->entryCount) != t->entryCount) {
+                LOGW("ResTable_type entry count inconsistent: given %d, previously %d",
+                    (int)dtohl(type->entryCount), (int)t->entryCount);
+                return (mError=BAD_TYPE);
+            }
+            
+            TABLE_GETENTRY(
+                ResTable_config thisConfig;
+                thisConfig.copyFromDtoH(type->config);
+                LOGI("Adding config to type %d: imsi:%d/%d lang:%c%c cnt:%c%c "
+                     "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n",
+                      type->id,
+                      thisConfig.mcc, thisConfig.mnc,
+                      thisConfig.language[0] ? thisConfig.language[0] : '-',
+                      thisConfig.language[1] ? thisConfig.language[1] : '-',
+                      thisConfig.country[0] ? thisConfig.country[0] : '-',
+                      thisConfig.country[1] ? thisConfig.country[1] : '-',
+                      thisConfig.orientation,
+                      thisConfig.touchscreen,
+                      thisConfig.density,
+                      thisConfig.keyboard,
+                      thisConfig.inputFlags,
+                      thisConfig.navigation,
+                      thisConfig.screenWidth,
+                      thisConfig.screenHeight));
+            t->configs.add(type);
+        } else {
+            status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
+                                          endPos, "ResTable_package:unknown");
+            if (err != NO_ERROR) {
+                return (mError=err);
+            }
+        }
+        chunk = (const ResChunk_header*)
+            (((const uint8_t*)chunk) + csize);
+    }
+
+    if (group->typeCount == 0) {
+        group->typeCount = package->types.size();
+    }
+    
+    return NO_ERROR;
+}
+
+#ifndef HAVE_ANDROID_OS
+#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
+
+#define CHAR16_ARRAY_EQ(constant, var, len) \
+        ((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
+
+void ResTable::print() const
+{
+    printf("mError=0x%x (%s)\n", mError, strerror(mError));
+#if 0
+    printf("mParams=%c%c-%c%c,\n",
+            mParams.language[0], mParams.language[1],
+            mParams.country[0], mParams.country[1]);
+#endif
+    size_t pgCount = mPackageGroups.size();
+    printf("Package Groups (%d)\n", (int)pgCount);
+    for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) {
+        const PackageGroup* pg = mPackageGroups[pgIndex];
+        printf("Package Group %d id=%d packageCount=%d name=%s\n",
+                (int)pgIndex, pg->id, (int)pg->packages.size(),
+                String8(pg->name).string());
+        
+        size_t pkgCount = pg->packages.size();
+        for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
+            const Package* pkg = pg->packages[pkgIndex];
+            size_t typeCount = pkg->types.size();
+            printf("  Package %d id=%d name=%s typeCount=%d\n", (int)pkgIndex,
+                    pkg->package->id, String8(String16(pkg->package->name)).string(),
+                    (int)typeCount);
+            for (size_t typeIndex=0; typeIndex<typeCount; typeIndex++) {
+                const Type* typeConfigs = pkg->getType(typeIndex);
+                if (typeConfigs == NULL) {
+                    printf("    type %d NULL\n", (int)typeIndex);
+                    continue;
+                }
+                const size_t NTC = typeConfigs->configs.size();
+                printf("    type %d configCount=%d entryCount=%d\n",
+                       (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount);
+                if (typeConfigs->typeSpecFlags != NULL) {
+                    for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) {
+                        uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
+                                    | (0x00ff0000 & ((typeIndex+1)<<16))
+                                    | (0x0000ffff & (entryIndex));
+                        resource_name resName;
+                        this->getResourceName(resID, &resName);
+                        printf("      spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
+                            resID,
+                            CHAR16_TO_CSTR(resName.package, resName.packageLen),
+                            CHAR16_TO_CSTR(resName.type, resName.typeLen),
+                            CHAR16_TO_CSTR(resName.name, resName.nameLen),
+                            dtohl(typeConfigs->typeSpecFlags[entryIndex]));
+                    }
+                }
+                for (size_t configIndex=0; configIndex<NTC; configIndex++) {
+                    const ResTable_type* type = typeConfigs->configs[configIndex];
+                    if ((((uint64_t)type)&0x3) != 0) {
+                        printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
+                        continue;
+                    }
+                    printf("      config %d lang=%c%c cnt=%c%c orien=%d touch=%d density=%d key=%d infl=%d nav=%d w=%d h=%d\n",
+                           (int)configIndex,
+                           type->config.language[0] ? type->config.language[0] : '-',
+                           type->config.language[1] ? type->config.language[1] : '-',
+                           type->config.country[0] ? type->config.country[0] : '-',
+                           type->config.country[1] ? type->config.country[1] : '-',
+                           type->config.orientation,
+                           type->config.touchscreen,
+                           dtohs(type->config.density),
+                           type->config.keyboard,
+                           type->config.inputFlags,
+                           type->config.navigation,
+                           dtohs(type->config.screenWidth),
+                           dtohs(type->config.screenHeight));
+                    size_t entryCount = dtohl(type->entryCount);
+                    uint32_t entriesStart = dtohl(type->entriesStart);
+                    if ((entriesStart&0x3) != 0) {
+                        printf("      NON-INTEGER ResTable_type entriesStart OFFSET: %p\n", (void*)entriesStart);
+                        continue;
+                    }
+                    uint32_t typeSize = dtohl(type->header.size);
+                    if ((typeSize&0x3) != 0) {
+                        printf("      NON-INTEGER ResTable_type header.size: %p\n", (void*)typeSize);
+                        continue;
+                    }
+                    for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
+                        
+                        const uint8_t* const end = ((const uint8_t*)type)
+                            + dtohl(type->header.size);
+                        const uint32_t* const eindex = (const uint32_t*)
+                            (((const uint8_t*)type) + dtohs(type->header.headerSize));
+                        
+                        uint32_t thisOffset = dtohl(eindex[entryIndex]);
+                        if (thisOffset == ResTable_type::NO_ENTRY) {
+                            continue;
+                        }
+                        
+                        uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
+                                    | (0x00ff0000 & ((typeIndex+1)<<16))
+                                    | (0x0000ffff & (entryIndex));
+                        resource_name resName;
+                        this->getResourceName(resID, &resName);
+                        printf("        resource 0x%08x %s:%s/%s: ", resID,
+                                CHAR16_TO_CSTR(resName.package, resName.packageLen),
+                                CHAR16_TO_CSTR(resName.type, resName.typeLen),
+                                CHAR16_TO_CSTR(resName.name, resName.nameLen));
+                        if ((thisOffset&0x3) != 0) {
+                            printf("NON-INTEGER OFFSET: %p\n", (void*)thisOffset);
+                            continue;
+                        }
+                        if ((thisOffset+sizeof(ResTable_entry)) > typeSize) {
+                            printf("OFFSET OUT OF BOUNDS: %p+%p (size is %p)\n",
+                                   (void*)entriesStart, (void*)thisOffset,
+                                   (void*)typeSize);
+                            continue;
+                        }
+                        
+                        const ResTable_entry* ent = (const ResTable_entry*)
+                            (((const uint8_t*)type) + entriesStart + thisOffset);
+                        if (((entriesStart + thisOffset)&0x3) != 0) {
+                            printf("NON-INTEGER ResTable_entry OFFSET: %p\n",
+                                 (void*)(entriesStart + thisOffset));
+                            continue;
+                        }
+                        if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
+                            printf("<bag>");
+                        } else {
+                            uint16_t esize = dtohs(ent->size);
+                            if ((esize&0x3) != 0) {
+                                printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize);
+                                continue;
+                            }
+                            if ((thisOffset+esize) > typeSize) {
+                                printf("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n",
+                                       (void*)entriesStart, (void*)thisOffset,
+                                       (void*)esize, (void*)typeSize);
+                                continue;
+                            }
+                            
+                            const Res_value* value = (const Res_value*)
+                                (((const uint8_t*)ent) + esize);
+                            printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
+                                   (int)value->dataType, (int)dtohl(value->data),
+                                   (int)dtohs(value->size), (int)value->res0);
+                        }
+                        
+                        if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
+                            printf(" (PUBLIC)");
+                        }
+                        printf("\n");
+                    }
+                }
+            }
+        }
+    }
+}
+
+#endif // HAVE_ANDROID_OS
+
+}   // namespace android
diff --git a/libs/utils/SharedBuffer.cpp b/libs/utils/SharedBuffer.cpp
new file mode 100644
index 0000000..3555fb7
--- /dev/null
+++ b/libs/utils/SharedBuffer.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2005 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 <stdlib.h>
+#include <string.h>
+
+#include <utils/SharedBuffer.h>
+#include <utils/Atomic.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+SharedBuffer* SharedBuffer::alloc(size_t size)
+{
+    SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size));
+    if (sb) {
+        sb->mRefs = 1;
+        sb->mSize = size;
+    }
+    return sb;
+}
+
+
+ssize_t SharedBuffer::dealloc(const SharedBuffer* released)
+{
+    if (released->mRefs != 0) return -1; // XXX: invalid operation
+    free(const_cast<SharedBuffer*>(released));
+    return 0;
+}
+
+SharedBuffer* SharedBuffer::edit() const
+{
+    if (onlyOwner()) {
+        return const_cast<SharedBuffer*>(this);
+    }
+    SharedBuffer* sb = alloc(mSize);
+    if (sb) {
+        memcpy(sb->data(), data(), size());
+        release();
+    }
+    return sb;    
+}
+
+SharedBuffer* SharedBuffer::editResize(size_t newSize) const
+{
+    if (onlyOwner()) {
+        SharedBuffer* buf = const_cast<SharedBuffer*>(this);
+        if (buf->mSize == newSize) return buf;
+        buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
+        if (buf != NULL) {
+            buf->mSize = newSize;
+            return buf;
+        }
+    }
+    SharedBuffer* sb = alloc(newSize);
+    if (sb) {
+        const size_t mySize = mSize;
+        memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize);
+        release();
+    }
+    return sb;    
+}
+
+SharedBuffer* SharedBuffer::attemptEdit() const
+{
+    if (onlyOwner()) {
+        return const_cast<SharedBuffer*>(this);
+    }
+    return 0;
+}
+
+SharedBuffer* SharedBuffer::reset(size_t new_size) const
+{
+    // cheap-o-reset.
+    SharedBuffer* sb = alloc(new_size);
+    if (sb) {
+        release();
+    }
+    return sb;
+}
+
+void SharedBuffer::acquire() const {
+    android_atomic_inc(&mRefs);
+}
+
+int32_t SharedBuffer::release(uint32_t flags) const
+{
+    int32_t prev = 1;
+    if (onlyOwner() || ((prev = android_atomic_dec(&mRefs)) == 1)) {
+        mRefs = 0;
+        if ((flags & eKeepStorage) == 0) {
+            free(const_cast<SharedBuffer*>(this));
+        }
+    }
+    return prev;
+}
+
+
+}; // namespace android
diff --git a/libs/utils/Socket.cpp b/libs/utils/Socket.cpp
new file mode 100644
index 0000000..51509a3
--- /dev/null
+++ b/libs/utils/Socket.cpp
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Internet address class.
+//
+
+#ifdef HAVE_WINSOCK
+// This needs to come first, or Cygwin gets concerned about a potential
+// clash between WinSock and <sys/types.h>.
+# include <winsock2.h>
+#endif
+
+#include <utils/Socket.h>
+#include <utils/inet_address.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+
+#ifndef HAVE_WINSOCK
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+
+/*
+ * ===========================================================================
+ *      Socket
+ * ===========================================================================
+ */
+
+#ifndef INVALID_SOCKET
+# define INVALID_SOCKET (-1)
+#endif
+#define UNDEF_SOCKET   ((unsigned long) INVALID_SOCKET)
+
+/*static*/ bool Socket::mBootInitialized = false;
+
+/*
+ * Extract system-dependent error code.
+ */
+static inline int getSocketError(void) {
+#ifdef HAVE_WINSOCK
+    return WSAGetLastError();
+#else
+    return errno;
+#endif
+}
+
+/*
+ * One-time initialization for socket code.
+ */
+/*static*/ bool Socket::bootInit(void)
+{
+#ifdef HAVE_WINSOCK
+    WSADATA wsaData;
+    int err;
+
+    err = WSAStartup(MAKEWORD(2, 0), &wsaData);
+    if (err != 0) {
+        LOG(LOG_ERROR, "socket", "Unable to start WinSock\n");
+        return false;
+    }
+
+    LOG(LOG_INFO, "socket", "Using WinSock v%d.%d\n",
+        LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
+#endif
+
+    mBootInitialized = true;
+    return true;
+}
+
+/*
+ * One-time shutdown for socket code.
+ */
+/*static*/ void Socket::finalShutdown(void)
+{
+#ifdef HAVE_WINSOCK
+    WSACleanup();
+#endif
+    mBootInitialized = false;
+}
+
+
+/*
+ * Simple constructor.  Allow the application to create us and then make
+ * bind/connect calls.
+ */
+Socket::Socket(void)
+    : mSock(UNDEF_SOCKET)
+{
+    if (!mBootInitialized)
+        LOG(LOG_WARN, "socket", "WARNING: sockets not initialized\n");
+}
+
+/*
+ * Destructor.  Closes the socket and resets our storage.
+ */
+Socket::~Socket(void)
+{
+    close();
+}
+
+
+/*
+ * Create a socket and connect to the specified host and port.
+ */
+int Socket::connect(const char* host, int port)
+{
+    if (mSock != UNDEF_SOCKET) {
+        LOG(LOG_WARN, "socket", "Socket already connected\n");
+        return -1;
+    }
+
+    InetSocketAddress sockAddr;
+    if (!sockAddr.create(host, port))
+        return -1;
+
+    //return doConnect(sockAddr);
+    int foo;
+    foo = doConnect(sockAddr);
+    return foo;
+}
+
+/*
+ * Create a socket and connect to the specified host and port.
+ */
+int Socket::connect(const InetAddress* addr, int port)
+{
+    if (mSock != UNDEF_SOCKET) {
+        LOG(LOG_WARN, "socket", "Socket already connected\n");
+        return -1;
+    }
+
+    InetSocketAddress sockAddr;
+    if (!sockAddr.create(addr, port))
+        return -1;
+
+    return doConnect(sockAddr);
+}
+
+/*
+ * Finish creating a socket by connecting to the remote host.
+ *
+ * Returns 0 on success.
+ */
+int Socket::doConnect(const InetSocketAddress& sockAddr)
+{
+#ifdef HAVE_WINSOCK
+    SOCKET sock;
+#else
+    int sock;
+#endif
+    const InetAddress* addr = sockAddr.getAddress();
+    int port = sockAddr.getPort();
+    struct sockaddr_in inaddr;
+    DurationTimer connectTimer;
+
+    assert(sizeof(struct sockaddr_in) == addr->getAddressLength());
+    memcpy(&inaddr, addr->getAddress(), addr->getAddressLength());
+    inaddr.sin_port = htons(port);
+
+    //fprintf(stderr, "--- connecting to %s:%d\n",
+    //    sockAddr.getHostName(), port);
+
+    sock = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (sock == INVALID_SOCKET) {
+        int err = getSocketError();
+        LOG(LOG_ERROR, "socket", "Unable to create socket (err=%d)\n", err);
+        return (err != 0) ? err : -1;
+    }
+
+    connectTimer.start();
+
+    if (::connect(sock, (struct sockaddr*) &inaddr, sizeof(inaddr)) != 0) {
+        int err = getSocketError();
+        LOG(LOG_WARN, "socket", "Connect to %s:%d failed: %d\n",
+            sockAddr.getHostName(), port, err);
+        return (err != 0) ? err : -1;
+    }
+
+    connectTimer.stop();
+    if ((long) connectTimer.durationUsecs() > 100000) {
+        LOG(LOG_INFO, "socket",
+            "Connect to %s:%d took %.3fs\n", sockAddr.getHostName(),
+            port, ((long) connectTimer.durationUsecs()) / 1000000.0);
+    }
+
+    mSock = (unsigned long) sock;
+    LOG(LOG_VERBOSE, "socket",
+        "--- connected to %s:%d\n", sockAddr.getHostName(), port);
+    return 0;
+}
+
+
+/*
+ * Close the socket if it needs closing.
+ */
+bool Socket::close(void)
+{
+    if (mSock != UNDEF_SOCKET) {
+        //fprintf(stderr, "--- closing socket %lu\n", mSock);
+#ifdef HAVE_WINSOCK
+        if (::closesocket((SOCKET) mSock) != 0)
+            return false;
+#else
+        if (::close((int) mSock) != 0)
+            return false;
+#endif
+    }
+
+    mSock = UNDEF_SOCKET;
+
+    return true;
+}
+
+/*
+ * Read data from socket.
+ *
+ * Standard semantics: read up to "len" bytes into "buf".  Returns the
+ * number of bytes read, or less than zero on error.
+ */
+int Socket::read(void* buf, ssize_t len) const
+{
+    if (mSock == UNDEF_SOCKET) {
+        LOG(LOG_ERROR, "socket", "ERROR: read on invalid socket\n");
+        return -500;
+    }
+
+#ifdef HAVE_WINSOCK
+    SOCKET sock = (SOCKET) mSock;
+#else
+    int sock = (int) mSock;
+#endif
+    int cc;
+
+    cc = recv(sock, (char*)buf, len, 0);
+    if (cc < 0) {
+        int err = getSocketError();
+        return (err > 0) ? -err : -1;
+    }
+
+    return cc;
+}
+
+/*
+ * Write data to a socket.
+ *
+ * Standard semantics: write up to "len" bytes into "buf".  Returns the
+ * number of bytes written, or less than zero on error.
+ */
+int Socket::write(const void* buf, ssize_t len) const
+{
+    if (mSock == UNDEF_SOCKET) {
+        LOG(LOG_ERROR, "socket", "ERROR: write on invalid socket\n");
+        return -500;
+    }
+
+#ifdef HAVE_WINSOCK
+    SOCKET sock = (SOCKET) mSock;
+#else
+    int sock = (int) mSock;
+#endif
+    int cc;
+
+    cc = send(sock, (const char*)buf, len, 0);
+    if (cc < 0) {
+        int err = getSocketError();
+        return (err > 0) ? -err : -1;
+    }
+
+    return cc;
+}
+
+
+/*
+ * ===========================================================================
+ *      Socket tests
+ * ===========================================================================
+ */
+
+/*
+ * Read all data from the socket.  The data is read into a buffer that
+ * expands as needed.
+ *
+ * On exit, the buffer is returned, and the length of the data is stored
+ * in "*sz".  A null byte is added to the end, but is not included in
+ * the length.
+ */
+static char* socketReadAll(const Socket& s, int *sz)
+{
+    int max, r;
+    char *data, *ptr, *tmp;
+
+    data = (char*) malloc(max = 32768);
+    if (data == NULL)
+        return NULL;
+
+    ptr = data;
+    
+    for (;;) {
+        if ((ptr - data) == max) {
+            tmp = (char*) realloc(data, max *= 2);
+            if(tmp == 0) {
+                free(data);
+                return 0;
+            }
+        }
+        r = s.read(ptr, max - (ptr - data));
+        if (r == 0)
+            break;
+        if (r < 0) {
+            LOG(LOG_WARN, "socket", "WARNING: socket read failed (res=%d)\n",r);
+            break;
+        }
+        ptr += r;
+    }
+
+    if ((ptr - data) == max) {
+        tmp = (char*) realloc(data, max + 1);
+        if (tmp == NULL) {
+            free(data);
+            return NULL;
+        }
+    }
+    *ptr = '\0';
+    *sz = (ptr - data);
+    return data;
+}
+
+/*
+ * Exercise the Socket class.
+ */
+void android::TestSockets(void)
+{
+    printf("----- SOCKET TEST ------\n");
+    Socket::bootInit();
+
+    char* buf = NULL;
+    int len, cc;
+    const char* kTestStr =
+        "GET / HTTP/1.0\n"
+        "Connection: close\n"
+        "\n";
+
+    Socket sock;
+    if (sock.connect("www.google.com", 80) != 0) {
+        fprintf(stderr, "socket connected failed\n");
+        goto bail;
+    }
+
+    cc = sock.write(kTestStr, strlen(kTestStr));
+    if (cc != (int) strlen(kTestStr)) {
+        fprintf(stderr, "write failed, res=%d\n", cc);
+        goto bail;
+    }
+    buf = socketReadAll(sock, &len);
+
+    printf("GOT '%s'\n", buf);
+
+bail:
+    sock.close();
+    free(buf);
+}
+
diff --git a/libs/utils/Static.cpp b/libs/utils/Static.cpp
new file mode 100644
index 0000000..93f7e4f
--- /dev/null
+++ b/libs/utils/Static.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+// All static variables go here, to control initialization and
+// destruction order in the library.
+
+#include <private/utils/Static.h>
+
+#include <utils/BufferedTextOutput.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Log.h>
+
+namespace android {
+
+class LibUtilsFirstStatics
+{
+public:
+    LibUtilsFirstStatics()
+    {
+        initialize_string8();
+        initialize_string16();
+    }
+    
+    ~LibUtilsFirstStatics()
+    {
+        terminate_string16();
+        terminate_string8();
+    }
+};
+
+static LibUtilsFirstStatics gFirstStatics;
+int gDarwinCantLoadAllObjects = 1;
+
+// ------------ Text output streams
+
+Vector<int32_t> gTextBuffers;
+
+class LogTextOutput : public BufferedTextOutput
+{
+public:
+    LogTextOutput() : BufferedTextOutput(MULTITHREADED) { }
+    virtual ~LogTextOutput() { };
+
+protected:
+    virtual status_t writeLines(const struct iovec& vec, size_t N)
+    {
+        android_writevLog(&vec, N);
+        return NO_ERROR;
+    }
+};
+
+class FdTextOutput : public BufferedTextOutput
+{
+public:
+    FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { }
+    virtual ~FdTextOutput() { };
+
+protected:
+    virtual status_t writeLines(const struct iovec& vec, size_t N)
+    {
+        writev(mFD, &vec, N);
+        return NO_ERROR;
+    }
+
+private:
+    int mFD;
+};
+
+static LogTextOutput gLogTextOutput;
+static FdTextOutput gStdoutTextOutput(STDOUT_FILENO);
+static FdTextOutput gStderrTextOutput(STDERR_FILENO);
+
+TextOutput& alog(gLogTextOutput);
+TextOutput& aout(gStdoutTextOutput);
+TextOutput& aerr(gStderrTextOutput);
+
+#ifndef LIBUTILS_NATIVE
+
+// ------------ ProcessState.cpp
+
+Mutex gProcessMutex;
+sp<ProcessState> gProcess;
+
+class LibUtilsIPCtStatics
+{
+public:
+    LibUtilsIPCtStatics()
+    {
+    }
+    
+    ~LibUtilsIPCtStatics()
+    {
+        IPCThreadState::shutdown();
+    }
+};
+
+static LibUtilsIPCtStatics gIPCStatics;
+
+// ------------ ServiceManager.cpp
+
+Mutex gDefaultServiceManagerLock;
+sp<IServiceManager> gDefaultServiceManager;
+sp<IPermissionController> gPermissionController;
+
+#endif
+
+}   // namespace android
diff --git a/libs/utils/StopWatch.cpp b/libs/utils/StopWatch.cpp
new file mode 100644
index 0000000..68a1c52
--- /dev/null
+++ b/libs/utils/StopWatch.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "StopWatch"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/StopWatch.h>
+
+/*****************************************************************************/
+
+namespace android {
+
+
+StopWatch::StopWatch(const char *name, int clock, uint32_t flags)
+    :   mName(name), mClock(clock), mFlags(flags),
+        mStartTime(0), mNumLaps(0)
+{
+    mStartTime = systemTime(mClock);
+}
+
+StopWatch::~StopWatch()
+{
+    nsecs_t elapsed = elapsedTime();
+    const int n = mNumLaps;
+    LOGD("StopWatch %s (us): %lld ", mName, ns2us(elapsed));
+    for (int i=0 ; i<n ; i++) {
+        const nsecs_t soFar = mLaps[i].soFar;
+        const nsecs_t thisLap = mLaps[i].thisLap;
+        LOGD(" [%d: %lld, %lld]", i, ns2us(soFar), ns2us(thisLap));
+    }
+}
+
+const char* StopWatch::name() const
+{
+    return mName;
+}
+
+nsecs_t StopWatch::lap()
+{
+    nsecs_t elapsed = elapsedTime();
+    if (mNumLaps >= 8) {
+        elapsed = 0;
+    } else {
+        const int n = mNumLaps;
+        mLaps[n].soFar   = elapsed;
+        mLaps[n].thisLap = n ? (elapsed - mLaps[n-1].soFar) : elapsed;
+        mNumLaps = n+1;
+    }
+    return elapsed;
+}
+
+nsecs_t StopWatch::elapsedTime() const
+{
+    return systemTime(mClock) - mStartTime;
+}
+
+
+/*****************************************************************************/
+
+}; // namespace android
+
diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp
new file mode 100644
index 0000000..1f81cad
--- /dev/null
+++ b/libs/utils/String16.cpp
@@ -0,0 +1,609 @@
+/*
+ * Copyright (C) 2005 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 <utils/String16.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/TextOutput.h>
+#include <utils/threads.h>
+
+#include <private/utils/Static.h>
+
+#ifdef HAVE_WINSOCK
+# undef  nhtol
+# undef  htonl
+# undef  nhtos
+# undef  htons
+
+# ifdef HAVE_LITTLE_ENDIAN
+#  define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
+#  define htonl(x)    ntohl(x)
+#  define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
+#  define htons(x)    ntohs(x)
+# else
+#  define ntohl(x)    (x)
+#  define htonl(x)    (x)
+#  define ntohs(x)    (x)
+#  define htons(x)    (x)
+# endif
+#else
+# include <netinet/in.h>
+#endif
+
+#include <memory.h>
+#include <stdio.h>
+#include <ctype.h>
+
+// ---------------------------------------------------------------------------
+
+int strcmp16(const char16_t *s1, const char16_t *s2)
+{
+  char16_t ch;
+  int d = 0;
+
+  while ( 1 ) {
+    d = (int)(ch = *s1++) - (int)*s2++;
+    if ( d || !ch )
+      break;
+  }
+
+  return d;
+}
+
+int strncmp16(const char16_t *s1, const char16_t *s2, size_t n)
+{
+  char16_t ch;
+  int d = 0;
+
+  while ( n-- ) {
+    d = (int)(ch = *s1++) - (int)*s2++;
+    if ( d || !ch )
+      break;
+  }
+
+  return d;
+}
+
+char16_t *strcpy16(char16_t *dst, const char16_t *src)
+{
+  char16_t *q = dst;
+  const char16_t *p = src;
+  char16_t ch;
+
+  do {
+    *q++ = ch = *p++;
+  } while ( ch );
+
+  return dst;
+}
+
+size_t strlen16(const char16_t *s)
+{
+  const char16_t *ss = s;
+  while ( *ss )
+    ss++;
+  return ss-s;
+}
+
+
+char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n)
+{
+  char16_t *q = dst;
+  const char16_t *p = src;
+  char ch;
+
+  while (n) {
+    n--;
+    *q++ = ch = *p++;
+    if ( !ch )
+      break;
+  }
+
+  *q = 0;
+
+  return dst;
+}
+
+size_t strnlen16(const char16_t *s, size_t maxlen)
+{
+  const char16_t *ss = s;
+
+  /* Important: the maxlen test must precede the reference through ss;
+     since the byte beyond the maximum may segfault */
+  while ((maxlen > 0) && *ss) {
+    ss++;
+    maxlen--;
+  }
+  return ss-s;
+}
+
+int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2)
+{
+    const char16_t* e1 = s1+n1;
+    const char16_t* e2 = s2+n2;
+
+    while (s1 < e1 && s2 < e2) {
+        const int d = (int)*s1++ - (int)*s2++;
+        if (d) {
+            return d;
+        }
+    }
+
+    return n1 < n2
+        ? (0 - (int)*s2)
+        : (n1 > n2
+           ? ((int)*s1 - 0)
+           : 0);
+}
+
+int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2)
+{
+    const char16_t* e1 = s1H+n1;
+    const char16_t* e2 = s2N+n2;
+
+    while (s1H < e1 && s2N < e2) {
+        const char16_t c2 = ntohs(*s2N);
+        const int d = (int)*s1H++ - (int)c2;
+        s2N++;
+        if (d) {
+            return d;
+        }
+    }
+
+    return n1 < n2
+        ? (0 - (int)ntohs(*s2N))
+        : (n1 > n2
+           ? ((int)*s1H - 0)
+           : 0);
+}
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+static inline size_t
+utf8_char_len(uint8_t ch)
+{
+    return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1;
+}
+
+#define UTF8_SHIFT_AND_MASK(unicode, byte)  (unicode)<<=6; (unicode) |= (0x3f & (byte));
+
+static inline uint32_t
+utf8_to_utf32(const uint8_t *src, size_t length)
+{
+    uint32_t unicode;
+
+    switch (length)
+    {
+        case 1:
+            return src[0];
+        case 2:
+            unicode = src[0] & 0x1f;
+            UTF8_SHIFT_AND_MASK(unicode, src[1])
+            return unicode;
+        case 3:
+            unicode = src[0] & 0x0f;
+            UTF8_SHIFT_AND_MASK(unicode, src[1])
+            UTF8_SHIFT_AND_MASK(unicode, src[2])
+            return unicode;
+        case 4:
+            unicode = src[0] & 0x07;
+            UTF8_SHIFT_AND_MASK(unicode, src[1])
+            UTF8_SHIFT_AND_MASK(unicode, src[2])
+            UTF8_SHIFT_AND_MASK(unicode, src[3])
+            return unicode;
+        default:
+            return 0xffff;
+    }
+    
+    //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result);
+}
+
+// ---------------------------------------------------------------------------
+
+static SharedBuffer* gEmptyStringBuf = NULL;
+static char16_t* gEmptyString = NULL;
+
+static inline char16_t* getEmptyString()
+{
+    gEmptyStringBuf->acquire();
+   return gEmptyString;
+}
+
+void initialize_string16()
+{
+    SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
+    char16_t* str = (char16_t*)buf->data();
+    *str = 0;
+    gEmptyStringBuf = buf;
+    gEmptyString = str;
+}
+
+void terminate_string16()
+{
+    SharedBuffer::bufferFromData(gEmptyString)->release();
+    gEmptyStringBuf = NULL;
+    gEmptyString = NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+// Note: not dealing with generating surrogate pairs.
+static char16_t* allocFromUTF8(const char* in, size_t len)
+{
+    if (len == 0) return getEmptyString();
+    
+    size_t chars = 0;
+    const char* end = in+len;
+    const char* p = in;
+    
+    while (p < end) {
+        chars++;
+        p += utf8_char_len(*p);
+    }
+    
+    SharedBuffer* buf = SharedBuffer::alloc((chars+1)*sizeof(char16_t));
+    if (buf) {
+        p = in;
+        char16_t* str = (char16_t*)buf->data();
+        char16_t* d = str;
+        while (p < end) {
+            size_t len = utf8_char_len(*p);
+            *d++ = (char16_t)utf8_to_utf32((const uint8_t*)p, len);
+            p += len;
+        }
+        *d = 0;
+        
+        //printf("Created UTF-16 string from UTF-8 \"%s\":", in);
+        //printHexData(1, str, buf->size(), 16, 1);
+        //printf("\n");
+        
+        return str;
+    }
+    
+    return getEmptyString();
+}
+
+// ---------------------------------------------------------------------------
+
+String16::String16()
+    : mString(getEmptyString())
+{
+}
+
+String16::String16(const String16& o)
+    : mString(o.mString)
+{
+    SharedBuffer::bufferFromData(mString)->acquire();
+}
+
+String16::String16(const String16& o, size_t len, size_t begin)
+    : mString(getEmptyString())
+{
+    setTo(o, len, begin);
+}
+
+String16::String16(const char16_t* o)
+{
+    size_t len = strlen16(o);
+    SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
+    LOG_ASSERT(buf, "Unable to allocate shared buffer");
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        strcpy16(str, o);
+        mString = str;
+        return;
+    }
+    
+    mString = getEmptyString();
+}
+
+String16::String16(const char16_t* o, size_t len)
+{
+    SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
+    LOG_ASSERT(buf, "Unable to allocate shared buffer");
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        memcpy(str, o, len*sizeof(char16_t));
+        str[len] = 0;
+        mString = str;
+        return;
+    }
+    
+    mString = getEmptyString();
+}
+
+String16::String16(const String8& o)
+    : mString(allocFromUTF8(o.string(), o.size()))
+{
+}
+
+String16::String16(const char* o)
+    : mString(allocFromUTF8(o, strlen(o)))
+{
+}
+
+String16::String16(const char* o, size_t len)
+    : mString(allocFromUTF8(o, len))
+{
+}
+
+String16::~String16()
+{
+    SharedBuffer::bufferFromData(mString)->release();
+}
+
+void String16::setTo(const String16& other)
+{
+    SharedBuffer::bufferFromData(other.mString)->acquire();
+    SharedBuffer::bufferFromData(mString)->release();
+    mString = other.mString;
+}
+
+status_t String16::setTo(const String16& other, size_t len, size_t begin)
+{
+    const size_t N = other.size();
+    if (begin >= N) {
+        SharedBuffer::bufferFromData(mString)->release();
+        mString = getEmptyString();
+        return NO_ERROR;
+    }
+    if ((begin+len) > N) len = N-begin;
+    if (begin == 0 && len == N) {
+        setTo(other);
+        return NO_ERROR;
+    }
+
+    if (&other == this) {
+        LOG_ALWAYS_FATAL("Not implemented");
+    }
+
+    return setTo(other.string()+begin, len);
+}
+
+status_t String16::setTo(const char16_t* other)
+{
+    return setTo(other, strlen16(other));
+}
+
+status_t String16::setTo(const char16_t* other, size_t len)
+{
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((len+1)*sizeof(char16_t));
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        memcpy(str, other, len*sizeof(char16_t));
+        str[len] = 0;
+        mString = str;
+        return NO_ERROR;
+    }
+    return NO_MEMORY;
+}
+
+status_t String16::append(const String16& other)
+{
+    const size_t myLen = size();
+    const size_t otherLen = other.size();
+    if (myLen == 0) {
+        setTo(other);
+        return NO_ERROR;
+    } else if (otherLen == 0) {
+        return NO_ERROR;
+    }
+    
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((myLen+otherLen+1)*sizeof(char16_t));
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t));
+        mString = str;
+        return NO_ERROR;
+    }
+    return NO_MEMORY;
+}
+
+status_t String16::append(const char16_t* chrs, size_t otherLen)
+{
+    const size_t myLen = size();
+    if (myLen == 0) {
+        setTo(chrs, otherLen);
+        return NO_ERROR;
+    } else if (otherLen == 0) {
+        return NO_ERROR;
+    }
+    
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((myLen+otherLen+1)*sizeof(char16_t));
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        memcpy(str+myLen, chrs, otherLen*sizeof(char16_t));
+        str[myLen+otherLen] = 0;
+        mString = str;
+        return NO_ERROR;
+    }
+    return NO_MEMORY;
+}
+
+status_t String16::insert(size_t pos, const char16_t* chrs)
+{
+    return insert(pos, chrs, strlen16(chrs));
+}
+
+status_t String16::insert(size_t pos, const char16_t* chrs, size_t len)
+{
+    const size_t myLen = size();
+    if (myLen == 0) {
+        return setTo(chrs, len);
+        return NO_ERROR;
+    } else if (len == 0) {
+        return NO_ERROR;
+    }
+
+    if (pos > myLen) pos = myLen;
+
+    #if 0
+    printf("Insert in to %s: pos=%d, len=%d, myLen=%d, chrs=%s\n",
+           String8(*this).string(), pos,
+           len, myLen, String8(chrs, len).string());
+    #endif
+
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((myLen+len+1)*sizeof(char16_t));
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        if (pos < myLen) {
+            memmove(str+pos+len, str+pos, (myLen-pos)*sizeof(char16_t));
+        }
+        memcpy(str+pos, chrs, len*sizeof(char16_t));
+        str[myLen+len] = 0;
+        mString = str;
+        #if 0
+        printf("Result (%d chrs): %s\n", size(), String8(*this).string());
+        #endif
+        return NO_ERROR;
+    }
+    return NO_MEMORY;
+}
+
+ssize_t String16::findFirst(char16_t c) const
+{
+    const char16_t* str = string();
+    const char16_t* p = str;
+    const char16_t* e = p + size();
+    while (p < e) {
+        if (*p == c) {
+            return p-str;
+        }
+        p++;
+    }
+    return -1;
+}
+
+ssize_t String16::findLast(char16_t c) const
+{
+    const char16_t* str = string();
+    const char16_t* p = str;
+    const char16_t* e = p + size();
+    while (p < e) {
+        e--;
+        if (*e == c) {
+            return e-str;
+        }
+    }
+    return -1;
+}
+
+bool String16::startsWith(const String16& prefix) const
+{
+    const size_t ps = prefix.size();
+    if (ps > size()) return false;
+    return strzcmp16(mString, ps, prefix.string(), ps) == 0;
+}
+
+bool String16::startsWith(const char16_t* prefix) const
+{
+    const size_t ps = strlen16(prefix);
+    if (ps > size()) return false;
+    return strncmp16(mString, prefix, ps) == 0;
+}
+
+status_t String16::makeLower()
+{
+    const size_t N = size();
+    const char16_t* str = string();
+    char16_t* edit = NULL;
+    for (size_t i=0; i<N; i++) {
+        const char16_t v = str[i];
+        if (v >= 'A' && v <= 'Z') {
+            if (!edit) {
+                SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
+                if (!buf) {
+                    return NO_MEMORY;
+                }
+                edit = (char16_t*)buf->data();
+                mString = str = edit;
+            }
+            edit[i] = tolower((char)v);
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
+{
+    const size_t N = size();
+    const char16_t* str = string();
+    char16_t* edit = NULL;
+    for (size_t i=0; i<N; i++) {
+        if (str[i] == replaceThis) {
+            if (!edit) {
+                SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
+                if (!buf) {
+                    return NO_MEMORY;
+                }
+                edit = (char16_t*)buf->data();
+                mString = str = edit;
+            }
+            edit[i] = withThis;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t String16::remove(size_t len, size_t begin)
+{
+    const size_t N = size();
+    if (begin >= N) {
+        SharedBuffer::bufferFromData(mString)->release();
+        mString = getEmptyString();
+        return NO_ERROR;
+    }
+    if ((begin+len) > N) len = N-begin;
+    if (begin == 0 && len == N) {
+        return NO_ERROR;
+    }
+
+    if (begin > 0) {
+        SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+            ->editResize((N+1)*sizeof(char16_t));
+        if (!buf) {
+            return NO_MEMORY;
+        }
+        char16_t* str = (char16_t*)buf->data();
+        memmove(str, str+begin, (N-begin+1)*sizeof(char16_t));
+        mString = str;
+    }
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((len+1)*sizeof(char16_t));
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        str[len] = 0;
+        mString = str;
+        return NO_ERROR;
+    }
+    return NO_MEMORY;
+}
+
+TextOutput& operator<<(TextOutput& to, const String16& val)
+{
+    to << String8(val).string();
+    return to;
+}
+
+}; // namespace android
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
new file mode 100644
index 0000000..c50d343
--- /dev/null
+++ b/libs/utils/String8.cpp
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2005 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 <utils/String8.h>
+
+#include <utils/Log.h>
+#include <utils/String16.h>
+#include <utils/TextOutput.h>
+#include <utils/threads.h>
+
+#include <private/utils/Static.h>
+
+#include <ctype.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+static const uint32_t kByteMask = 0x000000BF;
+static const uint32_t kByteMark = 0x00000080;
+
+// Surrogates aren't valid for UTF-32 characters, so define some
+// constants that will let us screen them out.
+static const uint32_t kUnicodeSurrogateHighStart  = 0x0000D800;
+static const uint32_t kUnicodeSurrogateHighEnd    = 0x0000DBFF;
+static const uint32_t kUnicodeSurrogateLowStart   = 0x0000DC00;
+static const uint32_t kUnicodeSurrogateLowEnd     = 0x0000DFFF;
+static const uint32_t kUnicodeSurrogateStart      = kUnicodeSurrogateHighStart;
+static const uint32_t kUnicodeSurrogateEnd        = kUnicodeSurrogateLowEnd;
+
+// Mask used to set appropriate bits in first byte of UTF-8 sequence,
+// indexed by number of bytes in the sequence.
+static const uint32_t kFirstByteMark[] = {
+    0x00000000, 0x00000000, 0x000000C0, 0x000000E0, 0x000000F0
+};
+
+// Separator used by resource paths. This is not platform dependent contrary
+// to OS_PATH_SEPARATOR.
+#define RES_PATH_SEPARATOR '/'
+
+// Return number of utf8 bytes required for the character.
+static size_t utf32_to_utf8_bytes(uint32_t srcChar)
+{
+    size_t bytesToWrite;
+
+    // Figure out how many bytes the result will require.
+    if (srcChar < 0x00000080)
+    {
+        bytesToWrite = 1;
+    }
+    else if (srcChar < 0x00000800)
+    {
+        bytesToWrite = 2;
+    }
+    else if (srcChar < 0x00010000)
+    {
+        if ((srcChar < kUnicodeSurrogateStart)
+         || (srcChar > kUnicodeSurrogateEnd))
+        {
+            bytesToWrite = 3;
+        }
+        else
+        {
+            // Surrogates are invalid UTF-32 characters.
+            return 0;
+        }
+    }
+    // Max code point for Unicode is 0x0010FFFF.
+    else if (srcChar < 0x00110000)
+    {
+        bytesToWrite = 4;
+    }
+    else
+    {
+        // Invalid UTF-32 character.
+        return 0;
+    }
+
+    return bytesToWrite;
+}
+
+// Write out the source character to <dstP>.
+
+static void utf32_to_utf8(uint8_t* dstP, uint32_t srcChar, size_t bytes)
+{
+    dstP += bytes;
+    switch (bytes)
+    {   /* note: everything falls through. */
+        case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+        case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+        case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+        case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]);
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+static SharedBuffer* gEmptyStringBuf = NULL;
+static char* gEmptyString = NULL;
+
+extern int gDarwinCantLoadAllObjects;
+int gDarwinIsReallyAnnoying;
+
+static inline char* getEmptyString()
+{
+    gEmptyStringBuf->acquire();
+    return gEmptyString;
+}
+
+void initialize_string8()
+{
+#ifdef LIBUTILS_NATIVE
+	  // Bite me, Darwin!
+		gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
+#endif
+			
+    SharedBuffer* buf = SharedBuffer::alloc(1);
+    char* str = (char*)buf->data();
+    *str = 0;
+    gEmptyStringBuf = buf;
+    gEmptyString = str;
+}
+
+void terminate_string8()
+{
+    SharedBuffer::bufferFromData(gEmptyString)->release();
+    gEmptyStringBuf = NULL;
+    gEmptyString = NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+static char* allocFromUTF8(const char* in, size_t len)
+{
+    if (len > 0) {
+        SharedBuffer* buf = SharedBuffer::alloc(len+1);
+        LOG_ASSERT(buf, "Unable to allocate shared buffer");
+        if (buf) {
+            char* str = (char*)buf->data();
+            memcpy(str, in, len);
+            str[len] = 0;
+            return str;
+        }
+        return NULL;
+    }
+
+    return getEmptyString();
+}
+
+// Note: not dealing with expanding surrogate pairs.
+static char* allocFromUTF16(const char16_t* in, size_t len)
+{
+    if (len == 0) return getEmptyString();
+    
+    size_t bytes = 0;
+    const char16_t* end = in+len;
+    const char16_t* p = in;
+    
+    while (p < end) {
+        bytes += utf32_to_utf8_bytes(*p);
+        p++;
+    }
+    
+    SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+    LOG_ASSERT(buf, "Unable to allocate shared buffer");
+    if (buf) {
+        p = in;
+        char* str = (char*)buf->data();
+        char* d = str;
+        while (p < end) {
+            uint32_t c = *p++;
+            size_t len = utf32_to_utf8_bytes(c);
+            utf32_to_utf8((uint8_t*)d, c, len);
+            d += len;
+        }
+        *d = 0;
+        
+        return str;
+    }
+    
+    return getEmptyString();
+}
+
+// ---------------------------------------------------------------------------
+
+String8::String8()
+    : mString(getEmptyString())
+{
+}
+
+String8::String8(const String8& o)
+    : mString(o.mString)
+{
+    SharedBuffer::bufferFromData(mString)->acquire();
+}
+
+String8::String8(const char* o)
+    : mString(allocFromUTF8(o, strlen(o)))
+{
+    if (mString == NULL) {
+        mString = getEmptyString();
+    }
+}
+
+String8::String8(const char* o, size_t len)
+    : mString(allocFromUTF8(o, len))
+{
+    if (mString == NULL) {
+        mString = getEmptyString();
+    }
+}
+
+String8::String8(const String16& o)
+    : mString(allocFromUTF16(o.string(), o.size()))
+{
+}
+
+String8::String8(const char16_t* o)
+    : mString(allocFromUTF16(o, strlen16(o)))
+{
+}
+
+String8::String8(const char16_t* o, size_t len)
+    : mString(allocFromUTF16(o, len))
+{
+}
+
+String8::~String8()
+{
+    SharedBuffer::bufferFromData(mString)->release();
+}
+
+void String8::setTo(const String8& other)
+{
+    SharedBuffer::bufferFromData(other.mString)->acquire();
+    SharedBuffer::bufferFromData(mString)->release();
+    mString = other.mString;
+}
+
+status_t String8::setTo(const char* other)
+{
+    SharedBuffer::bufferFromData(mString)->release();
+    mString = allocFromUTF8(other, strlen(other));
+    if (mString) return NO_ERROR;
+
+    mString = getEmptyString();
+    return NO_MEMORY;
+}
+
+status_t String8::setTo(const char* other, size_t len)
+{
+    SharedBuffer::bufferFromData(mString)->release();
+    mString = allocFromUTF8(other, len);
+    if (mString) return NO_ERROR;
+
+    mString = getEmptyString();
+    return NO_MEMORY;
+}
+
+status_t String8::setTo(const char16_t* other, size_t len)
+{
+    SharedBuffer::bufferFromData(mString)->release();
+    mString = allocFromUTF16(other, len);
+    if (mString) return NO_ERROR;
+
+    mString = getEmptyString();
+    return NO_MEMORY;
+}
+
+status_t String8::append(const String8& other)
+{
+    const size_t otherLen = other.bytes();
+    if (bytes() == 0) {
+        setTo(other);
+        return NO_ERROR;
+    } else if (otherLen == 0) {
+        return NO_ERROR;
+    }
+
+    return real_append(other.string(), otherLen);
+}
+
+status_t String8::append(const char* other)
+{
+    return append(other, strlen(other));
+}
+
+status_t String8::append(const char* other, size_t otherLen)
+{
+    if (bytes() == 0) {
+        return setTo(other, otherLen);
+    } else if (otherLen == 0) {
+        return NO_ERROR;
+    }
+
+    return real_append(other, otherLen);
+}
+
+status_t String8::real_append(const char* other, size_t otherLen)
+{
+    const size_t myLen = bytes();
+    
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize(myLen+otherLen+1);
+    if (buf) {
+        char* str = (char*)buf->data();
+        mString = str;
+        str += myLen;
+        memcpy(str, other, otherLen);
+        str[otherLen] = '\0';
+        return NO_ERROR;
+    }
+    return NO_MEMORY;
+}
+
+char* String8::lockBuffer(size_t size)
+{
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize(size+1);
+    if (buf) {
+        char* str = (char*)buf->data();
+        mString = str;
+        return str;
+    }
+    return NULL;
+}
+
+void String8::unlockBuffer()
+{
+    unlockBuffer(strlen(mString));
+}
+
+status_t String8::unlockBuffer(size_t size)
+{
+    if (size != this->size()) {
+        SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+            ->editResize(size+1);
+        if (buf) {
+            char* str = (char*)buf->data();
+            str[size] = 0;
+            mString = str;
+            return NO_ERROR;
+        }
+    }
+    
+    return NO_MEMORY;
+}
+
+ssize_t String8::find(const char* other, size_t start) const
+{
+    size_t len = size();
+    if (start >= len) {
+        return -1;
+    }
+    const char* s = mString+start;
+    const char* p = strstr(s, other);
+    return p ? p-mString : -1;
+}
+
+void String8::toLower()
+{
+    toLower(0, size());
+}
+
+void String8::toLower(size_t start, size_t length)
+{
+    const size_t len = size();
+    if (start >= len) {
+        return;
+    }
+    if (start+length > len) {
+        length = len-start;
+    }
+    char* buf = lockBuffer(len);
+    buf += start;
+    while (length > 0) {
+        *buf = tolower(*buf);
+        buf++;
+        length--;
+    }
+    unlockBuffer(len);
+}
+
+void String8::toUpper()
+{
+    toUpper(0, size());
+}
+
+void String8::toUpper(size_t start, size_t length)
+{
+    const size_t len = size();
+    if (start >= len) {
+        return;
+    }
+    if (start+length > len) {
+        length = len-start;
+    }
+    char* buf = lockBuffer(len);
+    buf += start;
+    while (length > 0) {
+        *buf = toupper(*buf);
+        buf++;
+        length--;
+    }
+    unlockBuffer(len);
+}
+
+TextOutput& operator<<(TextOutput& to, const String8& val)
+{
+    to << val.string();
+    return to;
+}
+
+// ---------------------------------------------------------------------------
+// Path functions
+
+
+void String8::setPathName(const char* name)
+{
+    setPathName(name, strlen(name));
+}
+
+void String8::setPathName(const char* name, size_t len)
+{
+    char* buf = lockBuffer(len);
+
+    memcpy(buf, name, len);
+
+    // remove trailing path separator, if present
+    if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
+        len--;
+
+    buf[len] = '\0';
+
+    unlockBuffer(len);
+}
+
+String8 String8::getPathLeaf(void) const
+{
+    const char* cp;
+    const char*const buf = mString;
+
+    cp = strrchr(buf, OS_PATH_SEPARATOR);
+    if (cp == NULL)
+        return String8(*this);
+    else
+        return String8(cp+1);
+}
+
+String8 String8::getPathDir(void) const
+{
+    const char* cp;
+    const char*const str = mString;
+
+    cp = strrchr(str, OS_PATH_SEPARATOR);
+    if (cp == NULL)
+        return String8("");
+    else
+        return String8(str, cp - str);
+}
+
+String8 String8::walkPath(String8* outRemains) const
+{
+    const char* cp;
+    const char*const str = mString;
+    const char* buf = str;
+
+    cp = strchr(buf, OS_PATH_SEPARATOR);
+    if (cp == buf) {
+        // don't include a leading '/'.
+        buf = buf+1;
+        cp = strchr(buf, OS_PATH_SEPARATOR);
+    }
+
+    if (cp == NULL) {
+        String8 res = buf != str ? String8(buf) : *this;
+        if (outRemains) *outRemains = String8("");
+        return res;
+    }
+
+    String8 res(buf, cp-buf);
+    if (outRemains) *outRemains = String8(cp+1);
+    return res;
+}
+
+/*
+ * Helper function for finding the start of an extension in a pathname.
+ *
+ * Returns a pointer inside mString, or NULL if no extension was found.
+ */
+char* String8::find_extension(void) const
+{
+    const char* lastSlash;
+    const char* lastDot;
+    int extLen;
+    const char* const str = mString;
+
+    // only look at the filename
+    lastSlash = strrchr(str, OS_PATH_SEPARATOR);
+    if (lastSlash == NULL)
+        lastSlash = str;
+    else
+        lastSlash++;
+
+    // find the last dot
+    lastDot = strrchr(lastSlash, '.');
+    if (lastDot == NULL)
+        return NULL;
+
+    // looks good, ship it
+    return const_cast<char*>(lastDot);
+}
+
+String8 String8::getPathExtension(void) const
+{
+    char* ext;
+
+    ext = find_extension();
+    if (ext != NULL)
+        return String8(ext);
+    else
+        return String8("");
+}
+
+String8 String8::getBasePath(void) const
+{
+    char* ext;
+    const char* const str = mString;
+
+    ext = find_extension();
+    if (ext == NULL)
+        return String8(*this);
+    else
+        return String8(str, ext - str);
+}
+
+String8& String8::appendPath(const char* name)
+{
+    // TODO: The test below will fail for Win32 paths. Fix later or ignore.
+    if (name[0] != OS_PATH_SEPARATOR) {
+        if (*name == '\0') {
+            // nothing to do
+            return *this;
+        }
+
+        size_t len = length();
+        if (len == 0) {
+            // no existing filename, just use the new one
+            setPathName(name);
+            return *this;
+        }
+
+        // make room for oldPath + '/' + newPath
+        int newlen = strlen(name);
+
+        char* buf = lockBuffer(len+1+newlen);
+
+        // insert a '/' if needed
+        if (buf[len-1] != OS_PATH_SEPARATOR)
+            buf[len++] = OS_PATH_SEPARATOR;
+
+        memcpy(buf+len, name, newlen+1);
+        len += newlen;
+
+        unlockBuffer(len);
+
+        return *this;
+    } else {
+        setPathName(name);
+        return *this;
+    }
+}
+
+String8& String8::convertToResPath()
+{
+#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
+    size_t len = length();
+    if (len > 0) {
+        char * buf = lockBuffer(len);
+        for (char * end = buf + len; buf < end; ++buf) {
+            if (*buf == OS_PATH_SEPARATOR)
+                *buf = RES_PATH_SEPARATOR;
+        }
+        unlockBuffer(len);
+    }
+#endif
+    return *this;
+}
+
+
+}; // namespace android
diff --git a/libs/utils/SystemClock.cpp b/libs/utils/SystemClock.cpp
new file mode 100644
index 0000000..2bdc0ce
--- /dev/null
+++ b/libs/utils/SystemClock.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+
+/*
+ * System clock functions.
+ */
+
+#if HAVE_ANDROID_OS
+#include <linux/ioctl.h>
+#include <linux/rtc.h>
+#include <utils/Atomic.h>
+#include <linux/android_alarm.h>
+#endif
+
+#include <sys/time.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include <utils/SystemClock.h>
+#include <utils/Timers.h>
+
+#define LOG_TAG "SystemClock"
+#include "utils/Log.h"
+
+namespace android {
+
+/*
+ * Set the current time.  This only works when running as root.
+ */
+int setCurrentTimeMillis(int64_t millis)
+{
+#if WIN32
+    // not implemented
+    return -1;
+#else
+    struct timeval tv;
+#if HAVE_ANDROID_OS
+    struct timespec ts;
+    int fd;
+    int res;
+#endif
+    int ret = 0;
+
+    if (millis <= 0 || millis / 1000LL >= INT_MAX) {
+        return -1;
+    }
+
+    tv.tv_sec = (time_t) (millis / 1000LL);
+    tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);
+
+    LOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
+
+#if HAVE_ANDROID_OS
+    fd = open("/dev/alarm", O_RDWR);
+    if(fd < 0) {
+        LOGW("Unable to open alarm driver: %s\n", strerror(errno));
+        return -1;
+    }
+    ts.tv_sec = tv.tv_sec;
+    ts.tv_nsec = tv.tv_usec * 1000;
+    res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
+    if(res < 0) {
+        LOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
+        ret = -1;
+    }
+    close(fd);
+#else
+    if (settimeofday(&tv, NULL) != 0) {
+        LOGW("Unable to set clock to %d.%d: %s\n",
+            (int) tv.tv_sec, (int) tv.tv_usec, strerror(errno));
+        ret = -1;
+    }
+#endif
+
+    return ret;
+#endif // WIN32
+}
+
+/*
+ * native public static long uptimeMillis();
+ */
+int64_t uptimeMillis()
+{
+    int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+    return (int64_t) nanoseconds_to_milliseconds(when);
+}
+
+/*
+ * native public static long elapsedRealtime();
+ */
+int64_t elapsedRealtime()
+{
+#if HAVE_ANDROID_OS
+    static int s_fd = -1;
+
+    if (s_fd == -1) {
+        int fd = open("/dev/alarm", O_RDONLY);
+        if (android_atomic_cmpxchg(-1, fd, &s_fd)) {
+            close(fd);
+        }
+    }
+
+    struct timespec ts;
+    int result = ioctl(s_fd,
+            ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts);
+
+    if (result == 0) {
+        int64_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+        return (int64_t) nanoseconds_to_milliseconds(when);
+    } else {
+        // XXX: there was an error, probably because the driver didn't
+        // exist ... this should return
+        // a real error, like an exception!
+        int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+        return (int64_t) nanoseconds_to_milliseconds(when);
+    }
+#else
+    int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+    return (int64_t) nanoseconds_to_milliseconds(when);
+#endif
+}
+
+}; // namespace android
diff --git a/libs/utils/TextOutput.cpp b/libs/utils/TextOutput.cpp
new file mode 100644
index 0000000..cebee99
--- /dev/null
+++ b/libs/utils/TextOutput.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005 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 <utils/TextOutput.h>
+
+#include <utils/Debug.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+TextOutput& operator<<(TextOutput& to, bool val)
+{
+    if (val) to.print("true", 4);
+    else to.print("false", 5);
+    return to;
+}
+
+TextOutput& operator<<(TextOutput& to, int val)
+{
+    char buf[16];
+    sprintf(buf, "%d", val);
+    to.print(buf, strlen(buf));
+    return to;
+}
+
+TextOutput& operator<<(TextOutput& to, long val)
+{
+    char buf[16];
+    sprintf(buf, "%ld", val);
+    to.print(buf, strlen(buf));
+    return to;
+}
+
+TextOutput& operator<<(TextOutput& to, unsigned int val)
+{
+    char buf[16];
+    sprintf(buf, "%u", val);
+    to.print(buf, strlen(buf));
+    return to;
+}
+
+TextOutput& operator<<(TextOutput& to, unsigned long val)
+{
+    char buf[16];
+    sprintf(buf, "%lu", val);
+    to.print(buf, strlen(buf));
+    return to;
+}
+
+TextOutput& operator<<(TextOutput& to, long long val)
+{
+    char buf[32];
+    sprintf(buf, "%Ld", val);
+    to.print(buf, strlen(buf));
+    return to;
+}
+
+TextOutput& operator<<(TextOutput& to, unsigned long long val)
+{
+    char buf[32];
+    sprintf(buf, "%Lu", val);
+    to.print(buf, strlen(buf));
+    return to;
+}
+
+static TextOutput& print_float(TextOutput& to, double value)
+{
+    char buf[64];
+    sprintf(buf, "%g", value);
+    if( !strchr(buf, '.') && !strchr(buf, 'e') &&
+        !strchr(buf, 'E') ) {
+        strncat(buf, ".0", sizeof(buf)-1);
+    }
+    to.print(buf, strlen(buf));
+    return to;
+}
+
+TextOutput& operator<<(TextOutput& to, float val)
+{
+    return print_float(to,val);
+}
+
+TextOutput& operator<<(TextOutput& to, double val)
+{
+    return print_float(to,val);
+}
+
+TextOutput& operator<<(TextOutput& to, const void* val)
+{
+    char buf[16];
+    sprintf(buf, "%p", val);
+    to.print(buf, strlen(buf));
+    return to;
+}
+
+static void textOutputPrinter(void* cookie, const char* txt)
+{
+    ((TextOutput*)cookie)->print(txt, strlen(txt));
+}
+
+TextOutput& operator<<(TextOutput& to, const TypeCode& val)
+{
+    printTypeCode(val.typeCode(), textOutputPrinter, (void*)&to);
+    return to;
+}
+
+HexDump::HexDump(const void *buf, size_t size, size_t bytesPerLine)
+    : mBuffer(buf)
+    , mSize(size)
+    , mBytesPerLine(bytesPerLine)
+    , mSingleLineCutoff(16)
+    , mAlignment(4)
+    , mCArrayStyle(false)
+{
+    if (bytesPerLine >= 16) mAlignment = 4;
+    else if (bytesPerLine >= 8) mAlignment = 2;
+    else mAlignment = 1;
+}
+
+TextOutput& operator<<(TextOutput& to, const HexDump& val)
+{
+    printHexData(0, val.buffer(), val.size(), val.bytesPerLine(),
+        val.singleLineCutoff(), val.alignment(), val.carrayStyle(),
+        textOutputPrinter, (void*)&to);
+    return to;
+}
+
+}; // namespace android
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
new file mode 100644
index 0000000..5f407a9
--- /dev/null
+++ b/libs/utils/Threads.cpp
@@ -0,0 +1,1128 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "libutils.threads"
+
+#include <utils/threads.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+# include <sched.h>
+# include <sys/resource.h>
+#elif defined(HAVE_WIN32_THREADS)
+# include <windows.h>
+# include <stdint.h>
+# include <process.h>
+# define HAVE_CREATETHREAD  // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW
+#endif
+
+#if defined(HAVE_FUTEX)
+#include <private/utils/futex_synchro.h>
+#endif
+
+#if defined(HAVE_PRCTL)
+#include <sys/prctl.h>
+#endif
+
+/*
+ * ===========================================================================
+ *      Thread wrappers
+ * ===========================================================================
+ */
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+#if defined(HAVE_PTHREADS)
+#if 0
+#pragma mark -
+#pragma mark PTHREAD
+#endif
+// ----------------------------------------------------------------------------
+
+/*
+ * Create and run a new thead.
+ *
+ * We create it "detached", so it cleans up after itself.
+ */
+
+typedef void* (*android_pthread_entry)(void*);
+
+struct thread_data_t {
+    thread_func_t   entryFunction;
+    void*           userData;
+    int             priority;
+    char *          threadName;
+
+    // we use this trampoline when we need to set the priority with
+    // nice/setpriority.
+    static int trampoline(const thread_data_t* t) {
+        thread_func_t f = t->entryFunction;
+        void* u = t->userData;
+        int prio = t->priority;
+        char * name = t->threadName;
+        delete t;
+        setpriority(PRIO_PROCESS, 0, prio);
+        if (name) {
+#if defined(HAVE_PRCTL)
+            // Mac OS doesn't have this, and we build libutil for the host too
+            int hasAt = 0;
+            int hasDot = 0;
+            char *s = name;
+            while (*s) {
+                if (*s == '.') hasDot = 1;
+                else if (*s == '@') hasAt = 1;
+                s++;
+            }
+            int len = s - name;
+            if (len < 15 || hasAt || !hasDot) {
+                s = name;
+            } else {
+                s = name + len - 15;
+            }
+            prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0);
+#endif
+            free(name);
+        }
+        return f(u);
+    }
+};
+
+int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
+                               void *userData,
+                               const char* threadName,
+                               int32_t threadPriority,
+                               size_t threadStackSize,
+                               android_thread_id_t *threadId)
+{
+    pthread_attr_t attr; 
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+#ifdef HAVE_ANDROID_OS  /* valgrind is rejecting RT-priority create reqs */
+    if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
+        // We could avoid the trampoline if there was a way to get to the
+        // android_thread_id_t (pid) from pthread_t
+        thread_data_t* t = new thread_data_t;
+        t->priority = threadPriority;
+        t->threadName = threadName ? strdup(threadName) : NULL;
+        t->entryFunction = entryFunction;
+        t->userData = userData;
+        entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
+        userData = t;            
+    }
+#endif
+
+    if (threadStackSize) {
+        pthread_attr_setstacksize(&attr, threadStackSize);
+    }
+    
+    errno = 0;
+    pthread_t thread;
+    int result = pthread_create(&thread, &attr,
+                    (android_pthread_entry)entryFunction, userData);
+    if (result != 0) {
+        LOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n"
+             "(android threadPriority=%d)",
+            entryFunction, result, errno, threadPriority);
+        return 0;
+    }
+
+    if (threadId != NULL) {
+        *threadId = (android_thread_id_t)thread; // XXX: this is not portable
+    }
+    return 1;
+}
+
+android_thread_id_t androidGetThreadId()
+{
+    return (android_thread_id_t)pthread_self();
+}
+
+// ----------------------------------------------------------------------------
+#elif defined(HAVE_WIN32_THREADS)
+#if 0
+#pragma mark -
+#pragma mark WIN32_THREADS
+#endif
+// ----------------------------------------------------------------------------
+
+/*
+ * Trampoline to make us __stdcall-compliant.
+ *
+ * We're expected to delete "vDetails" when we're done.
+ */
+struct threadDetails {
+    int (*func)(void*);
+    void* arg;
+};
+static __stdcall unsigned int threadIntermediary(void* vDetails)
+{
+    struct threadDetails* pDetails = (struct threadDetails*) vDetails;
+    int result;
+
+    result = (*(pDetails->func))(pDetails->arg);
+
+    delete pDetails;
+
+    LOG(LOG_VERBOSE, "thread", "thread exiting\n");
+    return (unsigned int) result;
+}
+
+/*
+ * Create and run a new thread.
+ */
+static bool doCreateThread(android_thread_func_t fn, void* arg, android_thread_id_t *id)
+{
+    HANDLE hThread;
+    struct threadDetails* pDetails = new threadDetails; // must be on heap
+    unsigned int thrdaddr;
+
+    pDetails->func = fn;
+    pDetails->arg = arg;
+
+#if defined(HAVE__BEGINTHREADEX)
+    hThread = (HANDLE) _beginthreadex(NULL, 0, threadIntermediary, pDetails, 0,
+                    &thrdaddr);
+    if (hThread == 0)
+#elif defined(HAVE_CREATETHREAD)
+    hThread = CreateThread(NULL, 0,
+                    (LPTHREAD_START_ROUTINE) threadIntermediary,
+                    (void*) pDetails, 0, (DWORD*) &thrdaddr);
+    if (hThread == NULL)
+#endif
+    {
+        LOG(LOG_WARN, "thread", "WARNING: thread create failed\n");
+        return false;
+    }
+
+#if defined(HAVE_CREATETHREAD)
+    /* close the management handle */
+    CloseHandle(hThread);
+#endif
+
+    if (id != NULL) {
+      	*id = (android_thread_id_t)thrdaddr;
+    }
+
+    return true;
+}
+
+int androidCreateRawThreadEtc(android_thread_func_t fn,
+                               void *userData,
+                               const char* threadName,
+                               int32_t threadPriority,
+                               size_t threadStackSize,
+                               android_thread_id_t *threadId)
+{
+    return doCreateThread(  fn, userData, threadId);
+}
+
+android_thread_id_t androidGetThreadId()
+{
+    return (android_thread_id_t)GetCurrentThreadId();
+}
+
+// ----------------------------------------------------------------------------
+#else
+#error "Threads not supported"
+#endif
+
+// ----------------------------------------------------------------------------
+
+#if 0
+#pragma mark -
+#pragma mark Common Thread functions
+#endif
+
+int androidCreateThread(android_thread_func_t fn, void* arg)
+{
+    return createThreadEtc(fn, arg);
+}
+
+int androidCreateThreadGetID(android_thread_func_t fn, void *arg, android_thread_id_t *id)
+{
+    return createThreadEtc(fn, arg, "android:unnamed_thread",
+                           PRIORITY_DEFAULT, 0, id);
+}
+
+static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;
+
+int androidCreateThreadEtc(android_thread_func_t entryFunction,
+                            void *userData,
+                            const char* threadName,
+                            int32_t threadPriority,
+                            size_t threadStackSize,
+                            android_thread_id_t *threadId)
+{
+    return gCreateThreadFn(entryFunction, userData, threadName,
+        threadPriority, threadStackSize, threadId);
+}
+
+void androidSetCreateThreadFunc(android_create_thread_fn func)
+{
+    gCreateThreadFn = func;
+}
+
+namespace android {
+
+/*
+ * ===========================================================================
+ *      Mutex class
+ * ===========================================================================
+ */
+
+#if 0
+#pragma mark -
+#pragma mark Mutex
+#endif
+
+#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX)
+/*
+ * Simple pthread wrapper.
+ */
+
+Mutex::Mutex()
+{
+    _init();
+}
+
+Mutex::Mutex(const char* name)
+{
+    // XXX: name not used for now
+    _init();
+}
+
+void Mutex::_init()
+{
+    pthread_mutex_t* pMutex = new pthread_mutex_t;
+    pthread_mutex_init(pMutex, NULL);
+    mState = pMutex;
+}
+
+Mutex::~Mutex()
+{
+    delete (pthread_mutex_t*) mState;
+}
+
+status_t Mutex::lock()
+{
+    int res;
+    while ((res=pthread_mutex_lock((pthread_mutex_t*) mState)) == EINTR) ;
+    return -res;
+}
+
+void Mutex::unlock()
+{
+    pthread_mutex_unlock((pthread_mutex_t*) mState);
+}
+
+status_t Mutex::tryLock()
+{
+    int res;
+    while ((res=pthread_mutex_trylock((pthread_mutex_t*) mState)) == EINTR) ;
+    return -res;
+}
+
+#elif defined(HAVE_FUTEX)
+#if 0
+#pragma mark -
+#endif
+
+#define STATE ((futex_mutex_t*) (&mState))
+
+Mutex::Mutex()
+{
+    _init();
+}
+
+Mutex::Mutex(const char* name)
+{
+    _init();
+}
+
+void
+Mutex::_init()
+{
+    futex_mutex_init(STATE);
+}
+
+Mutex::~Mutex()
+{
+}
+
+status_t Mutex::lock()
+{
+    int res;
+    while ((res=futex_mutex_lock(STATE, FUTEX_WAIT_INFINITE)) == EINTR) ;
+    return -res;
+}
+
+void Mutex::unlock()
+{
+    futex_mutex_unlock(STATE);
+}
+
+status_t Mutex::tryLock()
+{
+    int res;
+    while ((res=futex_mutex_trylock(STATE)) == EINTR) ;
+    return -res;
+}
+#undef STATE
+
+#elif defined(HAVE_WIN32_THREADS)
+#if 0
+#pragma mark -
+#endif
+
+Mutex::Mutex()
+{
+    HANDLE hMutex;
+
+    assert(sizeof(hMutex) == sizeof(mState));
+
+    hMutex = CreateMutex(NULL, FALSE, NULL);
+    mState = (void*) hMutex;
+}
+
+Mutex::Mutex(const char* name)
+{
+    // XXX: name not used for now
+    HANDLE hMutex;
+
+    hMutex = CreateMutex(NULL, FALSE, NULL);
+    mState = (void*) hMutex;
+}
+
+Mutex::~Mutex()
+{
+    CloseHandle((HANDLE) mState);
+}
+
+status_t Mutex::lock()
+{
+    DWORD dwWaitResult;
+    dwWaitResult = WaitForSingleObject((HANDLE) mState, INFINITE);
+    return dwWaitResult != WAIT_OBJECT_0 ? -1 : NO_ERROR;
+}
+
+void Mutex::unlock()
+{
+    if (!ReleaseMutex((HANDLE) mState))
+        LOG(LOG_WARN, "thread", "WARNING: bad result from unlocking mutex\n");
+}
+
+status_t Mutex::tryLock()
+{
+    DWORD dwWaitResult;
+
+    dwWaitResult = WaitForSingleObject((HANDLE) mState, 0);
+    if (dwWaitResult != WAIT_OBJECT_0 && dwWaitResult != WAIT_TIMEOUT)
+        LOG(LOG_WARN, "thread", "WARNING: bad result from try-locking mutex\n");
+    return (dwWaitResult == WAIT_OBJECT_0) ? 0 : -1;
+}
+
+#else
+#error "Somebody forgot to implement threads for this platform."
+#endif
+
+
+/*
+ * ===========================================================================
+ *      Condition class
+ * ===========================================================================
+ */
+
+#if 0
+#pragma mark -
+#pragma mark Condition
+#endif
+
+#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX)
+
+/*
+ * Constructor.  This is a simple pthread wrapper.
+ */
+Condition::Condition()
+{
+    pthread_cond_t* pCond = new pthread_cond_t;
+
+    pthread_cond_init(pCond, NULL);
+    mState = pCond;
+}
+
+/*
+ * Destructor.
+ */
+Condition::~Condition()
+{
+    pthread_cond_destroy((pthread_cond_t*) mState);
+    delete (pthread_cond_t*) mState;
+}
+
+/*
+ * Wait on a condition variable.  Lock the mutex before calling.
+ */
+
+status_t Condition::wait(Mutex& mutex)
+{
+    assert(mutex.mState != NULL);
+
+    int cc;
+    while ((cc = pthread_cond_wait((pthread_cond_t*)mState,
+                (pthread_mutex_t*) mutex.mState)) == EINTR) ;
+    return -cc;
+}
+
+status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
+{
+    assert(mutex.mState != NULL);
+
+    struct timespec ts;
+    ts.tv_sec = abstime/1000000000;
+    ts.tv_nsec = abstime-(ts.tv_sec*1000000000);
+    
+    int cc;
+    while ((cc = pthread_cond_timedwait((pthread_cond_t*)mState,
+            (pthread_mutex_t*) mutex.mState, &ts)) == EINTR) ;
+    return -cc;
+}
+
+status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
+{
+    return wait(mutex, systemTime()+reltime);
+}
+
+/*
+ * Signal the condition variable, allowing one thread to continue.
+ */
+void Condition::signal()
+{
+    pthread_cond_signal((pthread_cond_t*) mState);
+}
+
+/*
+ * Signal the condition variable, allowing all threads to continue.
+ */
+void Condition::broadcast()
+{
+    pthread_cond_broadcast((pthread_cond_t*) mState);
+}
+
+#elif defined(HAVE_FUTEX)
+#if 0
+#pragma mark -
+#endif
+
+#define STATE ((futex_cond_t*) (&mState))
+
+/*
+ * Constructor.  This is a simple pthread wrapper.
+ */
+Condition::Condition()
+{
+    futex_cond_init(STATE);
+}
+
+/*
+ * Destructor.
+ */
+Condition::~Condition()
+{
+}
+
+/*
+ * Wait on a condition variable.  Lock the mutex before calling.
+ */
+
+status_t Condition::wait(Mutex& mutex)
+{
+    assert(mutex.mState != NULL);
+
+    int res;
+    while ((res = futex_cond_wait(STATE,
+        (futex_mutex_t*)(&mutex.mState), FUTEX_WAIT_INFINITE)) == -EINTR) ;
+
+    return -res;
+}
+
+status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
+{
+    nsecs_t reltime = abstime - systemTime();
+    if (reltime <= 0) return true;
+    return waitRelative(mutex, reltime);
+}
+
+status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
+{
+    assert(mutex.mState != NULL);
+    int res;
+    unsigned msec = ns2ms(reltime);
+    if(msec == 0)
+        return true;
+    // This code will not time out at the correct time if interrupted by signals
+    while ((res = futex_cond_wait(STATE,
+        (futex_mutex_t*)(&mutex.mState), msec)) == -EINTR) ;
+    return res;
+}
+
+/*
+ * Signal the condition variable, allowing one thread to continue.
+ */
+void Condition::signal()
+{
+    futex_cond_signal(STATE);
+}
+
+/*
+ * Signal the condition variable, allowing all threads to continue.
+ */
+void Condition::broadcast()
+{
+    futex_cond_broadcast(STATE);
+}
+
+#undef STATE
+
+#elif defined(HAVE_WIN32_THREADS)
+#if 0
+#pragma mark -
+#endif
+
+/*
+ * Windows doesn't have a condition variable solution.  It's possible
+ * to create one, but it's easy to get it wrong.  For a discussion, and
+ * the origin of this implementation, see:
+ *
+ *  http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+ *
+ * The implementation shown on the page does NOT follow POSIX semantics.
+ * As an optimization they require acquiring the external mutex before
+ * calling signal() and broadcast(), whereas POSIX only requires grabbing
+ * it before calling wait().  The implementation here has been un-optimized
+ * to have the correct behavior.
+ */
+typedef struct WinCondition {
+    // Number of waiting threads.
+    int                 waitersCount;
+
+    // Serialize access to waitersCount.
+    CRITICAL_SECTION    waitersCountLock;
+
+    // Semaphore used to queue up threads waiting for the condition to
+    // become signaled.
+    HANDLE              sema;
+
+    // An auto-reset event used by the broadcast/signal thread to wait
+    // for all the waiting thread(s) to wake up and be released from
+    // the semaphore.
+    HANDLE              waitersDone;
+
+    // This mutex wouldn't be necessary if we required that the caller
+    // lock the external mutex before calling signal() and broadcast().
+    // I'm trying to mimic pthread semantics though.
+    HANDLE              internalMutex;
+
+    // Keeps track of whether we were broadcasting or signaling.  This
+    // allows us to optimize the code if we're just signaling.
+    bool                wasBroadcast;
+
+    status_t wait(WinCondition* condState, HANDLE hMutex, nsecs_t* abstime)
+    {
+        // Increment the wait count, avoiding race conditions.
+        EnterCriticalSection(&condState->waitersCountLock);
+        condState->waitersCount++;
+        //printf("+++ wait: incr waitersCount to %d (tid=%ld)\n",
+        //    condState->waitersCount, getThreadId());
+        LeaveCriticalSection(&condState->waitersCountLock);
+    
+        DWORD timeout = INFINITE;
+        if (abstime) {
+            nsecs_t reltime = *abstime - systemTime();
+            if (reltime < 0)
+                reltime = 0;
+            timeout = reltime/1000000;
+        }
+        
+        // Atomically release the external mutex and wait on the semaphore.
+        DWORD res =
+            SignalObjectAndWait(hMutex, condState->sema, timeout, FALSE);
+    
+        //printf("+++ wait: awake (tid=%ld)\n", getThreadId());
+    
+        // Reacquire lock to avoid race conditions.
+        EnterCriticalSection(&condState->waitersCountLock);
+    
+        // No longer waiting.
+        condState->waitersCount--;
+    
+        // Check to see if we're the last waiter after a broadcast.
+        bool lastWaiter = (condState->wasBroadcast && condState->waitersCount == 0);
+    
+        //printf("+++ wait: lastWaiter=%d (wasBc=%d wc=%d)\n",
+        //    lastWaiter, condState->wasBroadcast, condState->waitersCount);
+    
+        LeaveCriticalSection(&condState->waitersCountLock);
+    
+        // If we're the last waiter thread during this particular broadcast
+        // then signal broadcast() that we're all awake.  It'll drop the
+        // internal mutex.
+        if (lastWaiter) {
+            // Atomically signal the "waitersDone" event and wait until we
+            // can acquire the internal mutex.  We want to do this in one step
+            // because it ensures that everybody is in the mutex FIFO before
+            // any thread has a chance to run.  Without it, another thread
+            // could wake up, do work, and hop back in ahead of us.
+            SignalObjectAndWait(condState->waitersDone, condState->internalMutex,
+                INFINITE, FALSE);
+        } else {
+            // Grab the internal mutex.
+            WaitForSingleObject(condState->internalMutex, INFINITE);
+        }
+    
+        // Release the internal and grab the external.
+        ReleaseMutex(condState->internalMutex);
+        WaitForSingleObject(hMutex, INFINITE);
+    
+        return res == WAIT_OBJECT_0 ? NO_ERROR : -1;
+    }
+} WinCondition;
+
+/*
+ * Constructor.  Set up the WinCondition stuff.
+ */
+Condition::Condition()
+{
+    WinCondition* condState = new WinCondition;
+
+    condState->waitersCount = 0;
+    condState->wasBroadcast = false;
+    // semaphore: no security, initial value of 0
+    condState->sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
+    InitializeCriticalSection(&condState->waitersCountLock);
+    // auto-reset event, not signaled initially
+    condState->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
+    // used so we don't have to lock external mutex on signal/broadcast
+    condState->internalMutex = CreateMutex(NULL, FALSE, NULL);
+
+    mState = condState;
+}
+
+/*
+ * Destructor.  Free Windows resources as well as our allocated storage.
+ */
+Condition::~Condition()
+{
+    WinCondition* condState = (WinCondition*) mState;
+    if (condState != NULL) {
+        CloseHandle(condState->sema);
+        CloseHandle(condState->waitersDone);
+        delete condState;
+    }
+}
+
+
+status_t Condition::wait(Mutex& mutex)
+{
+    WinCondition* condState = (WinCondition*) mState;
+    HANDLE hMutex = (HANDLE) mutex.mState;
+    
+    return ((WinCondition*)mState)->wait(condState, hMutex, NULL);
+}
+
+status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
+{
+    WinCondition* condState = (WinCondition*) mState;
+    HANDLE hMutex = (HANDLE) mutex.mState;
+
+    return ((WinCondition*)mState)->wait(condState, hMutex, &abstime);
+}
+
+status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
+{
+    return wait(mutex, systemTime()+reltime);
+}
+
+/*
+ * Signal the condition variable, allowing one thread to continue.
+ */
+void Condition::signal()
+{
+    WinCondition* condState = (WinCondition*) mState;
+
+    // Lock the internal mutex.  This ensures that we don't clash with
+    // broadcast().
+    WaitForSingleObject(condState->internalMutex, INFINITE);
+
+    EnterCriticalSection(&condState->waitersCountLock);
+    bool haveWaiters = (condState->waitersCount > 0);
+    LeaveCriticalSection(&condState->waitersCountLock);
+
+    // If no waiters, then this is a no-op.  Otherwise, knock the semaphore
+    // down a notch.
+    if (haveWaiters)
+        ReleaseSemaphore(condState->sema, 1, 0);
+
+    // Release internal mutex.
+    ReleaseMutex(condState->internalMutex);
+}
+
+/*
+ * Signal the condition variable, allowing all threads to continue.
+ *
+ * First we have to wake up all threads waiting on the semaphore, then
+ * we wait until all of the threads have actually been woken before
+ * releasing the internal mutex.  This ensures that all threads are woken.
+ */
+void Condition::broadcast()
+{
+    WinCondition* condState = (WinCondition*) mState;
+
+    // Lock the internal mutex.  This keeps the guys we're waking up
+    // from getting too far.
+    WaitForSingleObject(condState->internalMutex, INFINITE);
+
+    EnterCriticalSection(&condState->waitersCountLock);
+    bool haveWaiters = false;
+
+    if (condState->waitersCount > 0) {
+        haveWaiters = true;
+        condState->wasBroadcast = true;
+    }
+
+    if (haveWaiters) {
+        // Wake up all the waiters.
+        ReleaseSemaphore(condState->sema, condState->waitersCount, 0);
+
+        LeaveCriticalSection(&condState->waitersCountLock);
+
+        // Wait for all awakened threads to acquire the counting semaphore.
+        // The last guy who was waiting sets this.
+        WaitForSingleObject(condState->waitersDone, INFINITE);
+
+        // Reset wasBroadcast.  (No crit section needed because nobody
+        // else can wake up to poke at it.)
+        condState->wasBroadcast = 0;
+    } else {
+        // nothing to do
+        LeaveCriticalSection(&condState->waitersCountLock);
+    }
+
+    // Release internal mutex.
+    ReleaseMutex(condState->internalMutex);
+}
+
+#else
+#error "condition variables not supported on this platform"
+#endif
+
+
+/*
+ * ===========================================================================
+ *      ReadWriteLock class
+ * ===========================================================================
+ */
+
+#if 0
+#pragma mark -
+#pragma mark ReadWriteLock
+#endif
+
+/*
+ * Add a reader.  Readers are nice.  They share.
+ */
+void ReadWriteLock::lockForRead()
+{
+    mLock.lock();
+    while (mNumWriters > 0) {
+        LOG(LOG_DEBUG, "thread", "+++ lockForRead: waiting\n");
+        mReadWaiter.wait(mLock);
+    }
+    assert(mNumWriters == 0);
+    mNumReaders++;
+#if defined(PRINT_RENDER_TIMES)
+    if (mNumReaders == 1)
+        mDebugTimer.start();
+#endif
+    mLock.unlock();
+}
+
+/*
+ * Try to add a reader.  If it doesn't work right away, return "false".
+ */
+bool ReadWriteLock::tryLockForRead()
+{
+    mLock.lock();
+    if (mNumWriters > 0) {
+        mLock.unlock();
+        return false;
+    }
+    assert(mNumWriters == 0);
+    mNumReaders++;
+#if defined(PRINT_RENDER_TIMES)
+    if (mNumReaders == 1)
+        mDebugTimer.start();
+#endif
+    mLock.unlock();
+    return true;
+}
+
+/*
+ * Remove a reader.
+ */
+void ReadWriteLock::unlockForRead()
+{
+    mLock.lock();
+    if (mNumReaders == 0) {
+        mLock.unlock();
+        LOG(LOG_WARN, "thread",
+            "WARNING: unlockForRead requested, but not locked\n");
+        return;
+    }
+    assert(mNumReaders > 0);
+    assert(mNumWriters == 0);
+    mNumReaders--;
+    if (mNumReaders == 0) {           // last reader?
+#if defined(PRINT_RENDER_TIMES)
+        mDebugTimer.stop();
+        printf(" rdlk held %.3f msec\n",
+            (double) mDebugTimer.durationUsecs() / 1000.0);
+#endif
+        //printf("+++ signaling writers (if any)\n");
+        mWriteWaiter.signal();      // wake one writer (if any)
+    }
+    mLock.unlock();
+}
+
+/*
+ * Add a writer.  This requires exclusive access to the object.
+ */
+void ReadWriteLock::lockForWrite()
+{
+    mLock.lock();
+    while (mNumReaders > 0 || mNumWriters > 0) {
+        LOG(LOG_DEBUG, "thread", "+++ lockForWrite: waiting\n");
+        mWriteWaiter.wait(mLock);
+    }
+    assert(mNumReaders == 0);
+    assert(mNumWriters == 0);
+    mNumWriters++;
+#if defined(PRINT_RENDER_TIMES)
+    mDebugTimer.start();
+#endif
+    mLock.unlock();
+}
+
+/*
+ * Try to add a writer.  If it doesn't work right away, return "false".
+ */
+bool ReadWriteLock::tryLockForWrite()
+{
+    mLock.lock();
+    if (mNumReaders > 0 || mNumWriters > 0) {
+        mLock.unlock();
+        return false;
+    }
+    assert(mNumReaders == 0);
+    assert(mNumWriters == 0);
+    mNumWriters++;
+#if defined(PRINT_RENDER_TIMES)
+    mDebugTimer.start();
+#endif
+    mLock.unlock();
+    return true;
+}
+
+/*
+ * Remove a writer.
+ */
+void ReadWriteLock::unlockForWrite()
+{
+    mLock.lock();
+    if (mNumWriters == 0) {
+        mLock.unlock();
+        LOG(LOG_WARN, "thread",
+            "WARNING: unlockForWrite requested, but not locked\n");
+        return;
+    }
+    assert(mNumWriters == 1);
+    mNumWriters--;
+#if defined(PRINT_RENDER_TIMES)
+    mDebugTimer.stop();
+    //printf(" wrlk held %.3f msec\n",
+    //    (double) mDebugTimer.durationUsecs() / 1000.0);
+#endif
+    mWriteWaiter.signal();         // should other writers get first dibs?
+    //printf("+++ signaling readers (if any)\n");
+    mReadWaiter.broadcast();        // wake all readers (if any)
+    mLock.unlock();
+}
+
+// ----------------------------------------------------------------------------
+
+#if 0
+#pragma mark -
+#pragma mark Thread::Thread
+#endif
+
+/*
+ * This is our thread object!
+ */
+
+Thread::Thread(bool canCallJava)
+    :   mCanCallJava(canCallJava),
+        mThread(thread_id_t(-1)),
+        mLock("Thread::mLock"),
+        mStatus(NO_ERROR),
+        mExitPending(false), mRunning(false)
+{
+}
+
+Thread::~Thread()
+{
+}
+
+status_t Thread::readyToRun()
+{
+    return NO_ERROR;
+}
+
+status_t Thread::run(const char* name, int32_t priority, size_t stack)
+{
+    Mutex::Autolock _l(mLock);
+
+    if (mRunning) {
+        // thread already started
+        return INVALID_OPERATION;
+    }
+
+    // reset status and exitPending to their default value, so we can
+    // try again after an error happened (either below, or in readyToRun())
+    mStatus = NO_ERROR;
+    mExitPending = false;
+    mThread = thread_id_t(-1);
+    
+    // hold a strong reference on ourself
+    mHoldSelf = this;
+
+    bool res;
+    if (mCanCallJava) {
+        res = createThreadEtc(_threadLoop,
+                this, name, priority, stack, &mThread);
+    } else {
+        res = androidCreateRawThreadEtc(_threadLoop,
+                this, name, priority, stack, &mThread);
+    }
+    
+    if (res == false) {
+        mStatus = UNKNOWN_ERROR;   // something happened!
+        mRunning = false;
+        mThread = thread_id_t(-1);
+    }
+    
+    if (mStatus < 0) {
+        // something happened, don't leak
+        mHoldSelf.clear();
+    }
+    
+    return mStatus;
+}
+
+int Thread::_threadLoop(void* user)
+{
+    Thread* const self = static_cast<Thread*>(user);
+    sp<Thread> strong(self->mHoldSelf);
+    wp<Thread> weak(strong);
+    self->mHoldSelf.clear();
+
+    // we're about to run...
+    self->mStatus = self->readyToRun();
+    if (self->mStatus!=NO_ERROR || self->mExitPending) {
+        // pretend the thread never started...
+        self->mExitPending = false;
+        self->mRunning = false;
+        return 0;
+    }
+    
+    // thread is running now
+    self->mRunning = true;
+
+    do {
+        bool result = self->threadLoop();
+        if (result == false || self->mExitPending) {
+            self->mExitPending = true;
+            self->mLock.lock();
+            self->mRunning = false;
+            self->mThreadExitedCondition.signal();
+            self->mLock.unlock();
+            break;
+        }
+        
+        // Release our strong reference, to let a chance to the thread
+        // to die a peaceful death.
+        strong.clear();
+        // And immediately, reacquire a strong reference for the next loop
+        strong = weak.promote();
+    } while(strong != 0);
+    
+    return 0;
+}
+
+void Thread::requestExit()
+{
+    mExitPending = true;
+}
+
+status_t Thread::requestExitAndWait()
+{
+    if (mStatus == OK) {
+
+        if (mThread == getThreadId()) {
+            LOGW(
+            "Thread (this=%p): don't call waitForExit() from this "
+            "Thread object's thread. It's a guaranteed deadlock!",
+            this);
+            return WOULD_BLOCK;
+        }
+        
+        requestExit();
+
+        Mutex::Autolock _l(mLock);
+        while (mRunning == true) {
+            mThreadExitedCondition.wait(mLock);
+        }
+        mExitPending = false;
+    }
+    return mStatus;
+}
+
+bool Thread::exitPending() const
+{
+    return mExitPending;
+}
+
+
+
+};  // namespace android
diff --git a/libs/utils/TimerProbe.cpp b/libs/utils/TimerProbe.cpp
new file mode 100644
index 0000000..835480d
--- /dev/null
+++ b/libs/utils/TimerProbe.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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 <utils/TimerProbe.h>
+ 
+#if ENABLE_TIMER_PROBE
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "time"
+
+namespace android {
+
+Vector<TimerProbe::Bucket> TimerProbe::gBuckets;
+TimerProbe* TimerProbe::gExecuteChain;
+int TimerProbe::gIndent;
+timespec TimerProbe::gRealBase;
+
+TimerProbe::TimerProbe(const char tag[], int* slot) : mTag(tag)
+{
+    mNext = gExecuteChain;
+    gExecuteChain = this;
+    mIndent = gIndent;
+    gIndent += 1;
+    if (mIndent > 0) {
+        if (*slot == 0) {
+            int count = gBuckets.add();
+            *slot = count;
+            Bucket& bucket = gBuckets.editItemAt(count);
+            memset(&bucket, 0, sizeof(Bucket));
+            bucket.mTag = tag;
+            bucket.mSlotPtr = slot;
+            bucket.mIndent = mIndent;
+        }
+        mBucket = *slot;
+    }
+    clock_gettime(CLOCK_REALTIME, &mRealStart);
+    if (gRealBase.tv_sec == 0)
+        gRealBase = mRealStart;
+    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mPStart);
+    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mTStart);
+}
+
+void TimerProbe::end()
+{
+    timespec realEnd, pEnd, tEnd;
+    clock_gettime(CLOCK_REALTIME, &realEnd);
+    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &pEnd);
+    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tEnd);
+    print(realEnd, pEnd, tEnd);
+    mTag = NULL;
+}
+
+TimerProbe::~TimerProbe()
+{
+    if (mTag != NULL)
+        end();
+    gExecuteChain = mNext;
+    gIndent--;
+}
+
+
+uint32_t TimerProbe::ElapsedTime(const timespec& start, const timespec& end)
+{
+    int sec = end.tv_sec - start.tv_sec;
+    int nsec = end.tv_nsec - start.tv_nsec;
+    if (nsec < 0) {
+        sec--;
+        nsec += 1000000000;
+    }
+    return sec * 1000000 + nsec / 1000;
+}
+
+void TimerProbe::print(const timespec& r, const timespec& p,
+        const timespec& t) const
+{
+    uint32_t es = ElapsedTime(gRealBase, mRealStart);
+    uint32_t er = ElapsedTime(mRealStart, r);
+    uint32_t ep = ElapsedTime(mPStart, p);
+    uint32_t et = ElapsedTime(mTStart, t);
+    if (mIndent > 0) {
+        Bucket& bucket = gBuckets.editItemAt(mBucket);
+        if (bucket.mStart == 0)
+            bucket.mStart = es;
+        bucket.mReal += er;
+        bucket.mProcess += ep;
+        bucket.mThread += et;
+        bucket.mCount++;
+        return;
+    }
+    int index = 0;
+    int buckets = gBuckets.size();
+    int count = 1;
+    const char* tag = mTag;
+    int indent = mIndent;
+    do {
+        LOGD("%-30.30s: (%3d) %-5.*s time=%-10.3f real=%7dus process=%7dus (%3d%%) thread=%7dus (%3d%%)\n", 
+            tag, count, indent > 5 ? 5 : indent, "+++++", es / 1000000.0,
+            er, ep, ep * 100 / er, et, et * 100 / er);
+        if (index >= buckets)
+            break;
+        Bucket& bucket = gBuckets.editItemAt(index);
+        count = bucket.mCount;
+        es = bucket.mStart;
+        er = bucket.mReal;
+        ep = bucket.mProcess;
+        et = bucket.mThread;
+        tag = bucket.mTag;
+        indent = bucket.mIndent;
+        *bucket.mSlotPtr = 0;
+    } while (++index); // always true
+    gBuckets.clear();
+}
+
+}; // namespace android
+
+#endif
diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp
new file mode 100644
index 0000000..2abc811
--- /dev/null
+++ b/libs/utils/Timers.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Timer functions.
+//
+#include <utils/Timers.h>
+#include <utils/ported.h>     // may need usleep
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+#ifdef HAVE_WIN32_THREADS
+#include <windows.h>
+#endif
+
+nsecs_t systemTime(int clock)
+{
+#if defined(HAVE_POSIX_CLOCKS)
+    static const clockid_t clocks[] = {
+            CLOCK_REALTIME,
+            CLOCK_MONOTONIC,
+            CLOCK_PROCESS_CPUTIME_ID,
+            CLOCK_THREAD_CPUTIME_ID
+    };
+    struct timespec t;
+    t.tv_sec = t.tv_nsec = 0;
+    clock_gettime(clocks[clock], &t);
+    return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+#else
+    // we don't support the clocks here.
+    struct timeval t;
+    t.tv_sec = t.tv_usec = 0;
+    gettimeofday(&t, NULL);
+    return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL;
+#endif
+}
+
+//#define MONITOR_USLEEP
+
+/*
+ * Sleep long enough that we'll wake up "interval" milliseconds after
+ * the previous snooze.
+ *
+ * The "nextTick" argument is updated on each call, and should be passed
+ * in every time.  Set its fields to zero on the first call.
+ *
+ * Returns the #of intervals we have overslept, which will be zero if we're
+ * on time.  [Currently just returns 0 or 1.]
+ */
+int sleepForInterval(long interval, struct timeval* pNextTick)
+{
+    struct timeval now;
+    long long timeBeforeNext;
+    long sleepTime = 0;
+    bool overSlept = false;
+    //int usleepBias = 0;
+
+#ifdef USLEEP_BIAS
+    /*
+     * Linux likes to add 9000ms or so.
+     * [not using this for now]
+     */
+    //usleepBias = USLEEP_BIAS;
+#endif
+
+    gettimeofday(&now, NULL);
+
+    if (pNextTick->tv_sec == 0) {
+        /* special-case for first time through */
+        *pNextTick = now;
+        sleepTime = interval;
+        android::DurationTimer::addToTimeval(pNextTick, interval);
+    } else {
+        /*
+         * Compute how much time there is before the next tick.  If this
+         * value is negative, we've run over.  If we've run over a little
+         * bit we can shorten the next frame to keep the pace steady, but
+         * if we've dramatically overshot we need to re-sync.
+         */
+        timeBeforeNext = android::DurationTimer::subtractTimevals(pNextTick, &now);
+        //printf("TOP: now=%ld.%ld next=%ld.%ld diff=%ld\n",
+        //    now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec,
+        //    (long) timeBeforeNext);
+        if (timeBeforeNext < -interval) {
+            /* way over */
+            overSlept = true;
+            sleepTime = 0;
+            *pNextTick = now;
+        } else if (timeBeforeNext <= 0) {
+            /* slightly over, keep the pace steady */
+            overSlept = true;
+            sleepTime = 0;
+        } else if (timeBeforeNext <= interval) {
+            /* right on schedule */
+            sleepTime = timeBeforeNext;
+        } else if (timeBeforeNext > interval && timeBeforeNext <= 2*interval) {
+            /* sleep call returned early; do a longer sleep this time */
+            sleepTime = timeBeforeNext;
+        } else if (timeBeforeNext > interval) {
+            /* we went back in time -- somebody updated system clock? */
+            /* (could also be a *seriously* broken usleep()) */
+            LOG(LOG_DEBUG, "",
+                " Impossible: timeBeforeNext = %ld\n", (long)timeBeforeNext);
+            sleepTime = 0;
+            *pNextTick = now;
+        }
+        android::DurationTimer::addToTimeval(pNextTick, interval);
+    }
+    //printf(" Before sleep: now=%ld.%ld next=%ld.%ld sleepTime=%ld\n",
+    //    now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec,
+    //    sleepTime);
+
+    /*
+     * Sleep for the designated period of time.
+     *
+     * Linux tends to sleep for longer than requested, often by 17-18ms.
+     * MinGW tends to sleep for less than requested, by as much as 14ms,
+     * but occasionally oversleeps for 40+ms (looks like some external
+     * factors plus round-off on a 64Hz clock).  Cygwin is pretty steady.
+     *
+     * If you start the MinGW version, and then launch the Cygwin version,
+     * the MinGW clock becomes more erratic.  Not entirely sure why.
+     *
+     * (There's a lot of stuff here; it's really just a usleep() call with
+     * a bunch of instrumentation.)
+     */
+    if (sleepTime > 0) {
+#if defined(MONITOR_USLEEP)
+        struct timeval before, after;
+        long long actual;
+
+        gettimeofday(&before, NULL);
+        usleep((long) sleepTime);
+        gettimeofday(&after, NULL);
+
+        /* check usleep() accuracy; default Linux threads are pretty sloppy */
+        actual = android::DurationTimer::subtractTimevals(&after, &before);
+        if ((long) actual < sleepTime - 14000 /*(sleepTime/10)*/ ||
+            (long) actual > sleepTime + 20000 /*(sleepTime/10)*/)
+        {
+            LOG(LOG_DEBUG, "", " Odd usleep: req=%ld, actual=%ld\n", sleepTime,
+                (long) actual);
+        }
+#else
+#ifdef HAVE_WIN32_THREADS
+        Sleep( sleepTime/1000 );
+#else        
+        usleep((long) sleepTime);
+#endif        
+#endif
+    }
+
+    //printf("slept %d\n", sleepTime);
+
+    if (overSlept)
+        return 1;       // close enough
+    else
+        return 0;
+}
+
+
+/*
+ * ===========================================================================
+ *      DurationTimer
+ * ===========================================================================
+ */
+
+using namespace android;
+
+// Start the timer.
+void DurationTimer::start(void)
+{
+    gettimeofday(&mStartWhen, NULL);
+}
+
+// Stop the timer.
+void DurationTimer::stop(void)
+{
+    gettimeofday(&mStopWhen, NULL);
+}
+
+// Get the duration in microseconds.
+long long DurationTimer::durationUsecs(void) const
+{
+    return (long) subtractTimevals(&mStopWhen, &mStartWhen);
+}
+
+// Subtract two timevals.  Returns the difference (ptv1-ptv2) in
+// microseconds.
+/*static*/ long long DurationTimer::subtractTimevals(const struct timeval* ptv1,
+    const struct timeval* ptv2)
+{
+    long long stop  = ((long long) ptv1->tv_sec) * 1000000LL +
+                      ((long long) ptv1->tv_usec);
+    long long start = ((long long) ptv2->tv_sec) * 1000000LL +
+                      ((long long) ptv2->tv_usec);
+    return stop - start;
+}
+
+// Add the specified amount of time to the timeval.
+/*static*/ void DurationTimer::addToTimeval(struct timeval* ptv, long usec)
+{
+    if (usec < 0) {
+        LOG(LOG_WARN, "", "Negative values not supported in addToTimeval\n");
+        return;
+    }
+
+    // normalize tv_usec if necessary
+    if (ptv->tv_usec >= 1000000) {
+        ptv->tv_sec += ptv->tv_usec / 1000000;
+        ptv->tv_usec %= 1000000;
+    }
+
+    ptv->tv_usec += usec % 1000000;
+    if (ptv->tv_usec >= 1000000) {
+        ptv->tv_usec -= 1000000;
+        ptv->tv_sec++;
+    }
+    ptv->tv_sec += usec / 1000000;
+}
+
diff --git a/libs/utils/Unicode.cpp b/libs/utils/Unicode.cpp
new file mode 100644
index 0000000..33f535f
--- /dev/null
+++ b/libs/utils/Unicode.cpp
@@ -0,0 +1,193 @@
+/*
+ * 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 "utils/AndroidUnicode.h"
+#include "characterData.h"
+
+#define LOG_TAG "Unicode"
+#include "utils/Log.h"
+
+// ICU headers for using macros
+#include <unicode/utf16.h>
+
+#define MIN_RADIX 2
+#define MAX_RADIX 36
+
+#define TYPE_SHIFT 0
+#define TYPE_MASK ((1<<5)-1)
+
+#define DIRECTION_SHIFT (TYPE_SHIFT+5)
+#define DIRECTION_MASK ((1<<5)-1)
+
+#define MIRRORED_SHIFT (DIRECTION_SHIFT+5)
+#define MIRRORED_MASK ((1<<1)-1)
+
+#define TOUPPER_SHIFT (MIRRORED_SHIFT+1)
+#define TOUPPER_MASK ((1<<6)-1)
+
+#define TOLOWER_SHIFT (TOUPPER_SHIFT+6)
+#define TOLOWER_MASK ((1<<6)-1)
+
+#define TOTITLE_SHIFT (TOLOWER_SHIFT+6)
+#define TOTITLE_MASK ((1<<2)-1)
+
+#define MIRROR_SHIFT (TOTITLE_SHIFT+2)
+#define MIRROR_MASK ((1<<5)-1)
+
+#define NUMERIC_SHIFT (TOTITLE_SHIFT+2)
+#define NUMERIC_MASK ((1<<7)-1)
+
+#define DECOMPOSITION_SHIFT (11)
+#define DECOMPOSITION_MASK ((1<<5)-1)
+
+/*
+ * Returns the value stored in the CharacterData tables that contains
+ * an index into the packed data table and the decomposition type.
+ */
+static uint16_t findCharacterValue(UChar32 c)
+{
+    LOG_ASSERT(c >= 0 && c <= 0x10FFFF, "findCharacterValue received an invalid codepoint");
+    if (c < 256)
+        return CharacterData::LATIN1_DATA[c];
+
+    // Rotate the bits because the tables are separated into even and odd codepoints
+    c = (c >> 1) | ((c & 1) << 20);
+
+    CharacterData::Range search = CharacterData::FULL_DATA[c >> 16];
+    const uint32_t* array = search.array;
+ 
+    // This trick is so that that compare in the while loop does not
+    // need to shift the array entry down by 16
+    c <<= 16;
+    c |= 0xFFFF;
+
+    int high = (int)search.length - 1;
+    int low = 0;
+
+    if (high < 0)
+        return 0;
+    
+    while (low < high - 1)
+    {
+        int probe = (high + low) >> 1;
+
+        // The entries contain the codepoint in the high 16 bits and the index
+        // into PACKED_DATA in the low 16.
+        if (array[probe] > (unsigned)c)
+            high = probe;
+        else
+            low = probe;
+    }
+
+    LOG_ASSERT((array[low] <= (unsigned)c), "A suitable range was not found");
+    return array[low] & 0xFFFF;
+}
+
+uint32_t android::Unicode::getPackedData(UChar32 c)
+{
+    // findCharacterValue returns a 16-bit value with the top 5 bits containing a decomposition type
+    // and the remaining bits containing an index.
+    return CharacterData::PACKED_DATA[findCharacterValue(c) & 0x7FF];
+}
+
+android::Unicode::CharType android::Unicode::getType(UChar32 c)
+{
+    if (c < 0 || c >= 0x10FFFF)
+        return CHARTYPE_UNASSIGNED;
+    return (CharType)((getPackedData(c) >> TYPE_SHIFT) & TYPE_MASK);
+}
+
+android::Unicode::DecompositionType android::Unicode::getDecompositionType(UChar32 c)
+{
+    // findCharacterValue returns a 16-bit value with the top 5 bits containing a decomposition type
+    // and the remaining bits containing an index.
+    return (DecompositionType)((findCharacterValue(c) >> DECOMPOSITION_SHIFT) & DECOMPOSITION_MASK);
+}
+
+int android::Unicode::getDigitValue(UChar32 c, int radix)
+{
+    if (radix < MIN_RADIX || radix > MAX_RADIX)
+        return -1;
+
+    int tempValue = radix;
+    
+    if (c >= '0' && c <= '9')
+        tempValue = c - '0';
+    else if (c >= 'a' && c <= 'z')
+        tempValue = c - 'a' + 10;
+    else if (c >= 'A' && c <= 'Z')
+        tempValue = c - 'A' + 10;
+    
+    return tempValue < radix ? tempValue : -1;
+}
+
+int android::Unicode::getNumericValue(UChar32 c)
+{
+    if (isMirrored(c))
+        return -1;
+    
+    return (int) CharacterData::NUMERICS[((getPackedData(c) >> NUMERIC_SHIFT) & NUMERIC_MASK)];
+}
+
+UChar32 android::Unicode::toLower(UChar32 c)
+{
+    return c + CharacterData::LCDIFF[(getPackedData(c) >> TOLOWER_SHIFT) & TOLOWER_MASK];
+}
+
+UChar32 android::Unicode::toUpper(UChar32 c)
+{
+    return c + CharacterData::UCDIFF[(getPackedData(c) >> TOUPPER_SHIFT) & TOUPPER_MASK];
+}
+
+android::Unicode::Direction android::Unicode::getDirectionality(UChar32 c)
+{
+    uint32_t data = getPackedData(c);
+
+    if (0 == data)
+        return DIRECTIONALITY_UNDEFINED;
+
+    Direction d = (Direction) ((data >> DIRECTION_SHIFT) & DIRECTION_MASK);
+
+    if (DIRECTION_MASK == d)
+        return DIRECTIONALITY_UNDEFINED;
+    
+    return d;
+}
+
+bool android::Unicode::isMirrored(UChar32 c)
+{
+    return ((getPackedData(c) >> MIRRORED_SHIFT) & MIRRORED_MASK) != 0;
+}
+
+UChar32 android::Unicode::toMirror(UChar32 c)
+{
+    if (!isMirrored(c))
+        return c;
+
+    return c + CharacterData::MIRROR_DIFF[(getPackedData(c) >> MIRROR_SHIFT) & MIRROR_MASK];
+}
+
+UChar32 android::Unicode::toTitle(UChar32 c)
+{
+    int32_t diff = CharacterData::TCDIFF[(getPackedData(c) >> TOTITLE_SHIFT) & TOTITLE_MASK];
+
+    if (TOTITLE_MASK == diff)
+        return toUpper(c);
+    
+    return c + diff;
+}
+
+
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
new file mode 100644
index 0000000..2c2d667
--- /dev/null
+++ b/libs/utils/VectorImpl.cpp
@@ -0,0 +1,611 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "Vector"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/SharedBuffer.h>
+#include <utils/VectorImpl.h>
+
+/*****************************************************************************/
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+const size_t kMinVectorCapacity = 4;
+
+static inline size_t max(size_t a, size_t b) {
+    return a>b ? a : b;
+}
+
+// ----------------------------------------------------------------------------
+
+VectorImpl::VectorImpl(size_t itemSize, uint32_t flags)
+    : mStorage(0), mCount(0), mFlags(flags), mItemSize(itemSize)
+{
+}
+
+VectorImpl::VectorImpl(const VectorImpl& rhs)
+    :   mStorage(rhs.mStorage), mCount(rhs.mCount),
+        mFlags(rhs.mFlags), mItemSize(rhs.mItemSize)
+{
+    if (mStorage) {
+        SharedBuffer::sharedBuffer(mStorage)->acquire();
+    }
+}
+
+VectorImpl::~VectorImpl()
+{
+    LOG_ASSERT(!mCount,
+        "[%p] "
+        "subclasses of VectorImpl must call finish_vector()"
+        " in their destructor. Leaking %d bytes.",
+        this, (int)(mCount*mItemSize));
+    // We can't call _do_destroy() here because the vtable is already gone. 
+}
+
+VectorImpl& VectorImpl::operator = (const VectorImpl& rhs)
+{
+    LOG_ASSERT(mItemSize == rhs.mItemSize,
+        "Vector<> have different types (this=%p, rhs=%p)", this, &rhs);
+    if (this != &rhs) {
+        release_storage();
+        if (rhs.mCount) {
+            mStorage = rhs.mStorage;
+            mCount = rhs.mCount;
+            SharedBuffer::sharedBuffer(mStorage)->acquire();
+        } else {
+            mStorage = 0;
+            mCount = 0;
+        }
+    }
+    return *this;
+}
+
+void* VectorImpl::editArrayImpl()
+{
+    if (mStorage) {
+        SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage)->attemptEdit();
+        if (sb == 0) {
+            sb = SharedBuffer::alloc(capacity() * mItemSize);
+            if (sb) {
+                _do_copy(sb->data(), mStorage, mCount);
+                release_storage();
+                mStorage = sb->data();
+            }
+        }
+    }
+    return mStorage;
+}
+
+size_t VectorImpl::capacity() const
+{
+    if (mStorage) {
+        return SharedBuffer::sharedBuffer(mStorage)->size() / mItemSize;
+    }
+    return 0;
+}
+
+ssize_t VectorImpl::insertVectorAt(const VectorImpl& vector, size_t index)
+{
+    if (index > size())
+        return BAD_INDEX;
+    void* where = _grow(index, vector.size());
+    if (where) {
+        _do_copy(where, vector.arrayImpl(), vector.size());
+    }
+    return where ? index : (ssize_t)NO_MEMORY;
+}
+
+ssize_t VectorImpl::appendVector(const VectorImpl& vector)
+{
+    return insertVectorAt(vector, size());
+}
+
+ssize_t VectorImpl::insertAt(size_t index, size_t numItems)
+{
+    return insertAt(0, index, numItems);
+}
+
+ssize_t VectorImpl::insertAt(const void* item, size_t index, size_t numItems)
+{
+    if (index > size())
+        return BAD_INDEX;
+    void* where = _grow(index, numItems);
+    if (where) {
+        if (item) {
+            _do_splat(where, item, numItems);
+        } else {
+            _do_construct(where, numItems);
+        }
+    }
+    return where ? index : (ssize_t)NO_MEMORY;
+}
+
+static int sortProxy(const void* lhs, const void* rhs, void* func)
+{
+    return (*(VectorImpl::compar_t)func)(lhs, rhs);
+}
+
+status_t VectorImpl::sort(VectorImpl::compar_t cmp)
+{
+    return sort(sortProxy, (void*)cmp);
+}
+
+status_t VectorImpl::sort(VectorImpl::compar_r_t cmp, void* state)
+{
+    // the sort must be stable. we're using insertion sort which
+    // is well suited for small and already sorted arrays
+    // for big arrays, it could be better to use mergesort
+    const ssize_t count = size();
+    if (count > 1) {
+        void* array = const_cast<void*>(arrayImpl());
+        void* temp = 0;
+        ssize_t i = 1;
+        while (i < count) {
+            void* item = reinterpret_cast<char*>(array) + mItemSize*(i);
+            void* curr = reinterpret_cast<char*>(array) + mItemSize*(i-1);
+            if (cmp(curr, item, state) > 0) {
+
+                if (!temp) {
+                    // we're going to have to modify the array...
+                    array = editArrayImpl();
+                    if (!array) return NO_MEMORY;
+                    temp = malloc(mItemSize);
+                    if (!temp) return NO_MEMORY;
+                    _do_construct(temp, 1);
+                    item = reinterpret_cast<char*>(array) + mItemSize*(i);
+                    curr = reinterpret_cast<char*>(array) + mItemSize*(i-1);
+                }
+
+                _do_copy(temp, item, 1);
+
+                ssize_t j = i-1;
+                void* next = reinterpret_cast<char*>(array) + mItemSize*(i);                    
+                do {
+                    _do_copy(next, curr, 1);
+                    next = curr;
+                    --j;
+                    curr = reinterpret_cast<char*>(array) + mItemSize*(j);                    
+                } while (j>=0 && (cmp(curr, temp, state) > 0));
+
+                _do_copy(next, temp, 1);
+            }
+            i++;
+        }
+        
+        if (temp) {
+            _do_destroy(temp, 1);
+            free(temp);
+        }
+    }
+    return NO_ERROR;
+}
+
+void VectorImpl::pop()
+{
+    if (size())
+        removeItemsAt(size()-1, 1);
+}
+
+void VectorImpl::push()
+{
+    push(0);
+}
+
+void VectorImpl::push(const void* item)
+{
+    insertAt(item, size());
+}
+
+ssize_t VectorImpl::add()
+{
+    return add(0);
+}
+
+ssize_t VectorImpl::add(const void* item)
+{
+    return insertAt(item, size());
+}
+
+ssize_t VectorImpl::replaceAt(size_t index)
+{
+    return replaceAt(0, index);
+}
+
+ssize_t VectorImpl::replaceAt(const void* prototype, size_t index)
+{
+    LOG_ASSERT(index<size(),
+        "[%p] replace: index=%d, size=%d", this, (int)index, (int)size());
+
+    void* item = editItemLocation(index);
+    if (item == 0)
+        return NO_MEMORY;
+    _do_destroy(item, 1);
+    if (prototype == 0) {
+        _do_construct(item, 1);
+    } else {
+        _do_copy(item, prototype, 1);
+    }
+    return ssize_t(index);
+}
+
+ssize_t VectorImpl::removeItemsAt(size_t index, size_t count)
+{
+    LOG_ASSERT((index+count)<=size(),
+        "[%p] remove: index=%d, count=%d, size=%d",
+               this, (int)index, (int)count, (int)size());
+
+    if ((index+count) > size())
+        return BAD_VALUE;
+   _shrink(index, count);
+   return index;
+}
+
+void VectorImpl::finish_vector()
+{
+    release_storage();
+    mStorage = 0;
+    mCount = 0;
+}
+
+void VectorImpl::clear()
+{
+    _shrink(0, mCount);
+}
+
+void* VectorImpl::editItemLocation(size_t index)
+{
+    LOG_ASSERT(index<capacity(),
+        "[%p] itemLocation: index=%d, capacity=%d, count=%d",
+        this, (int)index, (int)capacity(), (int)mCount);
+            
+    void* buffer = editArrayImpl();
+    if (buffer)
+        return reinterpret_cast<char*>(buffer) + index*mItemSize;
+    return 0;
+}
+
+const void* VectorImpl::itemLocation(size_t index) const
+{
+    LOG_ASSERT(index<capacity(),
+        "[%p] editItemLocation: index=%d, capacity=%d, count=%d",
+        this, (int)index, (int)capacity(), (int)mCount);
+
+    const  void* buffer = arrayImpl();
+    if (buffer)
+        return reinterpret_cast<const char*>(buffer) + index*mItemSize;
+    return 0;
+}
+
+ssize_t VectorImpl::setCapacity(size_t new_capacity)
+{
+    size_t current_capacity = capacity();
+    ssize_t amount = new_capacity - size();
+    if (amount <= 0) {
+        // we can't reduce the capacity
+        return current_capacity;
+    } 
+    SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
+    if (sb) {
+        void* array = sb->data();
+        _do_copy(array, mStorage, size());
+        release_storage();
+        mStorage = const_cast<void*>(array);
+    } else {
+        return NO_MEMORY;
+    }
+    return new_capacity;
+}
+
+void VectorImpl::release_storage()
+{
+    if (mStorage) {
+        const SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage);
+        if (sb->release(SharedBuffer::eKeepStorage) == 1) {
+            _do_destroy(mStorage, mCount);
+            SharedBuffer::dealloc(sb);
+        } 
+    }
+}
+
+void* VectorImpl::_grow(size_t where, size_t amount)
+{
+//    LOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
+//        this, (int)where, (int)amount, (int)mCount, (int)capacity());
+
+    if (where > mCount)
+        where = mCount;
+      
+    const size_t new_size = mCount + amount;
+    if (capacity() < new_size) {
+        const size_t new_capacity = max(kMinVectorCapacity, ((new_size*3)+1)/2);
+//        LOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity);
+        if ((mStorage) &&
+            (mCount==where) &&
+            (mFlags & HAS_TRIVIAL_COPY) &&
+            (mFlags & HAS_TRIVIAL_DTOR))
+        {
+            const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
+            SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
+            mStorage = sb->data();
+        } else {
+            SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
+            if (sb) {
+                void* array = sb->data();
+                if (where>0) {
+                    _do_copy(array, mStorage, where);
+                }
+                if (mCount>where) {
+                    const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize;
+                    void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+                    _do_copy(dest, from, mCount-where);
+                }
+                release_storage();
+                mStorage = const_cast<void*>(array);
+            }
+        }
+    } else {
+        ssize_t s = mCount-where;
+        if (s>0) {
+            void* array = editArrayImpl();    
+            void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+            const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize;
+            _do_move_forward(to, from, s);
+        }
+    }
+    mCount += amount;
+    void* free_space = const_cast<void*>(itemLocation(where));
+    return free_space;
+}
+
+void VectorImpl::_shrink(size_t where, size_t amount)
+{
+    if (!mStorage)
+        return;
+
+//    LOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
+//        this, (int)where, (int)amount, (int)mCount, (int)capacity());
+
+    if (where >= mCount)
+        where = mCount - amount;
+
+    const size_t new_size = mCount - amount;
+    if (new_size*3 < capacity()) {
+        const size_t new_capacity = max(kMinVectorCapacity, new_size*2);
+//        LOGV("shrink vector %p, new_capacity=%d", this, (int)new_capacity);
+        if ((where == mCount-amount) &&
+            (mFlags & HAS_TRIVIAL_COPY) &&
+            (mFlags & HAS_TRIVIAL_DTOR))
+        {
+            const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
+            SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
+            mStorage = sb->data();
+        } else {
+            SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
+            if (sb) {
+                void* array = sb->data();
+                if (where>0) {
+                    _do_copy(array, mStorage, where);
+                }
+                if (mCount > where+amount) {
+                    const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize;
+                    void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
+                    _do_copy(dest, from, mCount-(where+amount));
+                }
+                release_storage();
+                mStorage = const_cast<void*>(array);
+            }
+        }
+    } else {
+        void* array = editArrayImpl();    
+        void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
+        _do_destroy(to, amount);
+        ssize_t s = mCount-(where+amount);
+        if (s>0) {
+            const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+            _do_move_backward(to, from, s);
+        }
+    }
+
+    // adjust the number of items...
+    mCount -= amount;
+}
+
+size_t VectorImpl::itemSize() const {
+    return mItemSize;
+}
+
+void VectorImpl::_do_construct(void* storage, size_t num) const
+{
+    if (!(mFlags & HAS_TRIVIAL_CTOR)) {
+        do_construct(storage, num);
+    }
+}
+
+void VectorImpl::_do_destroy(void* storage, size_t num) const
+{
+    if (!(mFlags & HAS_TRIVIAL_DTOR)) {
+        do_destroy(storage, num);
+    }
+}
+
+void VectorImpl::_do_copy(void* dest, const void* from, size_t num) const
+{
+    if (!(mFlags & HAS_TRIVIAL_COPY)) {
+        do_copy(dest, from, num);
+    } else {
+        memcpy(dest, from, num*itemSize());
+    }
+}
+
+void VectorImpl::_do_splat(void* dest, const void* item, size_t num) const {
+    do_splat(dest, item, num);
+}
+
+void VectorImpl::_do_move_forward(void* dest, const void* from, size_t num) const {
+    do_move_forward(dest, from, num);
+}
+
+void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) const {
+    do_move_backward(dest, from, num);
+}
+
+void VectorImpl::reservedVectorImpl1() { }
+void VectorImpl::reservedVectorImpl2() { }
+void VectorImpl::reservedVectorImpl3() { }
+void VectorImpl::reservedVectorImpl4() { }
+void VectorImpl::reservedVectorImpl5() { }
+void VectorImpl::reservedVectorImpl6() { }
+void VectorImpl::reservedVectorImpl7() { }
+void VectorImpl::reservedVectorImpl8() { }
+
+/*****************************************************************************/
+
+SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags)
+    : VectorImpl(itemSize, flags)
+{
+}
+
+SortedVectorImpl::SortedVectorImpl(const VectorImpl& rhs)
+: VectorImpl(rhs)
+{
+}
+
+SortedVectorImpl::~SortedVectorImpl()
+{
+}
+
+SortedVectorImpl& SortedVectorImpl::operator = (const SortedVectorImpl& rhs)
+{
+    return static_cast<SortedVectorImpl&>( VectorImpl::operator = (static_cast<const VectorImpl&>(rhs)) );
+}
+
+ssize_t SortedVectorImpl::indexOf(const void* item) const
+{
+    return _indexOrderOf(item);
+}
+
+size_t SortedVectorImpl::orderOf(const void* item) const
+{
+    size_t o;
+    _indexOrderOf(item, &o);
+    return o;
+}
+
+ssize_t SortedVectorImpl::_indexOrderOf(const void* item, size_t* order) const
+{
+    // binary search
+    ssize_t err = NAME_NOT_FOUND;
+    ssize_t l = 0;
+    ssize_t h = size()-1;
+    ssize_t mid;
+    const void* a = arrayImpl();
+    const size_t s = itemSize();
+    while (l <= h) {
+        mid = l + (h - l)/2;
+        const void* const curr = reinterpret_cast<const char *>(a) + (mid*s);
+        const int c = do_compare(curr, item);
+        if (c == 0) {
+            err = l = mid;
+            break;
+        } else if (c < 0) {
+            l = mid + 1;
+        } else {
+            h = mid - 1;
+        }
+    }
+    if (order) *order = l;
+    return err;
+}
+
+ssize_t SortedVectorImpl::add(const void* item)
+{
+    size_t order;
+    ssize_t index = _indexOrderOf(item, &order);
+    if (index < 0) {
+        index = VectorImpl::insertAt(item, order, 1);
+    } else {
+        index = VectorImpl::replaceAt(item, index);
+    }
+    return index;
+}
+
+ssize_t SortedVectorImpl::merge(const VectorImpl& vector)
+{
+    // naive merge...
+    if (!vector.isEmpty()) {
+        const void* buffer = vector.arrayImpl();
+        const size_t is = itemSize();
+        size_t s = vector.size();
+        for (size_t i=0 ; i<s ; i++) {
+            ssize_t err = add( reinterpret_cast<const char*>(buffer) + i*is );
+            if (err<0) {
+                return err;
+            }
+        }
+    }
+    return NO_ERROR;
+}
+
+ssize_t SortedVectorImpl::merge(const SortedVectorImpl& vector)
+{
+    // we've merging a sorted vector... nice!
+    ssize_t err = NO_ERROR;
+    if (!vector.isEmpty()) {
+        // first take care of the case where the vectors are sorted together
+        if (do_compare(vector.itemLocation(vector.size()-1), arrayImpl()) <= 0) {
+            err = VectorImpl::insertVectorAt(static_cast<const VectorImpl&>(vector), 0);
+        } else if (do_compare(vector.arrayImpl(), itemLocation(size()-1)) >= 0) {
+            err = VectorImpl::appendVector(static_cast<const VectorImpl&>(vector));
+        } else {
+            // this could be made a little better
+            err = merge(static_cast<const VectorImpl&>(vector));
+        }
+    }
+    return err;
+}
+
+ssize_t SortedVectorImpl::remove(const void* item)
+{
+    ssize_t i = indexOf(item);
+    if (i>=0) {
+        VectorImpl::removeItemsAt(i, 1);
+    }
+    return i;
+}
+
+void SortedVectorImpl::reservedSortedVectorImpl1() { };
+void SortedVectorImpl::reservedSortedVectorImpl2() { };
+void SortedVectorImpl::reservedSortedVectorImpl3() { };
+void SortedVectorImpl::reservedSortedVectorImpl4() { };
+void SortedVectorImpl::reservedSortedVectorImpl5() { };
+void SortedVectorImpl::reservedSortedVectorImpl6() { };
+void SortedVectorImpl::reservedSortedVectorImpl7() { };
+void SortedVectorImpl::reservedSortedVectorImpl8() { };
+
+
+/*****************************************************************************/
+
+}; // namespace android
+
diff --git a/libs/utils/ZipEntry.cpp b/libs/utils/ZipEntry.cpp
new file mode 100644
index 0000000..fbc9e67
--- /dev/null
+++ b/libs/utils/ZipEntry.cpp
@@ -0,0 +1,696 @@
+/*
+ * 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.
+ */
+
+//
+// Access to entries in a Zip archive.
+//
+
+#define LOG_TAG "zip"
+
+#include "utils/ZipEntry.h"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Initialize a new ZipEntry structure from a FILE* positioned at a
+ * CentralDirectoryEntry.
+ *
+ * On exit, the file pointer will be at the start of the next CDE or
+ * at the EOCD.
+ */
+status_t ZipEntry::initFromCDE(FILE* fp)
+{
+    status_t result;
+    long posn;
+    bool hasDD;
+
+    //LOGV("initFromCDE ---\n");
+
+    /* read the CDE */
+    result = mCDE.read(fp);
+    if (result != NO_ERROR) {
+        LOGD("mCDE.read failed\n");
+        return result;
+    }
+
+    //mCDE.dump();
+
+    /* using the info in the CDE, go load up the LFH */
+    posn = ftell(fp);
+    if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) {
+        LOGD("local header seek failed (%ld)\n",
+            mCDE.mLocalHeaderRelOffset);
+        return UNKNOWN_ERROR;
+    }
+
+    result = mLFH.read(fp);
+    if (result != NO_ERROR) {
+        LOGD("mLFH.read failed\n");
+        return result;
+    }
+
+    if (fseek(fp, posn, SEEK_SET) != 0)
+        return UNKNOWN_ERROR;
+
+    //mLFH.dump();
+
+    /*
+     * We *might* need to read the Data Descriptor at this point and
+     * integrate it into the LFH.  If this bit is set, the CRC-32,
+     * compressed size, and uncompressed size will be zero.  In practice
+     * these seem to be rare.
+     */
+    hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0;
+    if (hasDD) {
+        // do something clever
+        //LOGD("+++ has data descriptor\n");
+    }
+
+    /*
+     * Sanity-check the LFH.  Note that this will fail if the "kUsesDataDescr"
+     * flag is set, because the LFH is incomplete.  (Not a problem, since we
+     * prefer the CDE values.)
+     */
+    if (!hasDD && !compareHeaders()) {
+        LOGW("WARNING: header mismatch\n");
+        // keep going?
+    }
+
+    /*
+     * If the mVersionToExtract is greater than 20, we may have an
+     * issue unpacking the record -- could be encrypted, compressed
+     * with something we don't support, or use Zip64 extensions.  We
+     * can defer worrying about that to when we're extracting data.
+     */
+
+    return NO_ERROR;
+}
+
+/*
+ * Initialize a new entry.  Pass in the file name and an optional comment.
+ *
+ * Initializes the CDE and the LFH.
+ */
+void ZipEntry::initNew(const char* fileName, const char* comment)
+{
+    assert(fileName != NULL && *fileName != '\0');  // name required
+
+    /* most fields are properly initialized by constructor */
+    mCDE.mVersionMadeBy = kDefaultMadeBy;
+    mCDE.mVersionToExtract = kDefaultVersion;
+    mCDE.mCompressionMethod = kCompressStored;
+    mCDE.mFileNameLength = strlen(fileName);
+    if (comment != NULL)
+        mCDE.mFileCommentLength = strlen(comment);
+    mCDE.mExternalAttrs = 0x81b60020;   // matches what WinZip does
+
+    if (mCDE.mFileNameLength > 0) {
+        mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
+        strcpy((char*) mCDE.mFileName, fileName);
+    }
+    if (mCDE.mFileCommentLength > 0) {
+        /* TODO: stop assuming null-terminated ASCII here? */
+        mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
+        strcpy((char*) mCDE.mFileComment, comment);
+    }
+
+    copyCDEtoLFH();
+}
+
+/*
+ * Initialize a new entry, starting with the ZipEntry from a different
+ * archive.
+ *
+ * Initializes the CDE and the LFH.
+ */
+status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
+    const ZipEntry* pEntry)
+{
+    /*
+     * Copy everything in the CDE over, then fix up the hairy bits.
+     */
+    memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
+
+    if (mCDE.mFileNameLength > 0) {
+        mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
+        if (mCDE.mFileName == NULL)
+            return NO_MEMORY;
+        strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
+    }
+    if (mCDE.mFileCommentLength > 0) {
+        mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
+        if (mCDE.mFileComment == NULL)
+            return NO_MEMORY;
+        strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
+    }
+    if (mCDE.mExtraFieldLength > 0) {
+        /* we null-terminate this, though it may not be a string */
+        mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
+        if (mCDE.mExtraField == NULL)
+            return NO_MEMORY;
+        memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
+            mCDE.mExtraFieldLength+1);
+    }
+
+    /* construct the LFH from the CDE */
+    copyCDEtoLFH();
+
+    /*
+     * The LFH "extra" field is independent of the CDE "extra", so we
+     * handle it here.
+     */
+    assert(mLFH.mExtraField == NULL);
+    mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
+    if (mLFH.mExtraFieldLength > 0) {
+        mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
+        if (mLFH.mExtraField == NULL)
+            return NO_MEMORY;
+        memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
+            mLFH.mExtraFieldLength+1);
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Insert pad bytes in the LFH by tweaking the "extra" field.  This will
+ * potentially confuse something that put "extra" data in here earlier,
+ * but I can't find an actual problem.
+ */
+status_t ZipEntry::addPadding(int padding)
+{
+    if (padding <= 0)
+        return INVALID_OPERATION;
+
+    //LOGI("HEY: adding %d pad bytes to existing %d in %s\n",
+    //    padding, mLFH.mExtraFieldLength, mCDE.mFileName);
+
+    if (mLFH.mExtraFieldLength > 0) {
+        /* extend existing field */
+        unsigned char* newExtra;
+
+        newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
+        if (newExtra == NULL)
+            return NO_MEMORY;
+        memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
+        memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
+
+        delete[] mLFH.mExtraField;
+        mLFH.mExtraField = newExtra;
+        mLFH.mExtraFieldLength += padding;
+    } else {
+        /* create new field */
+        mLFH.mExtraField = new unsigned char[padding];
+        memset(mLFH.mExtraField, 0, padding);
+        mLFH.mExtraFieldLength = padding;
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Set the fields in the LFH equal to the corresponding fields in the CDE.
+ *
+ * This does not touch the LFH "extra" field.
+ */
+void ZipEntry::copyCDEtoLFH(void)
+{
+    mLFH.mVersionToExtract  = mCDE.mVersionToExtract;
+    mLFH.mGPBitFlag         = mCDE.mGPBitFlag;
+    mLFH.mCompressionMethod = mCDE.mCompressionMethod;
+    mLFH.mLastModFileTime   = mCDE.mLastModFileTime;
+    mLFH.mLastModFileDate   = mCDE.mLastModFileDate;
+    mLFH.mCRC32             = mCDE.mCRC32;
+    mLFH.mCompressedSize    = mCDE.mCompressedSize;
+    mLFH.mUncompressedSize  = mCDE.mUncompressedSize;
+    mLFH.mFileNameLength    = mCDE.mFileNameLength;
+    // the "extra field" is independent
+
+    delete[] mLFH.mFileName;
+    if (mLFH.mFileNameLength > 0) {
+        mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
+        strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
+    } else {
+        mLFH.mFileName = NULL;
+    }
+}
+
+/*
+ * Set some information about a file after we add it.
+ */
+void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+    int compressionMethod)
+{
+    mCDE.mCompressionMethod = compressionMethod;
+    mCDE.mCRC32 = crc32;
+    mCDE.mCompressedSize = compLen;
+    mCDE.mUncompressedSize = uncompLen;
+    mCDE.mCompressionMethod = compressionMethod;
+    if (compressionMethod == kCompressDeflated) {
+        mCDE.mGPBitFlag |= 0x0002;      // indicates maximum compression used
+    }
+    copyCDEtoLFH();
+}
+
+/*
+ * See if the data in mCDE and mLFH match up.  This is mostly useful for
+ * debugging these classes, but it can be used to identify damaged
+ * archives.
+ *
+ * Returns "false" if they differ.
+ */
+bool ZipEntry::compareHeaders(void) const
+{
+    if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
+        LOGV("cmp: VersionToExtract\n");
+        return false;
+    }
+    if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
+        LOGV("cmp: GPBitFlag\n");
+        return false;
+    }
+    if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
+        LOGV("cmp: CompressionMethod\n");
+        return false;
+    }
+    if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
+        LOGV("cmp: LastModFileTime\n");
+        return false;
+    }
+    if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
+        LOGV("cmp: LastModFileDate\n");
+        return false;
+    }
+    if (mCDE.mCRC32 != mLFH.mCRC32) {
+        LOGV("cmp: CRC32\n");
+        return false;
+    }
+    if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
+        LOGV("cmp: CompressedSize\n");
+        return false;
+    }
+    if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
+        LOGV("cmp: UncompressedSize\n");
+        return false;
+    }
+    if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
+        LOGV("cmp: FileNameLength\n");
+        return false;
+    }
+#if 0       // this seems to be used for padding, not real data
+    if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
+        LOGV("cmp: ExtraFieldLength\n");
+        return false;
+    }
+#endif
+    if (mCDE.mFileName != NULL) {
+        if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
+            LOGV("cmp: FileName\n");
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
+/*
+ * Convert the DOS date/time stamp into a UNIX time stamp.
+ */
+time_t ZipEntry::getModWhen(void) const
+{
+    struct tm parts;
+
+    parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
+    parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
+    parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
+    parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
+    parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
+    parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
+    parts.tm_wday = parts.tm_yday = 0;
+    parts.tm_isdst = -1;        // DST info "not available"
+
+    return mktime(&parts);
+}
+
+/*
+ * Set the CDE/LFH timestamp from UNIX time.
+ */
+void ZipEntry::setModWhen(time_t when)
+{
+#ifdef HAVE_LOCALTIME_R
+    struct tm tmResult;
+#endif
+    time_t even;
+    unsigned short zdate, ztime;
+
+    struct tm* ptm;
+
+    /* round up to an even number of seconds */
+    even = (time_t)(((unsigned long)(when) + 1) & (~1));
+
+    /* expand */
+#ifdef HAVE_LOCALTIME_R
+    ptm = localtime_r(&even, &tmResult);
+#else
+    ptm = localtime(&even);
+#endif
+
+    int year;
+    year = ptm->tm_year;
+    if (year < 80)
+        year = 80;
+
+    zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
+    ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
+
+    mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
+    mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
+}
+
+
+/*
+ * ===========================================================================
+ *      ZipEntry::LocalFileHeader
+ * ===========================================================================
+ */
+
+/*
+ * Read a local file header.
+ *
+ * On entry, "fp" points to the signature at the start of the header.
+ * On exit, "fp" points to the start of data.
+ */
+status_t ZipEntry::LocalFileHeader::read(FILE* fp)
+{
+    status_t result = NO_ERROR;
+    unsigned char buf[kLFHLen];
+
+    assert(mFileName == NULL);
+    assert(mExtraField == NULL);
+
+    if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
+        LOGD("whoops: didn't find expected signature\n");
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
+    mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
+    mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
+    mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
+    mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
+    mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
+    mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
+    mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
+    mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
+    mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
+
+    // TODO: validate sizes
+
+    /* grab filename */
+    if (mFileNameLength != 0) {
+        mFileName = new unsigned char[mFileNameLength+1];
+        if (mFileName == NULL) {
+            result = NO_MEMORY;
+            goto bail;
+        }
+        if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+        mFileName[mFileNameLength] = '\0';
+    }
+
+    /* grab extra field */
+    if (mExtraFieldLength != 0) {
+        mExtraField = new unsigned char[mExtraFieldLength+1];
+        if (mExtraField == NULL) {
+            result = NO_MEMORY;
+            goto bail;
+        }
+        if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+        mExtraField[mExtraFieldLength] = '\0';
+    }
+
+bail:
+    return result;
+}
+
+/*
+ * Write a local file header.
+ */
+status_t ZipEntry::LocalFileHeader::write(FILE* fp)
+{
+    unsigned char buf[kLFHLen];
+
+    ZipEntry::putLongLE(&buf[0x00], kSignature);
+    ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
+    ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
+    ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
+    ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
+    ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
+    ZipEntry::putLongLE(&buf[0x0e], mCRC32);
+    ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
+    ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
+    ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
+    ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
+
+    if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
+        return UNKNOWN_ERROR;
+
+    /* write filename */
+    if (mFileNameLength != 0) {
+        if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
+            return UNKNOWN_ERROR;
+    }
+
+    /* write "extra field" */
+    if (mExtraFieldLength != 0) {
+        if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
+            return UNKNOWN_ERROR;
+    }
+
+    return NO_ERROR;
+}
+
+
+/*
+ * Dump the contents of a LocalFileHeader object.
+ */
+void ZipEntry::LocalFileHeader::dump(void) const
+{
+    LOGD(" LocalFileHeader contents:\n");
+    LOGD("  versToExt=%u gpBits=0x%04x compression=%u\n",
+        mVersionToExtract, mGPBitFlag, mCompressionMethod);
+    LOGD("  modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
+        mLastModFileTime, mLastModFileDate, mCRC32);
+    LOGD("  compressedSize=%lu uncompressedSize=%lu\n",
+        mCompressedSize, mUncompressedSize);
+    LOGD("  filenameLen=%u extraLen=%u\n",
+        mFileNameLength, mExtraFieldLength);
+    if (mFileName != NULL)
+        LOGD("  filename: '%s'\n", mFileName);
+}
+
+
+/*
+ * ===========================================================================
+ *      ZipEntry::CentralDirEntry
+ * ===========================================================================
+ */
+
+/*
+ * Read the central dir entry that appears next in the file.
+ *
+ * On entry, "fp" should be positioned on the signature bytes for the
+ * entry.  On exit, "fp" will point at the signature word for the next
+ * entry or for the EOCD.
+ */
+status_t ZipEntry::CentralDirEntry::read(FILE* fp)
+{
+    status_t result = NO_ERROR;
+    unsigned char buf[kCDELen];
+
+    /* no re-use */
+    assert(mFileName == NULL);
+    assert(mExtraField == NULL);
+    assert(mFileComment == NULL);
+
+    if (fread(buf, 1, kCDELen, fp) != kCDELen) {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
+        LOGD("Whoops: didn't find expected signature\n");
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
+    mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
+    mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
+    mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
+    mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
+    mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
+    mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
+    mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
+    mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
+    mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
+    mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
+    mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
+    mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
+    mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
+    mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
+    mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
+
+    // TODO: validate sizes and offsets
+
+    /* grab filename */
+    if (mFileNameLength != 0) {
+        mFileName = new unsigned char[mFileNameLength+1];
+        if (mFileName == NULL) {
+            result = NO_MEMORY;
+            goto bail;
+        }
+        if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+        mFileName[mFileNameLength] = '\0';
+    }
+
+    /* read "extra field" */
+    if (mExtraFieldLength != 0) {
+        mExtraField = new unsigned char[mExtraFieldLength+1];
+        if (mExtraField == NULL) {
+            result = NO_MEMORY;
+            goto bail;
+        }
+        if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+        mExtraField[mExtraFieldLength] = '\0';
+    }
+
+
+    /* grab comment, if any */
+    if (mFileCommentLength != 0) {
+        mFileComment = new unsigned char[mFileCommentLength+1];
+        if (mFileComment == NULL) {
+            result = NO_MEMORY;
+            goto bail;
+        }
+        if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
+        {
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+        mFileComment[mFileCommentLength] = '\0';
+    }
+
+bail:
+    return result;
+}
+
+/*
+ * Write a central dir entry.
+ */
+status_t ZipEntry::CentralDirEntry::write(FILE* fp)
+{
+    unsigned char buf[kCDELen];
+
+    ZipEntry::putLongLE(&buf[0x00], kSignature);
+    ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
+    ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
+    ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
+    ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
+    ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
+    ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
+    ZipEntry::putLongLE(&buf[0x10], mCRC32);
+    ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
+    ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
+    ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
+    ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
+    ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
+    ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
+    ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
+    ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
+    ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
+
+    if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
+        return UNKNOWN_ERROR;
+
+    /* write filename */
+    if (mFileNameLength != 0) {
+        if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
+            return UNKNOWN_ERROR;
+    }
+
+    /* write "extra field" */
+    if (mExtraFieldLength != 0) {
+        if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
+            return UNKNOWN_ERROR;
+    }
+
+    /* write comment */
+    if (mFileCommentLength != 0) {
+        if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
+            return UNKNOWN_ERROR;
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Dump the contents of a CentralDirEntry object.
+ */
+void ZipEntry::CentralDirEntry::dump(void) const
+{
+    LOGD(" CentralDirEntry contents:\n");
+    LOGD("  versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
+        mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
+    LOGD("  modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
+        mLastModFileTime, mLastModFileDate, mCRC32);
+    LOGD("  compressedSize=%lu uncompressedSize=%lu\n",
+        mCompressedSize, mUncompressedSize);
+    LOGD("  filenameLen=%u extraLen=%u commentLen=%u\n",
+        mFileNameLength, mExtraFieldLength, mFileCommentLength);
+    LOGD("  diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
+        mDiskNumberStart, mInternalAttrs, mExternalAttrs,
+        mLocalHeaderRelOffset);
+
+    if (mFileName != NULL)
+        LOGD("  filename: '%s'\n", mFileName);
+    if (mFileComment != NULL)
+        LOGD("  comment: '%s'\n", mFileComment);
+}
+
diff --git a/libs/utils/ZipFile.cpp b/libs/utils/ZipFile.cpp
new file mode 100644
index 0000000..89aa874
--- /dev/null
+++ b/libs/utils/ZipFile.cpp
@@ -0,0 +1,1296 @@
+/*
+ * 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.
+ */
+
+//
+// Access to Zip archives.
+//
+
+#define LOG_TAG "zip"
+
+#include "utils/ZipFile.h"
+#include "utils/ZipUtils.h"
+#include "utils/Log.h"
+
+#include <zlib.h>
+#define DEF_MEM_LEVEL 8                // normally in zutil.h?
+
+#include <memory.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Some environments require the "b", some choke on it.
+ */
+#define FILE_OPEN_RO        "rb"
+#define FILE_OPEN_RW        "r+b"
+#define FILE_OPEN_RW_CREATE "w+b"
+
+/* should live somewhere else? */
+static status_t errnoToStatus(int err)
+{
+    if (err == ENOENT)
+        return NAME_NOT_FOUND;
+    else if (err == EACCES)
+        return PERMISSION_DENIED;
+    else
+        return UNKNOWN_ERROR;
+}
+
+/*
+ * Open a file and parse its guts.
+ */
+status_t ZipFile::open(const char* zipFileName, int flags)
+{
+    bool newArchive = false;
+
+    assert(mZipFp == NULL);     // no reopen
+
+    if ((flags & kOpenTruncate))
+        flags |= kOpenCreate;           // trunc implies create
+
+    if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
+        return INVALID_OPERATION;       // not both
+    if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
+        return INVALID_OPERATION;       // not neither
+    if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
+        return INVALID_OPERATION;       // create requires write
+
+    if (flags & kOpenTruncate) {
+        newArchive = true;
+    } else {
+        newArchive = (access(zipFileName, F_OK) != 0);
+        if (!(flags & kOpenCreate) && newArchive) {
+            /* not creating, must already exist */
+            LOGD("File %s does not exist", zipFileName);
+            return NAME_NOT_FOUND;
+        }
+    }
+
+    /* open the file */
+    const char* openflags;
+    if (flags & kOpenReadWrite) {
+        if (newArchive)
+            openflags = FILE_OPEN_RW_CREATE;
+        else
+            openflags = FILE_OPEN_RW;
+    } else {
+        openflags = FILE_OPEN_RO;
+    }
+    mZipFp = fopen(zipFileName, openflags);
+    if (mZipFp == NULL) {
+		int err = errno;
+		LOGD("fopen failed: %d\n", err);
+        return errnoToStatus(err);
+	}
+
+    status_t result;
+    if (!newArchive) {
+        /*
+         * Load the central directory.  If that fails, then this probably
+         * isn't a Zip archive.
+         */
+        result = readCentralDir();
+    } else {
+        /*
+         * Newly-created.  The EndOfCentralDir constructor actually
+         * sets everything to be the way we want it (all zeroes).  We
+         * set mNeedCDRewrite so that we create *something* if the
+         * caller doesn't add any files.  (We could also just unlink
+         * the file if it's brand new and nothing was added, but that's
+         * probably doing more than we really should -- the user might
+         * have a need for empty zip files.)
+         */
+        mNeedCDRewrite = true;
+        result = NO_ERROR;
+    }
+
+    if (flags & kOpenReadOnly)
+        mReadOnly = true;
+    else
+        assert(!mReadOnly);
+
+    return result;
+}
+
+/*
+ * Return the Nth entry in the archive.
+ */
+ZipEntry* ZipFile::getEntryByIndex(int idx) const
+{
+    if (idx < 0 || idx >= (int) mEntries.size())
+        return NULL;
+
+    return mEntries[idx];
+}
+
+/*
+ * Find an entry by name.
+ */
+ZipEntry* ZipFile::getEntryByName(const char* fileName) const
+{
+    /*
+     * Do a stupid linear string-compare search.
+     *
+     * There are various ways to speed this up, especially since it's rare
+     * to intermingle changes to the archive with "get by name" calls.  We
+     * don't want to sort the mEntries vector itself, however, because
+     * it's used to recreate the Central Directory.
+     *
+     * (Hash table works, parallel list of pointers in sorted order is good.)
+     */
+    int idx;
+
+    for (idx = mEntries.size()-1; idx >= 0; idx--) {
+        ZipEntry* pEntry = mEntries[idx];
+        if (!pEntry->getDeleted() &&
+            strcmp(fileName, pEntry->getFileName()) == 0)
+        {
+            return pEntry;
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Empty the mEntries vector.
+ */
+void ZipFile::discardEntries(void)
+{
+    int count = mEntries.size();
+
+    while (--count >= 0)
+        delete mEntries[count];
+
+    mEntries.clear();
+}
+
+
+/*
+ * Find the central directory and read the contents.
+ *
+ * The fun thing about ZIP archives is that they may or may not be
+ * readable from start to end.  In some cases, notably for archives
+ * that were written to stdout, the only length information is in the
+ * central directory at the end of the file.
+ *
+ * Of course, the central directory can be followed by a variable-length
+ * comment field, so we have to scan through it backwards.  The comment
+ * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
+ * itself, plus apparently sometimes people throw random junk on the end
+ * just for the fun of it.
+ *
+ * This is all a little wobbly.  If the wrong value ends up in the EOCD
+ * area, we're hosed.  This appears to be the way that everbody handles
+ * it though, so we're in pretty good company if this fails.
+ */
+status_t ZipFile::readCentralDir(void)
+{
+    status_t result = NO_ERROR;
+    unsigned char* buf = NULL;
+    off_t fileLength, seekStart;
+    long readAmount;
+    int i;
+
+    fseek(mZipFp, 0, SEEK_END);
+    fileLength = ftell(mZipFp);
+    rewind(mZipFp);
+
+    /* too small to be a ZIP archive? */
+    if (fileLength < EndOfCentralDir::kEOCDLen) {
+        LOGD("Length is %ld -- too small\n", (long)fileLength);
+        result = INVALID_OPERATION;
+        goto bail;
+    }
+
+    buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
+    if (buf == NULL) {
+		LOGD("Failure allocating %d bytes for EOCD search",
+			 EndOfCentralDir::kMaxEOCDSearch);
+        result = NO_MEMORY;
+        goto bail;
+    }
+
+    if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
+        seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
+        readAmount = EndOfCentralDir::kMaxEOCDSearch;
+    } else {
+        seekStart = 0;
+        readAmount = (long) fileLength;
+    }
+    if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
+		LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    /* read the last part of the file into the buffer */
+    if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
+        LOGD("short file? wanted %ld\n", readAmount);
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    /* find the end-of-central-dir magic */
+    for (i = readAmount - 4; i >= 0; i--) {
+        if (buf[i] == 0x50 &&
+            ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
+        {
+            LOGV("+++ Found EOCD at buf+%d\n", i);
+            break;
+        }
+    }
+    if (i < 0) {
+        LOGD("EOCD not found, not Zip\n");
+        result = INVALID_OPERATION;
+        goto bail;
+    }
+
+    /* extract eocd values */
+    result = mEOCD.readBuf(buf + i, readAmount - i);
+    if (result != NO_ERROR) {
+		LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
+        goto bail;
+	}
+    //mEOCD.dump();
+
+    if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
+        mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
+    {
+        LOGD("Archive spanning not supported\n");
+        result = INVALID_OPERATION;
+        goto bail;
+    }
+
+    /*
+     * So far so good.  "mCentralDirSize" is the size in bytes of the
+     * central directory, so we can just seek back that far to find it.
+     * We can also seek forward mCentralDirOffset bytes from the
+     * start of the file.
+     *
+     * We're not guaranteed to have the rest of the central dir in the
+     * buffer, nor are we guaranteed that the central dir will have any
+     * sort of convenient size.  We need to skip to the start of it and
+     * read the header, then the other goodies.
+     *
+     * The only thing we really need right now is the file comment, which
+     * we're hoping to preserve.
+     */
+    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+		LOGD("Failure seeking to central dir offset %ld\n",
+			 mEOCD.mCentralDirOffset);
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    /*
+     * Loop through and read the central dir entries.
+     */
+    LOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
+    int entry;
+    for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
+        ZipEntry* pEntry = new ZipEntry;
+
+        result = pEntry->initFromCDE(mZipFp);
+        if (result != NO_ERROR) {
+            LOGD("initFromCDE failed\n");
+            delete pEntry;
+            goto bail;
+        }
+
+        mEntries.add(pEntry);
+    }
+
+
+    /*
+     * If all went well, we should now be back at the EOCD.
+     */
+    {
+        unsigned char checkBuf[4];
+        if (fread(checkBuf, 1, 4, mZipFp) != 4) {
+            LOGD("EOCD check read failed\n");
+            result = INVALID_OPERATION;
+            goto bail;
+        }
+        if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
+            LOGD("EOCD read check failed\n");
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+        LOGV("+++ EOCD read check passed\n");
+    }
+
+bail:
+    delete[] buf;
+    return result;
+}
+
+
+/*
+ * Add a new file to the archive.
+ *
+ * This requires creating and populating a ZipEntry structure, and copying
+ * the data into the file at the appropriate position.  The "appropriate
+ * position" is the current location of the central directory, which we
+ * casually overwrite (we can put it back later).
+ *
+ * If we were concerned about safety, we would want to make all changes
+ * in a temp file and then overwrite the original after everything was
+ * safely written.  Not really a concern for us.
+ */
+status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
+    const char* storageName, int sourceType, int compressionMethod,
+    ZipEntry** ppEntry)
+{
+    ZipEntry* pEntry = NULL;
+    status_t result = NO_ERROR;
+    long lfhPosn, startPosn, endPosn, uncompressedLen;
+    FILE* inputFp = NULL;
+    unsigned long crc;
+    time_t modWhen;
+
+    if (mReadOnly)
+        return INVALID_OPERATION;
+
+    assert(compressionMethod == ZipEntry::kCompressDeflated ||
+           compressionMethod == ZipEntry::kCompressStored);
+
+    /* make sure we're in a reasonable state */
+    assert(mZipFp != NULL);
+    assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+    /* make sure it doesn't already exist */
+    if (getEntryByName(storageName) != NULL)
+        return ALREADY_EXISTS;
+
+    if (!data) {
+        inputFp = fopen(fileName, FILE_OPEN_RO);
+        if (inputFp == NULL)
+            return errnoToStatus(errno);
+    }
+
+    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    pEntry = new ZipEntry;
+    pEntry->initNew(storageName, NULL);
+
+    /*
+     * From here on out, failures are more interesting.
+     */
+    mNeedCDRewrite = true;
+
+    /*
+     * Write the LFH, even though it's still mostly blank.  We need it
+     * as a place-holder.  In theory the LFH isn't necessary, but in
+     * practice some utilities demand it.
+     */
+    lfhPosn = ftell(mZipFp);
+    pEntry->mLFH.write(mZipFp);
+    startPosn = ftell(mZipFp);
+
+    /*
+     * Copy the data in, possibly compressing it as we go.
+     */
+    if (sourceType == ZipEntry::kCompressStored) {
+        if (compressionMethod == ZipEntry::kCompressDeflated) {
+            bool failed = false;
+            result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
+            if (result != NO_ERROR) {
+                LOGD("compression failed, storing\n");
+                failed = true;
+            } else {
+                /*
+                 * Make sure it has compressed "enough".  This probably ought
+                 * to be set through an API call, but I don't expect our
+                 * criteria to change over time.
+                 */
+                long src = inputFp ? ftell(inputFp) : size;
+                long dst = ftell(mZipFp) - startPosn;
+                if (dst + (dst / 10) > src) {
+                    LOGD("insufficient compression (src=%ld dst=%ld), storing\n",
+                        src, dst);
+                    failed = true;
+                }
+            }
+
+            if (failed) {
+                compressionMethod = ZipEntry::kCompressStored;
+                if (inputFp) rewind(inputFp);
+                fseek(mZipFp, startPosn, SEEK_SET);
+                /* fall through to kCompressStored case */
+            }
+        }
+        /* handle "no compression" request, or failed compression from above */
+        if (compressionMethod == ZipEntry::kCompressStored) {
+            if (inputFp) {
+                result = copyFpToFp(mZipFp, inputFp, &crc);
+            } else {
+                result = copyDataToFp(mZipFp, data, size, &crc);
+            }
+            if (result != NO_ERROR) {
+                // don't need to truncate; happens in CDE rewrite
+                LOGD("failed copying data in\n");
+                goto bail;
+            }
+        }
+
+        // currently seeked to end of file
+        uncompressedLen = inputFp ? ftell(inputFp) : size;
+    } else if (sourceType == ZipEntry::kCompressDeflated) {
+        /* we should support uncompressed-from-compressed, but it's not
+         * important right now */
+        assert(compressionMethod == ZipEntry::kCompressDeflated);
+
+        bool scanResult;
+        int method;
+        long compressedLen;
+
+        scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
+                        &compressedLen, &crc);
+        if (!scanResult || method != ZipEntry::kCompressDeflated) {
+            LOGD("this isn't a deflated gzip file?");
+            result = UNKNOWN_ERROR;
+            goto bail;
+        }
+
+        result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
+        if (result != NO_ERROR) {
+            LOGD("failed copying gzip data in\n");
+            goto bail;
+        }
+    } else {
+        assert(false);
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    /*
+     * We could write the "Data Descriptor", but there doesn't seem to
+     * be any point since we're going to go back and write the LFH.
+     *
+     * Update file offsets.
+     */
+    endPosn = ftell(mZipFp);            // seeked to end of compressed data
+
+    /*
+     * Success!  Fill out new values.
+     */
+    pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
+        compressionMethod);
+    modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
+    pEntry->setModWhen(modWhen);
+    pEntry->setLFHOffset(lfhPosn);
+    mEOCD.mNumEntries++;
+    mEOCD.mTotalNumEntries++;
+    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
+    mEOCD.mCentralDirOffset = endPosn;
+
+    /*
+     * Go back and write the LFH.
+     */
+    if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+    pEntry->mLFH.write(mZipFp);
+
+    /*
+     * Add pEntry to the list.
+     */
+    mEntries.add(pEntry);
+    if (ppEntry != NULL)
+        *ppEntry = pEntry;
+    pEntry = NULL;
+
+bail:
+    if (inputFp != NULL)
+        fclose(inputFp);
+    delete pEntry;
+    return result;
+}
+
+/*
+ * Add an entry by copying it from another zip file.  If "padding" is
+ * nonzero, the specified number of bytes will be added to the "extra"
+ * field in the header.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+    int padding, ZipEntry** ppEntry)
+{
+    ZipEntry* pEntry = NULL;
+    status_t result;
+    long lfhPosn, endPosn;
+
+    if (mReadOnly)
+        return INVALID_OPERATION;
+
+    /* make sure we're in a reasonable state */
+    assert(mZipFp != NULL);
+    assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    pEntry = new ZipEntry;
+    if (pEntry == NULL) {
+        result = NO_MEMORY;
+        goto bail;
+    }
+
+    result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
+    if (result != NO_ERROR)
+        goto bail;
+    if (padding != 0) {
+        result = pEntry->addPadding(padding);
+        if (result != NO_ERROR)
+            goto bail;
+    }
+
+    /*
+     * From here on out, failures are more interesting.
+     */
+    mNeedCDRewrite = true;
+
+    /*
+     * Write the LFH.  Since we're not recompressing the data, we already
+     * have all of the fields filled out.
+     */
+    lfhPosn = ftell(mZipFp);
+    pEntry->mLFH.write(mZipFp);
+
+    /*
+     * Copy the data over.
+     *
+     * If the "has data descriptor" flag is set, we want to copy the DD
+     * fields as well.  This is a fixed-size area immediately following
+     * the data.
+     */
+    if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
+    {
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    off_t copyLen;
+    copyLen = pSourceEntry->getCompressedLen();
+    if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
+        copyLen += ZipEntry::kDataDescriptorLen;
+
+    if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
+        != NO_ERROR)
+    {
+        LOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
+        result = UNKNOWN_ERROR;
+        goto bail;
+    }
+
+    /*
+     * Update file offsets.
+     */
+    endPosn = ftell(mZipFp);
+
+    /*
+     * Success!  Fill out new values.
+     */
+    pEntry->setLFHOffset(lfhPosn);      // sets mCDE.mLocalHeaderRelOffset
+    mEOCD.mNumEntries++;
+    mEOCD.mTotalNumEntries++;
+    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
+    mEOCD.mCentralDirOffset = endPosn;
+
+    /*
+     * Add pEntry to the list.
+     */
+    mEntries.add(pEntry);
+    if (ppEntry != NULL)
+        *ppEntry = pEntry;
+    pEntry = NULL;
+
+    result = NO_ERROR;
+
+bail:
+    delete pEntry;
+    return result;
+}
+
+/*
+ * Copy all of the bytes in "src" to "dst".
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the data.
+ */
+status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
+{
+    unsigned char tmpBuf[32768];
+    size_t count;
+
+    *pCRC32 = crc32(0L, Z_NULL, 0);
+
+    while (1) {
+        count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
+        if (ferror(srcFp) || ferror(dstFp))
+            return errnoToStatus(errno);
+        if (count == 0)
+            break;
+
+        *pCRC32 = crc32(*pCRC32, tmpBuf, count);
+
+        if (fwrite(tmpBuf, 1, count, dstFp) != count) {
+            LOGD("fwrite %d bytes failed\n", (int) count);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Copy all of the bytes in "src" to "dst".
+ *
+ * On exit, "dstFp" will be seeked immediately past the data.
+ */
+status_t ZipFile::copyDataToFp(FILE* dstFp,
+    const void* data, size_t size, unsigned long* pCRC32)
+{
+    size_t count;
+
+    *pCRC32 = crc32(0L, Z_NULL, 0);
+    if (size > 0) {
+        *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
+        if (fwrite(data, 1, size, dstFp) != size) {
+            LOGD("fwrite %d bytes failed\n", (int) size);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Copy some of the bytes in "src" to "dst".
+ *
+ * If "pCRC32" is NULL, the CRC will not be computed.
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the data just written.
+ */
+status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+    unsigned long* pCRC32)
+{
+    unsigned char tmpBuf[32768];
+    size_t count;
+
+    if (pCRC32 != NULL)
+        *pCRC32 = crc32(0L, Z_NULL, 0);
+
+    while (length) {
+        long readSize;
+        
+        readSize = sizeof(tmpBuf);
+        if (readSize > length)
+            readSize = length;
+
+        count = fread(tmpBuf, 1, readSize, srcFp);
+        if ((long) count != readSize) {     // error or unexpected EOF
+            LOGD("fread %d bytes failed\n", (int) readSize);
+            return UNKNOWN_ERROR;
+        }
+
+        if (pCRC32 != NULL)
+            *pCRC32 = crc32(*pCRC32, tmpBuf, count);
+
+        if (fwrite(tmpBuf, 1, count, dstFp) != count) {
+            LOGD("fwrite %d bytes failed\n", (int) count);
+            return UNKNOWN_ERROR;
+        }
+
+        length -= readSize;
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Compress all of the data in "srcFp" and write it to "dstFp".
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the compressed data.
+ */
+status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
+    const void* data, size_t size, unsigned long* pCRC32)
+{
+    status_t result = NO_ERROR;
+	const size_t kBufSize = 32768;
+	unsigned char* inBuf = NULL;
+	unsigned char* outBuf = NULL;
+	z_stream zstream;
+    bool atEof = false;     // no feof() aviailable yet
+	unsigned long crc;
+	int zerr;
+
+	/*
+	 * Create an input buffer and an output buffer.
+	 */
+	inBuf = new unsigned char[kBufSize];
+	outBuf = new unsigned char[kBufSize];
+	if (inBuf == NULL || outBuf == NULL) {
+		result = NO_MEMORY;
+		goto bail;
+	}
+
+	/*
+	 * Initialize the zlib stream.
+	 */
+	memset(&zstream, 0, sizeof(zstream));
+	zstream.zalloc = Z_NULL;
+	zstream.zfree = Z_NULL;
+	zstream.opaque = Z_NULL;
+	zstream.next_in = NULL;
+	zstream.avail_in = 0;
+	zstream.next_out = outBuf;
+	zstream.avail_out = kBufSize;
+	zstream.data_type = Z_UNKNOWN;
+
+	zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
+		Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+	if (zerr != Z_OK) {
+		result = UNKNOWN_ERROR;
+		if (zerr == Z_VERSION_ERROR) {
+			LOGE("Installed zlib is not compatible with linked version (%s)\n",
+				ZLIB_VERSION);
+		} else {
+			LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
+		}
+		goto bail;
+	}
+
+ 	crc = crc32(0L, Z_NULL, 0);
+
+	/*
+	 * Loop while we have data.
+	 */
+	do {
+		size_t getSize;
+		int flush;
+
+		/* only read if the input buffer is empty */
+		if (zstream.avail_in == 0 && !atEof) {
+            LOGV("+++ reading %d bytes\n", (int)kBufSize);
+            if (data) {
+                getSize = size > kBufSize ? kBufSize : size;
+                memcpy(inBuf, data, getSize);
+                data = ((const char*)data) + getSize;
+                size -= getSize;
+            } else {
+                getSize = fread(inBuf, 1, kBufSize, srcFp);
+                if (ferror(srcFp)) {
+                    LOGD("deflate read failed (errno=%d)\n", errno);
+                    goto z_bail;
+                }
+            }
+            if (getSize < kBufSize) {
+                LOGV("+++  got %d bytes, EOF reached\n",
+                    (int)getSize);
+                atEof = true;
+            }
+
+			crc = crc32(crc, inBuf, getSize);
+
+			zstream.next_in = inBuf;
+			zstream.avail_in = getSize;
+		}
+
+		if (atEof)
+			flush = Z_FINISH;       /* tell zlib that we're done */
+		else
+			flush = Z_NO_FLUSH;     /* more to come! */
+
+		zerr = deflate(&zstream, flush);
+		if (zerr != Z_OK && zerr != Z_STREAM_END) {
+			LOGD("zlib deflate call failed (zerr=%d)\n", zerr);
+			result = UNKNOWN_ERROR;
+			goto z_bail;
+		}
+
+		/* write when we're full or when we're done */
+		if (zstream.avail_out == 0 ||
+			(zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
+		{
+			LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
+            if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
+                (size_t)(zstream.next_out - outBuf))
+            {
+				LOGD("write %d failed in deflate\n",
+                    (int) (zstream.next_out - outBuf));
+				goto z_bail;
+			}
+
+			zstream.next_out = outBuf;
+			zstream.avail_out = kBufSize;
+		}
+	} while (zerr == Z_OK);
+
+	assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
+
+	*pCRC32 = crc;
+
+z_bail:
+	deflateEnd(&zstream);        /* free up any allocated structures */
+
+bail:
+	delete[] inBuf;
+	delete[] outBuf;
+
+	return result;
+}
+
+/*
+ * Mark an entry as deleted.
+ *
+ * We will eventually need to crunch the file down, but if several files
+ * are being removed (perhaps as part of an "update" process) we can make
+ * things considerably faster by deferring the removal to "flush" time.
+ */
+status_t ZipFile::remove(ZipEntry* pEntry)
+{
+    /*
+     * Should verify that pEntry is actually part of this archive, and
+     * not some stray ZipEntry from a different file.
+     */
+
+    /* mark entry as deleted, and mark archive as dirty */
+    pEntry->setDeleted();
+    mNeedCDRewrite = true;
+    return NO_ERROR;
+}
+
+/*
+ * Flush any pending writes.
+ *
+ * In particular, this will crunch out deleted entries, and write the
+ * Central Directory and EOCD if we have stomped on them.
+ */
+status_t ZipFile::flush(void)
+{
+    status_t result = NO_ERROR;
+    long eocdPosn;
+    int i, count;
+
+    if (mReadOnly)
+        return INVALID_OPERATION;
+    if (!mNeedCDRewrite)
+        return NO_ERROR;
+
+    assert(mZipFp != NULL);
+
+    result = crunchArchive();
+    if (result != NO_ERROR)
+        return result;
+
+    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
+        return UNKNOWN_ERROR;
+
+    count = mEntries.size();
+    for (i = 0; i < count; i++) {
+        ZipEntry* pEntry = mEntries[i];
+        pEntry->mCDE.write(mZipFp);
+    }
+
+    eocdPosn = ftell(mZipFp);
+    mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
+
+    mEOCD.write(mZipFp);
+
+    /*
+     * If we had some stuff bloat up during compression and get replaced
+     * with plain files, or if we deleted some entries, there's a lot
+     * of wasted space at the end of the file.  Remove it now.
+     */
+    if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
+        LOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
+        // not fatal
+    }
+
+    /* should we clear the "newly added" flag in all entries now? */
+
+    mNeedCDRewrite = false;
+    return NO_ERROR;
+}
+
+/*
+ * Crunch deleted files out of an archive by shifting the later files down.
+ *
+ * Because we're not using a temp file, we do the operation inside the
+ * current file.
+ */
+status_t ZipFile::crunchArchive(void)
+{
+    status_t result = NO_ERROR;
+    int i, count;
+    long delCount, adjust;
+
+#if 0
+    printf("CONTENTS:\n");
+    for (i = 0; i < (int) mEntries.size(); i++) {
+        printf(" %d: lfhOff=%ld del=%d\n",
+            i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
+    }
+    printf("  END is %ld\n", (long) mEOCD.mCentralDirOffset);
+#endif
+
+    /*
+     * Roll through the set of files, shifting them as appropriate.  We
+     * could probably get a slight performance improvement by sliding
+     * multiple files down at once (because we could use larger reads
+     * when operating on batches of small files), but it's not that useful.
+     */
+    count = mEntries.size();
+    delCount = adjust = 0;
+    for (i = 0; i < count; i++) {
+        ZipEntry* pEntry = mEntries[i];
+        long span;
+
+        if (pEntry->getLFHOffset() != 0) {
+            long nextOffset;
+
+            /* Get the length of this entry by finding the offset
+             * of the next entry.  Directory entries don't have
+             * file offsets, so we need to find the next non-directory
+             * entry.
+             */
+            nextOffset = 0;
+            for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
+                nextOffset = mEntries[ii]->getLFHOffset();
+            if (nextOffset == 0)
+                nextOffset = mEOCD.mCentralDirOffset;
+            span = nextOffset - pEntry->getLFHOffset();
+
+            assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
+        } else {
+            /* This is a directory entry.  It doesn't have
+             * any actual file contents, so there's no need to
+             * move anything.
+             */
+            span = 0;
+        }
+
+        //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
+        //    i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
+
+        if (pEntry->getDeleted()) {
+            adjust += span;
+            delCount++;
+
+            delete pEntry;
+            mEntries.removeAt(i);
+
+            /* adjust loop control */
+            count--;
+            i--;
+        } else if (span != 0 && adjust > 0) {
+            /* shuffle this entry back */
+            //printf("+++ Shuffling '%s' back %ld\n",
+            //    pEntry->getFileName(), adjust);
+            result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
+                        pEntry->getLFHOffset(), span);
+            if (result != NO_ERROR) {
+                /* this is why you use a temp file */
+                LOGE("error during crunch - archive is toast\n");
+                return result;
+            }
+
+            pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
+        }
+    }
+
+    /*
+     * Fix EOCD info.  We have to wait until the end to do some of this
+     * because we use mCentralDirOffset to determine "span" for the
+     * last entry.
+     */
+    mEOCD.mCentralDirOffset -= adjust;
+    mEOCD.mNumEntries -= delCount;
+    mEOCD.mTotalNumEntries -= delCount;
+    mEOCD.mCentralDirSize = 0;  // mark invalid; set by flush()
+
+    assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
+    assert(mEOCD.mNumEntries == count);
+
+    return result;
+}
+
+/*
+ * Works like memmove(), but on pieces of a file.
+ */
+status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
+{
+    if (dst == src || n <= 0)
+        return NO_ERROR;
+
+    unsigned char readBuf[32768];
+
+    if (dst < src) {
+        /* shift stuff toward start of file; must read from start */
+        while (n != 0) {
+            size_t getSize = sizeof(readBuf);
+            if (getSize > n)
+                getSize = n;
+
+            if (fseek(fp, (long) src, SEEK_SET) != 0) {
+                LOGD("filemove src seek %ld failed\n", (long) src);
+                return UNKNOWN_ERROR;
+            }
+
+            if (fread(readBuf, 1, getSize, fp) != getSize) {
+                LOGD("filemove read %ld off=%ld failed\n",
+                    (long) getSize, (long) src);
+                return UNKNOWN_ERROR;
+            }
+
+            if (fseek(fp, (long) dst, SEEK_SET) != 0) {
+                LOGD("filemove dst seek %ld failed\n", (long) dst);
+                return UNKNOWN_ERROR;
+            }
+
+            if (fwrite(readBuf, 1, getSize, fp) != getSize) {
+                LOGD("filemove write %ld off=%ld failed\n",
+                    (long) getSize, (long) dst);
+                return UNKNOWN_ERROR;
+            }
+
+            src += getSize;
+            dst += getSize;
+            n -= getSize;
+        }
+    } else {
+        /* shift stuff toward end of file; must read from end */
+        assert(false);      // write this someday, maybe
+        return UNKNOWN_ERROR;
+    }
+
+    return NO_ERROR;
+}
+
+
+/*
+ * Get the modification time from a file descriptor.
+ */
+time_t ZipFile::getModTime(int fd)
+{
+    struct stat sb;
+
+    if (fstat(fd, &sb) < 0) {
+        LOGD("HEY: fstat on fd %d failed\n", fd);
+        return (time_t) -1;
+    }
+
+    return sb.st_mtime;
+}
+
+
+#if 0       /* this is a bad idea */
+/*
+ * Get a copy of the Zip file descriptor.
+ *
+ * We don't allow this if the file was opened read-write because we tend
+ * to leave the file contents in an uncertain state between calls to
+ * flush().  The duplicated file descriptor should only be valid for reads.
+ */
+int ZipFile::getZipFd(void) const
+{
+    if (!mReadOnly)
+        return INVALID_OPERATION;
+    assert(mZipFp != NULL);
+
+    int fd;
+    fd = dup(fileno(mZipFp));
+    if (fd < 0) {
+        LOGD("didn't work, errno=%d\n", errno);
+    }
+
+    return fd;
+}
+#endif
+
+
+#if 0
+/*
+ * Expand data.
+ */
+bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
+{
+    return false;
+}
+#endif
+
+// free the memory when you're done
+void* ZipFile::uncompress(const ZipEntry* entry)
+{
+    size_t unlen = entry->getUncompressedLen();
+    size_t clen = entry->getCompressedLen();
+
+    void* buf = malloc(unlen);
+    if (buf == NULL) {
+        return NULL;
+    }
+
+    fseek(mZipFp, 0, SEEK_SET);
+
+    off_t offset = entry->getFileOffset();
+    if (fseek(mZipFp, offset, SEEK_SET) != 0) {
+        goto bail;
+    }
+
+    switch (entry->getCompressionMethod())
+    {
+        case ZipEntry::kCompressStored: {
+            ssize_t amt = fread(buf, 1, unlen, mZipFp);
+            if (amt != (ssize_t)unlen) {
+                goto bail;
+            }
+#if 0
+            printf("data...\n");
+            const unsigned char* p = (unsigned char*)buf;
+            const unsigned char* end = p+unlen;
+            for (int i=0; i<32 && p < end; i++) {
+                printf("0x%08x ", (int)(offset+(i*0x10)));
+                for (int j=0; j<0x10 && p < end; j++) {
+                    printf(" %02x", *p);
+                    p++;
+                }
+                printf("\n");
+            }
+#endif
+
+            }
+            break;
+        case ZipEntry::kCompressDeflated: {
+            if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
+                goto bail;
+            }
+            }
+            break;
+        default:
+            goto bail;
+    }
+    return buf;
+
+bail:
+    free(buf);
+    return NULL;
+}
+
+
+/*
+ * ===========================================================================
+ *		ZipFile::EndOfCentralDir
+ * ===========================================================================
+ */
+
+/*
+ * Read the end-of-central-dir fields.
+ *
+ * "buf" should be positioned at the EOCD signature, and should contain
+ * the entire EOCD area including the comment.
+ */
+status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
+{
+    /* don't allow re-use */
+    assert(mComment == NULL);
+
+    if (len < kEOCDLen) {
+        /* looks like ZIP file got truncated */
+        LOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
+            kEOCDLen, len);
+        return INVALID_OPERATION;
+    }
+
+    /* this should probably be an assert() */
+    if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
+        return UNKNOWN_ERROR;
+
+    mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
+    mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
+    mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
+    mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
+    mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
+    mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
+    mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
+
+    // TODO: validate mCentralDirOffset
+
+    if (mCommentLen > 0) {
+        if (kEOCDLen + mCommentLen > len) {
+            LOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
+                kEOCDLen, mCommentLen, len);
+            return UNKNOWN_ERROR;
+        }
+        mComment = new unsigned char[mCommentLen];
+        memcpy(mComment, buf + kEOCDLen, mCommentLen);
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Write an end-of-central-directory section.
+ */
+status_t ZipFile::EndOfCentralDir::write(FILE* fp)
+{
+    unsigned char buf[kEOCDLen];
+
+    ZipEntry::putLongLE(&buf[0x00], kSignature);
+    ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
+    ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
+    ZipEntry::putShortLE(&buf[0x08], mNumEntries);
+    ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
+    ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
+    ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
+    ZipEntry::putShortLE(&buf[0x14], mCommentLen);
+
+    if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
+        return UNKNOWN_ERROR;
+    if (mCommentLen > 0) {
+        assert(mComment != NULL);
+        if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
+            return UNKNOWN_ERROR;
+    }
+
+    return NO_ERROR;
+}
+
+/*
+ * Dump the contents of an EndOfCentralDir object.
+ */
+void ZipFile::EndOfCentralDir::dump(void) const
+{
+    LOGD(" EndOfCentralDir contents:\n");
+    LOGD("  diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
+        mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
+    LOGD("  centDirSize=%lu centDirOff=%lu commentLen=%u\n",
+        mCentralDirSize, mCentralDirOffset, mCommentLen);
+}
+
diff --git a/libs/utils/ZipFileCRO.cpp b/libs/utils/ZipFileCRO.cpp
new file mode 100644
index 0000000..d312daf
--- /dev/null
+++ b/libs/utils/ZipFileCRO.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 "utils/ZipFileCRO.h"
+#include "utils/ZipFileRO.h"
+
+using namespace android;
+
+ZipFileCRO ZipFileXRO_open(const char* path) {
+    ZipFileRO* zip = new ZipFileRO();
+    if (zip->open(path) == NO_ERROR) {
+        return (ZipFileCRO)zip;
+    }
+    return NULL;
+}
+
+void ZipFileCRO_destroy(ZipFileCRO zipToken) {
+    ZipFileRO* zip = (ZipFileRO*)zipToken;
+    delete zip;
+}
+
+ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zipToken,
+        const char* fileName) {
+    ZipFileRO* zip = (ZipFileRO*)zipToken;
+    return (ZipEntryCRO)zip->findEntryByName(fileName);
+}
+
+bool ZipFileCRO_getEntryInfo(ZipFileCRO zipToken, ZipEntryRO entryToken,
+        int* pMethod, long* pUncompLen,
+        long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) {
+    ZipFileRO* zip = (ZipFileRO*)zipToken;
+    ZipEntryRO entry = (ZipEntryRO)entryToken;
+    return zip->getEntryInfo(entry, pMethod, pUncompLen, pCompLen, pOffset,
+            pModWhen, pCrc32);
+}
+
+bool ZipFileCRO_uncompressEntry(ZipFileCRO zipToken, ZipEntryRO entryToken, int fd) {
+    ZipFileRO* zip = (ZipFileRO*)zipToken;
+    ZipEntryRO entry = (ZipEntryRO)entryToken;
+    return zip->uncompressEntry(entry, fd);
+}
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
new file mode 100644
index 0000000..ae8c719
--- /dev/null
+++ b/libs/utils/ZipFileRO.cpp
@@ -0,0 +1,724 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+//
+// Read-only access to Zip archives, with minimal heap allocation.
+//
+#define LOG_TAG "zipro"
+//#define LOG_NDEBUG 0
+#include "utils/ZipFileRO.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <zlib.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Zip file constants.
+ */
+#define kEOCDSignature      0x06054b50
+#define kEOCDLen            22
+#define kEOCDNumEntries     8               // offset to #of entries in file
+#define kEOCDFileOffset     16              // offset to central directory
+
+#define kMaxCommentLen      65535           // longest possible in ushort
+#define kMaxEOCDSearch      (kMaxCommentLen + kEOCDLen)
+
+#define kLFHSignature       0x04034b50
+#define kLFHLen             30              // excluding variable-len fields
+#define kLFHNameLen         26              // offset to filename length
+#define kLFHExtraLen        28              // offset to extra length
+
+#define kCDESignature       0x02014b50
+#define kCDELen             46              // excluding variable-len fields
+#define kCDEMethod          10              // offset to compression method
+#define kCDEModWhen         12              // offset to modification timestamp
+#define kCDECRC             16              // offset to entry CRC
+#define kCDECompLen         20              // offset to compressed length
+#define kCDEUncompLen       24              // offset to uncompressed length
+#define kCDENameLen         28              // offset to filename length
+#define kCDEExtraLen        30              // offset to extra length
+#define kCDECommentLen      32              // offset to comment length
+#define kCDELocalOffset     42              // offset to local hdr
+
+/*
+ * The values we return for ZipEntryRO use 0 as an invalid value, so we
+ * want to adjust the hash table index by a fixed amount.  Using a large
+ * value helps insure that people don't mix & match arguments, e.g. to
+ * findEntryByIndex().
+ */
+#define kZipEntryAdj        10000
+
+/*
+ * Convert a ZipEntryRO to a hash table index, verifying that it's in a
+ * valid range.
+ */
+int ZipFileRO::entryToIndex(const ZipEntryRO entry) const
+{
+    long ent = ((long) entry) - kZipEntryAdj;
+    if (ent < 0 || ent >= mHashTableSize || mHashTable[ent].name == NULL) {
+        LOGW("Invalid ZipEntryRO %p (%ld)\n", entry, ent);
+        return -1;
+    }
+    return ent;
+}
+
+
+/*
+ * Open the specified file read-only.  We memory-map the entire thing and
+ * close the file before returning.
+ */
+status_t ZipFileRO::open(const char* zipFileName)
+{
+    int fd = -1;
+    off_t length;
+
+    assert(mFileMap == NULL);
+
+    /*
+     * Open and map the specified file.
+     */
+    fd = ::open(zipFileName, O_RDONLY);
+    if (fd < 0) {
+        LOGW("Unable to open zip '%s': %s\n", zipFileName, strerror(errno));
+        return NAME_NOT_FOUND;
+    }
+
+    length = lseek(fd, 0, SEEK_END);
+    if (length < 0) {
+        close(fd);
+        return UNKNOWN_ERROR;
+    }
+
+    mFileMap = new FileMap();
+    if (mFileMap == NULL) {
+        close(fd);
+        return NO_MEMORY;
+    }
+    if (!mFileMap->create(zipFileName, fd, 0, length, true)) {
+        LOGW("Unable to map '%s': %s\n", zipFileName, strerror(errno));
+        close(fd);
+        return UNKNOWN_ERROR;
+    }
+
+    mFd = fd;
+
+    /*
+     * Got it mapped, verify it and create data structures for fast access.
+     */
+    if (!parseZipArchive()) {
+        mFileMap->release();
+        mFileMap = NULL;
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+/*
+ * Parse the Zip archive, verifying its contents and initializing internal
+ * data structures.
+ */
+bool ZipFileRO::parseZipArchive(void)
+{
+#define CHECK_OFFSET(_off) {                                                \
+        if ((unsigned int) (_off) >= maxOffset) {                           \
+            LOGE("ERROR: bad offset %u (max %d): %s\n",                     \
+                (unsigned int) (_off), maxOffset, #_off);                   \
+            goto bail;                                                      \
+        }                                                                   \
+    }
+    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
+    const unsigned char* ptr;
+    size_t length = mFileMap->getDataLength();
+    bool result = false;
+    unsigned int i, numEntries, cdOffset;
+    unsigned int val;
+
+    /*
+     * The first 4 bytes of the file will either be the local header
+     * signature for the first file (kLFHSignature) or, if the archive doesn't
+     * have any files in it, the end-of-central-directory signature
+     * (kEOCDSignature).
+     */
+    val = get4LE(basePtr);
+    if (val == kEOCDSignature) {
+        LOGI("Found Zip archive, but it looks empty\n");
+        goto bail;
+    } else if (val != kLFHSignature) {
+        LOGV("Not a Zip archive (found 0x%08x)\n", val);
+        goto bail;
+    }
+
+    /*
+     * Find the EOCD.  We'll find it immediately unless they have a file
+     * comment.
+     */
+    ptr = basePtr + length - kEOCDLen;
+
+    while (ptr >= basePtr) {
+        if (*ptr == (kEOCDSignature & 0xff) && get4LE(ptr) == kEOCDSignature)
+            break;
+        ptr--;
+    }
+    if (ptr < basePtr) {
+        LOGI("Could not find end-of-central-directory in Zip\n");
+        goto bail;
+    }
+
+    /*
+     * There are two interesting items in the EOCD block: the number of
+     * entries in the file, and the file offset of the start of the
+     * central directory.
+     *
+     * (There's actually a count of the #of entries in this file, and for
+     * all files which comprise a spanned archive, but for our purposes
+     * we're only interested in the current file.  Besides, we expect the
+     * two to be equivalent for our stuff.)
+     */
+    numEntries = get2LE(ptr + kEOCDNumEntries);
+    cdOffset = get4LE(ptr + kEOCDFileOffset);
+
+    /* valid offsets are [0,EOCD] */
+    unsigned int maxOffset;
+    maxOffset = (ptr - basePtr) +1;
+
+    LOGV("+++ numEntries=%d cdOffset=%d\n", numEntries, cdOffset);
+    if (numEntries == 0 || cdOffset >= length) {
+        LOGW("Invalid entries=%d offset=%d (len=%zd)\n",
+            numEntries, cdOffset, length);
+        goto bail;
+    }
+
+    /*
+     * Create hash table.  We have a minimum 75% load factor, possibly as
+     * low as 50% after we round off to a power of 2.
+     */
+    mNumEntries = numEntries;
+    mHashTableSize = roundUpPower2(1 + ((numEntries * 4) / 3));
+    mHashTable = (HashEntry*) calloc(1, sizeof(HashEntry) * mHashTableSize);
+
+    /*
+     * Walk through the central directory, adding entries to the hash
+     * table.
+     */
+    ptr = basePtr + cdOffset;
+    for (i = 0; i < numEntries; i++) {
+        unsigned int fileNameLen, extraLen, commentLen, localHdrOffset;
+        const unsigned char* localHdr;
+        unsigned int hash;
+
+        if (get4LE(ptr) != kCDESignature) {
+            LOGW("Missed a central dir sig (at %d)\n", i);
+            goto bail;
+        }
+        if (ptr + kCDELen > basePtr + length) {
+            LOGW("Ran off the end (at %d)\n", i);
+            goto bail;
+        }
+
+        localHdrOffset = get4LE(ptr + kCDELocalOffset);
+        CHECK_OFFSET(localHdrOffset);
+        fileNameLen = get2LE(ptr + kCDENameLen);
+        extraLen = get2LE(ptr + kCDEExtraLen);
+        commentLen = get2LE(ptr + kCDECommentLen);
+
+        //LOGV("+++ %d: localHdr=%d fnl=%d el=%d cl=%d\n",
+        //    i, localHdrOffset, fileNameLen, extraLen, commentLen);
+        //LOGV(" '%.*s'\n", fileNameLen, ptr + kCDELen);
+
+        /* add the CDE filename to the hash table */
+        hash = computeHash((const char*)ptr + kCDELen, fileNameLen);
+        addToHash((const char*)ptr + kCDELen, fileNameLen, hash);
+
+        localHdr = basePtr + localHdrOffset;
+        if (get4LE(localHdr) != kLFHSignature) {
+            LOGW("Bad offset to local header: %d (at %d)\n",
+                localHdrOffset, i);
+            goto bail;
+        }
+
+        ptr += kCDELen + fileNameLen + extraLen + commentLen;
+        CHECK_OFFSET(ptr - basePtr);
+    }
+
+    result = true;
+
+bail:
+    return result;
+#undef CHECK_OFFSET
+}
+
+
+/*
+ * Simple string hash function for non-null-terminated strings.
+ */
+/*static*/ unsigned int ZipFileRO::computeHash(const char* str, int len)
+{
+    unsigned int hash = 0;
+
+    while (len--)
+        hash = hash * 31 + *str++;
+
+    return hash;
+}
+
+/*
+ * Add a new entry to the hash table.
+ */
+void ZipFileRO::addToHash(const char* str, int strLen, unsigned int hash)
+{
+    int ent = hash & (mHashTableSize-1);
+
+    /*
+     * We over-allocate the table, so we're guaranteed to find an empty slot.
+     */
+    while (mHashTable[ent].name != NULL)
+        ent = (ent + 1) & (mHashTableSize-1);
+
+    mHashTable[ent].name = str;
+    mHashTable[ent].nameLen = strLen;
+}
+
+/*
+ * Find a matching entry.
+ *
+ * Returns 0 if not found.
+ */
+ZipEntryRO ZipFileRO::findEntryByName(const char* fileName) const
+{
+    int nameLen = strlen(fileName);
+    unsigned int hash = computeHash(fileName, nameLen);
+    int ent = hash & (mHashTableSize-1);
+
+    while (mHashTable[ent].name != NULL) {
+        if (mHashTable[ent].nameLen == nameLen &&
+            memcmp(mHashTable[ent].name, fileName, nameLen) == 0)
+        {
+            /* match */
+            return (ZipEntryRO) (ent + kZipEntryAdj);
+        }
+
+        ent = (ent + 1) & (mHashTableSize-1);
+    }
+
+    return NULL;
+}
+
+/*
+ * Find the Nth entry.
+ *
+ * This currently involves walking through the sparse hash table, counting
+ * non-empty entries.  If we need to speed this up we can either allocate
+ * a parallel lookup table or (perhaps better) provide an iterator interface.
+ */
+ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const
+{
+    if (idx < 0 || idx >= mNumEntries) {
+        LOGW("Invalid index %d\n", idx);
+        return NULL;
+    }
+
+    for (int ent = 0; ent < mHashTableSize; ent++) {
+        if (mHashTable[ent].name != NULL) {
+            if (idx-- == 0)
+                return (ZipEntryRO) (ent + kZipEntryAdj);
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Get the useful fields from the zip entry.
+ *
+ * Returns "false" if the offsets to the fields or the contents of the fields
+ * appear to be bogus.
+ */
+bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen,
+    long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const
+{
+    int ent = entryToIndex(entry);
+    if (ent < 0)
+        return false;
+
+    /*
+     * Recover the start of the central directory entry from the filename
+     * pointer.
+     */
+    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
+    const unsigned char* ptr = (const unsigned char*) mHashTable[ent].name;
+    size_t zipLength = mFileMap->getDataLength();
+
+    ptr -= kCDELen;
+
+    int method = get2LE(ptr + kCDEMethod);
+    if (pMethod != NULL)
+        *pMethod = method;
+
+    if (pModWhen != NULL)
+        *pModWhen = get4LE(ptr + kCDEModWhen);
+    if (pCrc32 != NULL)
+        *pCrc32 = get4LE(ptr + kCDECRC);
+
+    /*
+     * We need to make sure that the lengths are not so large that somebody
+     * trying to map the compressed or uncompressed data runs off the end
+     * of the mapped region.
+     */
+    unsigned long localHdrOffset = get4LE(ptr + kCDELocalOffset);
+    if (localHdrOffset + kLFHLen >= zipLength) {
+        LOGE("ERROR: bad local hdr offset in zip\n");
+        return false;
+    }
+    const unsigned char* localHdr = basePtr + localHdrOffset;
+    off_t dataOffset = localHdrOffset + kLFHLen
+        + get2LE(localHdr + kLFHNameLen) + get2LE(localHdr + kLFHExtraLen);
+    if ((unsigned long) dataOffset >= zipLength) {
+        LOGE("ERROR: bad data offset in zip\n");
+        return false;
+    }
+
+    if (pCompLen != NULL) {
+        *pCompLen = get4LE(ptr + kCDECompLen);
+        if (*pCompLen < 0 || (size_t)(dataOffset + *pCompLen) >= zipLength) {
+            LOGE("ERROR: bad compressed length in zip\n");
+            return false;
+        }
+    }
+    if (pUncompLen != NULL) {
+        *pUncompLen = get4LE(ptr + kCDEUncompLen);
+        if (*pUncompLen < 0) {
+            LOGE("ERROR: negative uncompressed length in zip\n");
+            return false;
+        }
+        if (method == kCompressStored &&
+            (size_t)(dataOffset + *pUncompLen) >= zipLength)
+        {
+            LOGE("ERROR: bad uncompressed length in zip\n");
+            return false;
+        }
+    }
+
+    if (pOffset != NULL) {
+        *pOffset = dataOffset;
+    }
+    return true;
+}
+
+/*
+ * Copy the entry's filename to the buffer.
+ */
+int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen)
+    const
+{
+    int ent = entryToIndex(entry);
+    if (ent < 0)
+        return -1;
+
+    int nameLen = mHashTable[ent].nameLen;
+    if (bufLen < nameLen+1)
+        return nameLen+1;
+
+    memcpy(buffer, mHashTable[ent].name, nameLen);
+    buffer[nameLen] = '\0';
+    return 0;
+}
+
+/*
+ * Create a new FileMap object that spans the data in "entry".
+ */
+FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const
+{
+    /*
+     * TODO: the efficient way to do this is to modify FileMap to allow
+     * sub-regions of a file to be mapped.  A reference-counting scheme
+     * can manage the base memory mapping.  For now, we just create a brand
+     * new mapping off of the Zip archive file descriptor.
+     */
+
+    FileMap* newMap;
+    long compLen;
+    off_t offset;
+
+    if (!getEntryInfo(entry, NULL, NULL, &compLen, &offset, NULL, NULL))
+        return NULL;
+
+    newMap = new FileMap();
+    if (!newMap->create(mFileMap->getFileName(), mFd, offset, compLen, true)) {
+        newMap->release();
+        return NULL;
+    }
+
+    return newMap;
+}
+
+/*
+ * Uncompress an entry, in its entirety, into the provided output buffer.
+ *
+ * This doesn't verify the data's CRC, which might be useful for
+ * uncompressed data.  The caller should be able to manage it.
+ */
+bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const
+{
+    const int kSequentialMin = 32768;
+    bool result = false;
+    int ent = entryToIndex(entry);
+    if (ent < 0)
+        return -1;
+
+    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
+    int method;
+    long uncompLen, compLen;
+    off_t offset;
+
+    getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
+
+    /*
+     * Experiment with madvise hint.  When we want to uncompress a file,
+     * we pull some stuff out of the central dir entry and then hit a
+     * bunch of compressed or uncompressed data sequentially.  The CDE
+     * visit will cause a limited amount of read-ahead because it's at
+     * the end of the file.  We could end up doing lots of extra disk
+     * access if the file we're prying open is small.  Bottom line is we
+     * probably don't want to turn MADV_SEQUENTIAL on and leave it on.
+     *
+     * So, if the compressed size of the file is above a certain minimum
+     * size, temporarily boost the read-ahead in the hope that the extra
+     * pair of system calls are negated by a reduction in page faults.
+     */
+    if (compLen > kSequentialMin)
+        mFileMap->advise(FileMap::SEQUENTIAL);
+
+    if (method == kCompressStored) {
+        memcpy(buffer, basePtr + offset, uncompLen);
+    } else {
+        if (!inflateBuffer(buffer, basePtr + offset, uncompLen, compLen))
+            goto bail;
+    }
+
+    if (compLen > kSequentialMin)
+        mFileMap->advise(FileMap::NORMAL);
+
+    result = true;
+
+bail:
+    return result;
+}
+
+/*
+ * Uncompress an entry, in its entirety, to an open file descriptor.
+ *
+ * This doesn't verify the data's CRC, but probably should.
+ */
+bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const
+{
+    bool result = false;
+    int ent = entryToIndex(entry);
+    if (ent < 0)
+        return -1;
+
+    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
+    int method;
+    long uncompLen, compLen;
+    off_t offset;
+
+    getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
+
+    if (method == kCompressStored) {
+        ssize_t actual;
+
+        actual = write(fd, basePtr + offset, uncompLen);
+        if (actual < 0) {
+            LOGE("Write failed: %s\n", strerror(errno));
+            goto bail;
+        } else if (actual != uncompLen) {
+            LOGE("Partial write during uncompress (%d of %ld)\n",
+                (int)actual, uncompLen);
+            goto bail;
+        } else {
+            LOGI("+++ successful write\n");
+        }
+    } else {
+        if (!inflateBuffer(fd, basePtr+offset, uncompLen, compLen))
+            goto bail;
+    }
+
+    result = true;
+
+bail:
+    return result;
+}
+
+/*
+ * Uncompress "deflate" data from one buffer to another.
+ */
+/*static*/ bool ZipFileRO::inflateBuffer(void* outBuf, const void* inBuf,
+    long uncompLen, long compLen)
+{
+    bool result = false;
+    z_stream zstream;
+    int zerr;
+
+    /*
+     * Initialize the zlib stream struct.
+     */
+	memset(&zstream, 0, sizeof(zstream));
+    zstream.zalloc = Z_NULL;
+    zstream.zfree = Z_NULL;
+    zstream.opaque = Z_NULL;
+    zstream.next_in = (Bytef*)inBuf;
+    zstream.avail_in = compLen;
+    zstream.next_out = (Bytef*) outBuf;
+    zstream.avail_out = uncompLen;
+    zstream.data_type = Z_UNKNOWN;
+
+	/*
+	 * Use the undocumented "negative window bits" feature to tell zlib
+	 * that there's no zlib header waiting for it.
+	 */
+    zerr = inflateInit2(&zstream, -MAX_WBITS);
+    if (zerr != Z_OK) {
+        if (zerr == Z_VERSION_ERROR) {
+            LOGE("Installed zlib is not compatible with linked version (%s)\n",
+                ZLIB_VERSION);
+        } else {
+            LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+        }
+        goto bail;
+    }
+
+    /*
+     * Expand data.
+     */
+    zerr = inflate(&zstream, Z_FINISH);
+    if (zerr != Z_STREAM_END) {
+        LOGW("Zip inflate failed, zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n",
+            zerr, zstream.next_in, zstream.avail_in,
+            zstream.next_out, zstream.avail_out);
+        goto z_bail;
+    }
+
+    /* paranoia */
+    if ((long) zstream.total_out != uncompLen) {
+        LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+            zstream.total_out, uncompLen);
+        goto z_bail;
+    }
+
+    result = true;
+
+z_bail:
+    inflateEnd(&zstream);        /* free up any allocated structures */
+
+bail:
+    return result;
+}
+
+/*
+ * Uncompress "deflate" data from one buffer to an open file descriptor.
+ */
+/*static*/ bool ZipFileRO::inflateBuffer(int fd, const void* inBuf,
+    long uncompLen, long compLen)
+{
+    bool result = false;
+    const int kWriteBufSize = 32768;
+    unsigned char writeBuf[kWriteBufSize];
+    z_stream zstream;
+    int zerr;
+
+    /*
+     * Initialize the zlib stream struct.
+     */
+	memset(&zstream, 0, sizeof(zstream));
+    zstream.zalloc = Z_NULL;
+    zstream.zfree = Z_NULL;
+    zstream.opaque = Z_NULL;
+    zstream.next_in = (Bytef*)inBuf;
+    zstream.avail_in = compLen;
+    zstream.next_out = (Bytef*) writeBuf;
+    zstream.avail_out = sizeof(writeBuf);
+    zstream.data_type = Z_UNKNOWN;
+
+	/*
+	 * Use the undocumented "negative window bits" feature to tell zlib
+	 * that there's no zlib header waiting for it.
+	 */
+    zerr = inflateInit2(&zstream, -MAX_WBITS);
+    if (zerr != Z_OK) {
+        if (zerr == Z_VERSION_ERROR) {
+            LOGE("Installed zlib is not compatible with linked version (%s)\n",
+                ZLIB_VERSION);
+        } else {
+            LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+        }
+        goto bail;
+    }
+
+    /*
+     * Loop while we have more to do.
+     */
+    do {
+        /*
+         * Expand data.
+         */
+        zerr = inflate(&zstream, Z_NO_FLUSH);
+        if (zerr != Z_OK && zerr != Z_STREAM_END) {
+            LOGW("zlib inflate: zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n",
+                zerr, zstream.next_in, zstream.avail_in,
+                zstream.next_out, zstream.avail_out);
+            goto z_bail;
+        }
+
+        /* write when we're full or when we're done */
+        if (zstream.avail_out == 0 ||
+            (zerr == Z_STREAM_END && zstream.avail_out != sizeof(writeBuf)))
+        {
+            long writeSize = zstream.next_out - writeBuf;
+            int cc = write(fd, writeBuf, writeSize);
+            if (cc != (int) writeSize) {
+                LOGW("write failed in inflate (%d vs %ld)\n", cc, writeSize);
+                goto z_bail;
+            }
+
+            zstream.next_out = writeBuf;
+            zstream.avail_out = sizeof(writeBuf);
+        }
+    } while (zerr == Z_OK);
+
+    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
+
+    /* paranoia */
+    if ((long) zstream.total_out != uncompLen) {
+        LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+            zstream.total_out, uncompLen);
+        goto z_bail;
+    }
+
+    result = true;
+
+z_bail:
+    inflateEnd(&zstream);        /* free up any allocated structures */
+
+bail:
+    return result;
+}
diff --git a/libs/utils/ZipUtils.cpp b/libs/utils/ZipUtils.cpp
new file mode 100644
index 0000000..bfbacfe
--- /dev/null
+++ b/libs/utils/ZipUtils.cpp
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+//
+// Misc zip/gzip utility functions.
+//
+
+#define LOG_TAG "ziputil"
+
+#include "utils/ZipUtils.h"
+#include "utils/ZipFileRO.h"
+#include "utils/Log.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <zlib.h>
+
+using namespace android;
+
+/*
+ * Utility function that expands zip/gzip "deflate" compressed data
+ * into a buffer.
+ *
+ * "fd" is an open file positioned at the start of the "deflate" data
+ * "buf" must hold at least "uncompressedLen" bytes.
+ */
+/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
+    long uncompressedLen, long compressedLen)
+{
+    bool result = false;
+	const unsigned long kReadBufSize = 32768;
+	unsigned char* readBuf = NULL;
+    z_stream zstream;
+    int zerr;
+    unsigned long compRemaining;
+
+    assert(uncompressedLen >= 0);
+    assert(compressedLen >= 0);
+
+	readBuf = new unsigned char[kReadBufSize];
+	if (readBuf == NULL)
+        goto bail;
+    compRemaining = compressedLen;
+
+    /*
+     * Initialize the zlib stream.
+     */
+	memset(&zstream, 0, sizeof(zstream));
+    zstream.zalloc = Z_NULL;
+    zstream.zfree = Z_NULL;
+    zstream.opaque = Z_NULL;
+    zstream.next_in = NULL;
+    zstream.avail_in = 0;
+    zstream.next_out = (Bytef*) buf;
+    zstream.avail_out = uncompressedLen;
+    zstream.data_type = Z_UNKNOWN;
+
+	/*
+	 * Use the undocumented "negative window bits" feature to tell zlib
+	 * that there's no zlib header waiting for it.
+	 */
+    zerr = inflateInit2(&zstream, -MAX_WBITS);
+    if (zerr != Z_OK) {
+        if (zerr == Z_VERSION_ERROR) {
+            LOGE("Installed zlib is not compatible with linked version (%s)\n",
+                ZLIB_VERSION);
+        } else {
+            LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+        }
+        goto bail;
+    }
+
+    /*
+     * Loop while we have data.
+     */
+    do {
+        unsigned long getSize;
+
+        /* read as much as we can */
+        if (zstream.avail_in == 0) {
+            getSize = (compRemaining > kReadBufSize) ?
+                        kReadBufSize : compRemaining;
+            LOGV("+++ reading %ld bytes (%ld left)\n",
+                getSize, compRemaining);
+
+            int cc = read(fd, readBuf, getSize);
+            if (cc != (int) getSize) {
+                LOGD("inflate read failed (%d vs %ld)\n",
+                    cc, getSize);
+                goto z_bail;
+            }
+
+            compRemaining -= getSize;
+
+            zstream.next_in = readBuf;
+            zstream.avail_in = getSize;
+        }
+
+        /* uncompress the data */
+        zerr = inflate(&zstream, Z_NO_FLUSH);
+        if (zerr != Z_OK && zerr != Z_STREAM_END) {
+            LOGD("zlib inflate call failed (zerr=%d)\n", zerr);
+            goto z_bail;
+        }
+
+		/* output buffer holds all, so no need to write the output */
+    } while (zerr == Z_OK);
+
+    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
+
+    if ((long) zstream.total_out != uncompressedLen) {
+        LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+            zstream.total_out, uncompressedLen);
+        goto z_bail;
+    }
+
+    // success!
+    result = true;
+
+z_bail:
+    inflateEnd(&zstream);        /* free up any allocated structures */
+
+bail:
+	delete[] readBuf;
+    return result;
+}
+
+/*
+ * Utility function that expands zip/gzip "deflate" compressed data
+ * into a buffer.
+ *
+ * (This is a clone of the previous function, but it takes a FILE* instead
+ * of an fd.  We could pass fileno(fd) to the above, but we can run into
+ * trouble when "fp" has a different notion of what fd's file position is.)
+ *
+ * "fp" is an open file positioned at the start of the "deflate" data
+ * "buf" must hold at least "uncompressedLen" bytes.
+ */
+/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
+    long uncompressedLen, long compressedLen)
+{
+    bool result = false;
+	const unsigned long kReadBufSize = 32768;
+	unsigned char* readBuf = NULL;
+    z_stream zstream;
+    int zerr;
+    unsigned long compRemaining;
+
+    assert(uncompressedLen >= 0);
+    assert(compressedLen >= 0);
+
+	readBuf = new unsigned char[kReadBufSize];
+	if (readBuf == NULL)
+        goto bail;
+    compRemaining = compressedLen;
+
+    /*
+     * Initialize the zlib stream.
+     */
+	memset(&zstream, 0, sizeof(zstream));
+    zstream.zalloc = Z_NULL;
+    zstream.zfree = Z_NULL;
+    zstream.opaque = Z_NULL;
+    zstream.next_in = NULL;
+    zstream.avail_in = 0;
+    zstream.next_out = (Bytef*) buf;
+    zstream.avail_out = uncompressedLen;
+    zstream.data_type = Z_UNKNOWN;
+
+	/*
+	 * Use the undocumented "negative window bits" feature to tell zlib
+	 * that there's no zlib header waiting for it.
+	 */
+    zerr = inflateInit2(&zstream, -MAX_WBITS);
+    if (zerr != Z_OK) {
+        if (zerr == Z_VERSION_ERROR) {
+            LOGE("Installed zlib is not compatible with linked version (%s)\n",
+                ZLIB_VERSION);
+        } else {
+            LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+        }
+        goto bail;
+    }
+
+    /*
+     * Loop while we have data.
+     */
+    do {
+        unsigned long getSize;
+
+        /* read as much as we can */
+        if (zstream.avail_in == 0) {
+            getSize = (compRemaining > kReadBufSize) ?
+                        kReadBufSize : compRemaining;
+            LOGV("+++ reading %ld bytes (%ld left)\n",
+                getSize, compRemaining);
+
+            int cc = fread(readBuf, getSize, 1, fp);
+            if (cc != (int) getSize) {
+                LOGD("inflate read failed (%d vs %ld)\n",
+                    cc, getSize);
+                goto z_bail;
+            }
+
+            compRemaining -= getSize;
+
+            zstream.next_in = readBuf;
+            zstream.avail_in = getSize;
+        }
+
+        /* uncompress the data */
+        zerr = inflate(&zstream, Z_NO_FLUSH);
+        if (zerr != Z_OK && zerr != Z_STREAM_END) {
+            LOGD("zlib inflate call failed (zerr=%d)\n", zerr);
+            goto z_bail;
+        }
+
+		/* output buffer holds all, so no need to write the output */
+    } while (zerr == Z_OK);
+
+    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
+
+    if ((long) zstream.total_out != uncompressedLen) {
+        LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+            zstream.total_out, uncompressedLen);
+        goto z_bail;
+    }
+
+    // success!
+    result = true;
+
+z_bail:
+    inflateEnd(&zstream);        /* free up any allocated structures */
+
+bail:
+	delete[] readBuf;
+    return result;
+}
+
+/*
+ * Look at the contents of a gzip archive.  We want to know where the
+ * data starts, and how long it will be after it is uncompressed.
+ *
+ * We expect to find the CRC and length as the last 8 bytes on the file.
+ * This is a pretty reasonable thing to expect for locally-compressed
+ * files, but there's a small chance that some extra padding got thrown
+ * on (the man page talks about compressed data written to tape).  We
+ * don't currently deal with that here.  If "gzip -l" whines, we're going
+ * to fail too.
+ *
+ * On exit, "fp" is pointing at the start of the compressed data.
+ */
+/*static*/ bool ZipUtils::examineGzip(FILE* fp, int* pCompressionMethod,
+    long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32)
+{
+    enum {  // flags
+        FTEXT       = 0x01,
+        FHCRC       = 0x02,
+        FEXTRA      = 0x04,
+        FNAME       = 0x08,
+        FCOMMENT    = 0x10,
+    };
+    int ic;
+    int method, flags;
+    int i;
+
+    ic = getc(fp);
+    if (ic != 0x1f || getc(fp) != 0x8b)
+        return false;       // not gzip
+    method = getc(fp);
+    flags = getc(fp);
+
+    /* quick sanity checks */
+    if (method == EOF || flags == EOF)
+        return false;
+    if (method != ZipFileRO::kCompressDeflated)
+        return false;
+
+    /* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */
+    for (i = 0; i < 6; i++)
+        (void) getc(fp);
+    /* consume "extra" field, if present */
+    if ((flags & FEXTRA) != 0) {
+        int len;
+
+        len = getc(fp);
+        len |= getc(fp) << 8;
+        while (len-- && getc(fp) != EOF)
+            ;
+    }
+    /* consume filename, if present */
+    if ((flags & FNAME) != 0) {
+        do {
+            ic = getc(fp);
+        } while (ic != 0 && ic != EOF);
+    }
+    /* consume comment, if present */
+    if ((flags & FCOMMENT) != 0) {
+        do {
+            ic = getc(fp);
+        } while (ic != 0 && ic != EOF);
+    }
+    /* consume 16-bit header CRC, if present */
+    if ((flags & FHCRC) != 0) {
+        (void) getc(fp);
+        (void) getc(fp);
+    }
+
+    if (feof(fp) || ferror(fp))
+        return false;
+
+    /* seek to the end; CRC and length are in the last 8 bytes */
+    long curPosn = ftell(fp);
+    unsigned char buf[8];
+    fseek(fp, -8, SEEK_END);
+    *pCompressedLen = ftell(fp) - curPosn;
+
+    if (fread(buf, 1, 8, fp) != 8)
+        return false;
+    /* seek back to start of compressed data */
+    fseek(fp, curPosn, SEEK_SET);
+
+    *pCompressionMethod = method;
+    *pCRC32 = ZipFileRO::get4LE(&buf[0]);
+    *pUncompressedLen = ZipFileRO::get4LE(&buf[4]);
+
+    return true;
+}
+
diff --git a/libs/utils/characterData.h b/libs/utils/characterData.h
new file mode 100644
index 0000000..e931d99
--- /dev/null
+++ b/libs/utils/characterData.h
@@ -0,0 +1,730 @@
+/*
+ * 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.
+ */
+
+// Automatically generated on 07-11-2006 by make-CharacterDataC
+// DO NOT EDIT DIRECTLY
+namespace CharacterData {
+
+    // Structure containing an array of ranges
+    struct Range {
+        int length;
+        const uint32_t* array;
+    };
+
+    // For Latin1 characters just index into this array to get the index and decomposition
+    static const uint16_t LATIN1_DATA[] = {
+        0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 
+        0x0001, 0x0002, 0x0003, 0x0002, 0x0004, 0x0003, 0x0001, 0x0001, 
+        0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 
+        0x0001, 0x0001, 0x0001, 0x0001, 0x0003, 0x0003, 0x0003, 0x0002, 
+        0x0005, 0x0006, 0x0006, 0x0007, 0x0008, 0x0007, 0x0006, 0x0006, 
+        0x0009, 0x000A, 0x0006, 0x000B, 0x000C, 0x000D, 0x000C, 0x000C, 
+        0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 
+        0x0016, 0x0017, 0x000C, 0x0006, 0x0018, 0x0019, 0x001A, 0x0006, 
+        0x0006, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, 
+        0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 
+        0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 
+        0x0032, 0x0033, 0x0034, 0x0035, 0x0006, 0x0036, 0x0037, 0x0038, 
+        0x0037, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 
+        0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 
+        0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 
+        0x0050, 0x0051, 0x0052, 0x0035, 0x0019, 0x0036, 0x0019, 0x0001, 
+        0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0003, 0x0001, 0x0001, 
+        0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 
+        0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 
+        0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 
+        0x5853, 0x0006, 0x0008, 0x0008, 0x0008, 0x0008, 0x0054, 0x0054, 
+        0x1037, 0x0054, 0x7855, 0x0056, 0x0019, 0x0057, 0x0054, 0x1037, 
+        0x0058, 0x0059, 0x785A, 0x785B, 0x1037, 0x105C, 0x0054, 0x0006, 
+        0x1037, 0x785D, 0x7855, 0x005E, 0x305F, 0x305F, 0x305F, 0x0006, 
+        0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0060, 0x0860, 
+        0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 
+        0x0060, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0019, 
+        0x0060, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0060, 0x0055, 
+        0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0061, 0x0861, 
+        0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 
+        0x0061, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0019, 
+        0x0061, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0061, 0x0862
+    };
+
+    // Each of these arrays is stripped into ranges. In order to build the arrays, each
+    // codepoint was bit-shifted so that even and odd characters were separated into different
+    // arrays. The identifier of each array is the top byte after bit-shifting.
+    // The numbers stored in the array are the bit-shifted codepoint, the decomposition, and an
+    // index into another array of all possible packed data values. The top 16 bits are the
+    // codepoint and the bottom 16 are the decomposition and index. The top 5 bits for the decomposition
+    // and the rest for the index.
+    static const uint32_t a0[] = {
+        0x00800863, 0x00880063, 0x00890863, 0x00930063, 0x00940863, 0x00980864, 0x00991063, 0x009A0863, 
+        0x009C0055, 0x009D0865, 0x00A01065, 0x00A10065, 0x00A20865, 0x00A50063, 0x00A60863, 0x00A90063, 
+        0x00AA0863, 0x00B30063, 0x00B40863, 0x00BC0866, 0x00BD0865, 0x00C00055, 0x00C10063, 0x00C30067, 
+        0x00C40065, 0x00C50068, 0x00C60065, 0x00C70069, 0x00C8006A, 0x00C90065, 0x00CA006B, 0x00CB006C, 
+        0x00CC0063, 0x00CD006D, 0x00CE006C, 0x00CF006E, 0x00D00863, 0x00D10063, 0x00D3006F, 0x00D40065, 
+        0x00D50055, 0x00D60063, 0x00D7006F, 0x00D80865, 0x00D90070, 0x00DA0065, 0x00DC0063, 0x00DD0055, 
+        0x00DE0063, 0x00DF0055, 0x00E00071, 0x00E21072, 0x00E31073, 0x00E41074, 0x00E51072, 0x00E61073, 
+        0x00E70865, 0x00EF0863, 0x00F20063, 0x00F30863, 0x00F80855, 0x00F91074, 0x00FA0863, 0x00FB0075, 
+        0x00FC0863, 0x010E0063, 0x010F0863, 0x01100076, 0x01110063, 0x01130863, 0x011A0055, 0x011D0077, 
+        0x011E0065, 0x011F0077, 0x01200055, 0x01210078, 0x01280055, 0x012A0079, 0x012B007A, 0x012C0055, 
+        0x0130007A, 0x01310055, 0x0134007B, 0x01350055, 0x0139007C, 0x013A0055, 0x0140007D, 0x01410055, 
+        0x0144007D, 0x0145007E, 0x01460055, 0x0149007F, 0x014A0080, 0x014B0055, 0x01587881, 0x015D0082, 
+        0x015E0081, 0x01610037, 0x01630082, 0x01680081, 0x01690037, 0x016C1037, 0x016F0037, 0x01707881, 
+        0x01730037, 0x01770081, 0x01780037, 0x01800083, 0x01A00883, 0x01A10083, 0x01A20883, 0x01A30083, 
+        0x01B80078, 0x01BA0837, 0x01BB0078, 0x01BD1081, 0x01BE0078, 0x01BF0806, 0x01C00078, 0x01C21037, 
+        0x01C30884, 0x01C40885, 0x01C60886, 0x01C70887, 0x01C80855, 0x01C90060, 0x01D10078, 0x01D20060, 
+        0x01D50860, 0x01D60888, 0x01D70889, 0x01D80855, 0x01D90061, 0x01E1008A, 0x01E20061, 0x01E50861, 
+        0x01E6088B, 0x01E7088C, 0x01E8108D, 0x01E91077, 0x01EA0877, 0x01EB108E, 0x01EC0063, 0x01F8108F, 
+        0x01F91090, 0x01FA1091, 0x01FB0019, 0x01FC0065, 0x01FD0063, 0x01FE0055, 0x01FF0077, 0x02000892, 
+        0x02010092, 0x02060892, 0x02080060, 0x02180061, 0x02280893, 0x02290093, 0x022E0893, 0x02300063, 
+        0x023B0863, 0x023C0063, 0x02410094, 0x02420083, 0x02440095, 0x02450063, 0x02600077, 0x02610865, 
+        0x02620065, 0x02680863, 0x026A0063, 0x026B0863, 0x026C0063, 0x026D0863, 0x02700063, 0x02710863, 
+        0x02740063, 0x02750863, 0x027B0063, 0x027C0863, 0x027D0078, 0x02800063, 0x02880078, 0x02990096, 
+        0x02AC0078, 0x02AD0097, 0x02B00078, 0x02B10098, 0x02C40078, 0x02C50099, 0x02C60078, 0x02C90083, 
+        0x02DD0078, 0x02DE0083, 0x02DF009A, 0x02E10083, 0x02E3009A, 0x02E40078, 0x02E8009B, 0x02F60078, 
+        0x02F8009B, 0x02FA009A, 0x02FB0078, 0x0300009C, 0x03020078, 0x0306000C, 0x03070054, 0x03080083, 
+        0x030B0078, 0x030F009D, 0x03100078, 0x0311089E, 0x0314009E, 0x031E0078, 0x0320009F, 0x0321009E, 
+        0x03260083, 0x033000A0, 0x033100A1, 0x033200A2, 0x033300A3, 0x033400A4, 0x03350007, 0x033600A5, 
+        0x0337009E, 0x03380083, 0x0339009E, 0x033B109E, 0x033D009E, 0x0360089E, 0x0362009E, 0x036A009D, 
+        0x036B0083, 0x036F0095, 0x03700083, 0x0373009F, 0x03740083, 0x0377009E, 0x0378000E, 0x03790010, 
+        0x037A0012, 0x037B0014, 0x037C0016, 0x037D009E, 0x037F00A6, 0x0380009D, 0x03870078, 0x0388009E, 
+        0x03980083, 0x03A60078, 0x03A7009E, 0x03B70078, 0x03C0009E, 0x03D30083, 0x03D90078, 0x04810083, 
+        0x04820071, 0x049A0871, 0x049B0071, 0x049D0078, 0x049E0083, 0x049F00A7, 0x04A10083, 0x04A500A7, 
+        0x04A70078, 0x04A80071, 0x04A90083, 0x04AB0078, 0x04AC0871, 0x04B00071, 0x04B10083, 0x04B20097, 
+        0x04B300A8, 0x04B400A9, 0x04B500AA, 0x04B600AB, 0x04B700AC, 0x04B80097, 0x04B90078, 0x04C100A7, 
+        0x04C20078, 0x04C30071, 0x04C70078, 0x04C80071, 0x04C90078, 0x04CA0071, 0x04DA0078, 0x04DB0071, 
+        0x04DD0078, 0x04DE0083, 0x04DF00A7, 0x04E10083, 0x04E30078, 0x04E400A7, 0x04E50078, 0x04E608A7, 
+        0x04E70071, 0x04E80078, 0x04EE0871, 0x04EF0078, 0x04F00071, 0x04F10083, 0x04F20078, 0x04F300A8, 
+        0x04F400A9, 0x04F500AA, 0x04F600AB, 0x04F700AC, 0x04F80071, 0x04F90008, 0x04FA00AD, 0x04FB00AE, 
+        0x04FC00AF, 0x04FD0094, 0x04FE0078, 0x05010083, 0x05020078, 0x05030071, 0x05060078, 0x05080071, 
+        0x05090078, 0x050A0071, 0x051A0078, 0x051B0871, 0x051C0071, 0x051D0078, 0x051E0083, 0x051F00A7, 
+        0x05210083, 0x05220078, 0x05240083, 0x05250078, 0x05260083, 0x05270078, 0x052D0871, 0x052E0071, 
+        0x052F0871, 0x05300078, 0x053300A8, 0x053400A9, 0x053500AA, 0x053600AB, 0x053700AC, 0x05380083, 
+        0x05390071, 0x053B0078, 0x05410083, 0x05420078, 0x05430071, 0x05470078, 0x05480071, 0x05490078, 
+        0x054A0071, 0x055A0078, 0x055B0071, 0x055D0078, 0x055E0083, 0x055F00A7, 0x05610083, 0x05630078, 
+        0x05640083, 0x05650078, 0x056600A7, 0x05670078, 0x05680071, 0x05690078, 0x05700071, 0x05710083, 
+        0x05720078, 0x057300A8, 0x057400A9, 0x057500AA, 0x057600AB, 0x057700AC, 0x05780078, 0x058100A7, 
+        0x05820078, 0x05830071, 0x05870078, 0x05880071, 0x05890078, 0x058A0071, 0x059A0078, 0x059B0071, 
+        0x059D0078, 0x059E0083, 0x059F00A7, 0x05A10083, 0x05A20078, 0x05A408A7, 0x05A50078, 0x05A608A7, 
+        0x05A70078, 0x05AB0083, 0x05AC0078, 0x05AE0871, 0x05AF0078, 0x05B00071, 0x05B10078, 0x05B300A8, 
+        0x05B400A9, 0x05B500AA, 0x05B600AB, 0x05B700AC, 0x05B80094, 0x05B90078, 0x05C10083, 0x05C20078, 
+        0x05C30071, 0x05C60078, 0x05C70071, 0x05CA0871, 0x05CB0078, 0x05CD0071, 0x05D00078, 0x05D20071, 
+        0x05D30078, 0x05D40071, 0x05D60078, 0x05D70071, 0x05DD0078, 0x05DF00A7, 0x05E00083, 0x05E100A7, 
+        0x05E20078, 0x05E300A7, 0x05E508A7, 0x05E70078, 0x05F300A8, 0x05F400A9, 0x05F500AA, 0x05F600AB, 
+        0x05F700AC, 0x05F800B0, 0x05F900B1, 0x05FA0054, 0x05FE0078, 0x060100A7, 0x06020078, 0x06030071, 
+        0x061A0078, 0x061B0071, 0x061D0078, 0x061F0083, 0x062100A7, 0x06230083, 0x06240883, 0x06250083, 
+        0x06270078, 0x062B0083, 0x062C0078, 0x06300071, 0x06310078, 0x063300A8, 0x063400A9, 0x063500AA, 
+        0x063600AB, 0x063700AC, 0x06380078, 0x064100A7, 0x06420078, 0x06430071, 0x065A0078, 0x065B0071, 
+        0x065D0078, 0x065E0083, 0x065F00A7, 0x066008A7, 0x066100A7, 0x066300B2, 0x066408A7, 0x06660083, 
+        0x06670078, 0x066B00A7, 0x066C0078, 0x066F0071, 0x06710078, 0x067300A8, 0x067400A9, 0x067500AA, 
+        0x067600AB, 0x067700AC, 0x06780078, 0x068100A7, 0x06820078, 0x06830071, 0x069D0078, 0x069F00A7, 
+        0x06A10083, 0x06A20078, 0x06A300A7, 0x06A508A7, 0x06A70078, 0x06B00071, 0x06B10078, 0x06B300A8, 
+        0x06B400A9, 0x06B500AA, 0x06B600AB, 0x06B700AC, 0x06B80078, 0x06C100A7, 0x06C20078, 0x06C30071, 
+        0x06CC0078, 0x06CD0071, 0x06D90078, 0x06DA0071, 0x06DE0078, 0x06E00071, 0x06E40078, 0x06E50083, 
+        0x06E60078, 0x06E800A7, 0x06E90083, 0x06EC00A7, 0x06ED08A7, 0x06F00078, 0x06F900A7, 0x06FA0097, 
+        0x06FB0078, 0x07010071, 0x071A0083, 0x071E0078, 0x07200071, 0x07230081, 0x07240083, 0x072800A8, 
+        0x072900A9, 0x072A00AA, 0x072B00AB, 0x072C00AC, 0x072D0097, 0x072E0078, 0x07410071, 0x07430078, 
+        0x07440071, 0x07460078, 0x074A0071, 0x074C0078, 0x074D0071, 0x07500078, 0x07510071, 0x07520078, 
+        0x07550071, 0x07560078, 0x07570071, 0x075A0083, 0x075D0078, 0x075E0083, 0x075F0078, 0x07600071, 
+        0x07630081, 0x07640083, 0x07670078, 0x076800A8, 0x076900A9, 0x076A00AA, 0x076B00AB, 0x076C00AC, 
+        0x076D0078, 0x076E1071, 0x076F0078, 0x07800071, 0x07810094, 0x07820097, 0x07865897, 0x07870097, 
+        0x078A0094, 0x078C0083, 0x078D0094, 0x079000A8, 0x079100A9, 0x079200AA, 0x079300AB, 0x079400AC, 
+        0x079500B3, 0x079A0094, 0x079D00B4, 0x079F00A7, 0x07A00071, 0x07A40078, 0x07A50071, 0x07A90871, 
+        0x07AA0071, 0x07AE0871, 0x07AF0071, 0x07B60078, 0x07B90083, 0x07BB0883, 0x07BD0083, 0x07C40071, 
+        0x07C60078, 0x07C80083, 0x07CC0078, 0x07CD0083, 0x07D10883, 0x07D20083, 0x07D60883, 0x07D70083, 
+        0x07DF0094, 0x07E30083, 0x07E40094, 0x07E70078, 0x07E80097, 0x07E90078, 0x08000071, 0x08110078, 
+        0x08120071, 0x08130871, 0x08140078, 0x08150071, 0x081600A7, 0x08170083, 0x081A0078, 0x081B0083, 
+        0x081C00A7, 0x081D0078, 0x082000A8, 0x082100A9, 0x082200AA, 0x082300AB, 0x082400AC, 0x08250097, 
+        0x08280071, 0x082B00A7, 0x082C0083, 0x082D0078, 0x085000B5, 0x08630078, 0x08680071, 0x087E7881, 
+        0x087F0078, 0x08800071, 0x08AD0078, 0x08B00071, 0x08D20078, 0x08D40071, 0x08FD0078, 0x09000071, 
+        0x09270078, 0x09280071, 0x092F0078, 0x09300071, 0x09470078, 0x09480071, 0x095B0078, 0x095C0071, 
+        0x09630078, 0x09640071, 0x098B0078, 0x098C0071, 0x09AE0078, 0x09B00094, 0x09B10097, 0x09B500B6, 
+        0x09B600B7, 0x09B700B8, 0x09B800B9, 0x09B900B0, 0x09BA00BA, 0x09BB00BB, 0x09BC00BC, 0x09BD00BD, 
+        0x09BE00BE, 0x09BF0078, 0x09C00071, 0x09C80054, 0x09CD0078, 0x09D00071, 0x09FB0078, 0x0A010071, 
+        0x0B370097, 0x0B380071, 0x0B3C0078, 0x0B400005, 0x0B410071, 0x0B4E00BF, 0x0B4F0078, 0x0B500071, 
+        0x0B760097, 0x0B7700C0, 0x0B7800C1, 0x0B790078, 0x0B800071, 0x0B890083, 0x0B8B0078, 0x0B900071, 
+        0x0B990083, 0x0B9B0097, 0x0B9C0078, 0x0BA00071, 0x0BA90083, 0x0BAA0078, 0x0BB00071, 0x0BB90083, 
+        0x0BBA0078, 0x0BC00071, 0x0BDA00C2, 0x0BDB00A7, 0x0BDC0083, 0x0BDF00A7, 0x0BE30083, 0x0BE400A7, 
+        0x0BE50083, 0x0BEA0097, 0x0BEE0071, 0x0BEF0078, 0x0BF000A8, 0x0BF100A9, 0x0BF200AA, 0x0BF300AB, 
+        0x0BF400AC, 0x0BF50078, 0x0BF800C3, 0x0BF900C4, 0x0BFA00C5, 0x0BFB00C6, 0x0BFC00C7, 0x0BFD0078, 
+        0x0C000006, 0x0C030099, 0x0C040006, 0x0C060083, 0x0C070005, 0x0C0800A8, 0x0C0900A9, 0x0C0A00AA, 
+        0x0C0B00AB, 0x0C0C00AC, 0x0C0D0078, 0x0C100071, 0x0C3C0078, 0x0C400071, 0x0C550078, 0x0C800071, 
+        0x0C8F0078, 0x0C900083, 0x0C9200A7, 0x0C940083, 0x0C9500C8, 0x0C960078, 0x0C9800A7, 0x0C990083, 
+        0x0C9A00A7, 0x0C9D0083, 0x0C9E0078, 0x0CA00054, 0x0CA10078, 0x0CA20006, 0x0CA300A8, 0x0CA400A9, 
+        0x0CA500AA, 0x0CA600AB, 0x0CA700AC, 0x0CA80071, 0x0CB70078, 0x0CB80071, 0x0CBB0078, 0x0CC00071, 
+        0x0CD50078, 0x0CD800A7, 0x0CE10071, 0x0CE400A7, 0x0CE50078, 0x0CE800A8, 0x0CE900A9, 0x0CEA00AA, 
+        0x0CEB00AB, 0x0CEC00AC, 0x0CED0078, 0x0CEF0006, 0x0CF00054, 0x0D000071, 0x0D0C0083, 0x0D0D00A7, 
+        0x0D0E0078, 0x0D0F0097, 0x0D100078, 0x0E800055, 0x0E967881, 0x0EA70081, 0x0EA87881, 0x0EB17055, 
+        0x0EB60055, 0x0EBC7881, 0x0EBD0055, 0x0ECE7881, 0x0EE00083, 0x0EE20078, 0x0F000863, 0x0F4B0855, 
+        0x0F4D1055, 0x0F4E0078, 0x0F500863, 0x0F7D0078, 0x0F8008C9, 0x0F8408CA, 0x0F8808C9, 0x0F8B0078, 
+        0x0F8C08CA, 0x0F8F0078, 0x0F9008C9, 0x0F9408CA, 0x0F9808C9, 0x0F9C08CA, 0x0FA008C9, 0x0FA30078, 
+        0x0FA408CA, 0x0FA70078, 0x0FA80855, 0x0FAC0078, 0x0FB008C9, 0x0FB408CA, 0x0FB808CB, 0x0FB908CC, 
+        0x0FBB08CD, 0x0FBC08CE, 0x0FBD08CF, 0x0FBE08D0, 0x0FBF0078, 0x0FC008C9, 0x0FC408D1, 0x0FC808C9, 
+        0x0FCC08D1, 0x0FD008C9, 0x0FD408D1, 0x0FD808C9, 0x0FD90855, 0x0FDC08CA, 0x0FDD08D2, 0x0FDE08D3, 
+        0x0FDF08D4, 0x0FE01037, 0x0FE10855, 0x0FE408D5, 0x0FE608D3, 0x0FE70837, 0x0FE808C9, 0x0FE90855, 
+        0x0FEA0078, 0x0FEB0855, 0x0FEC08CA, 0x0FED08D6, 0x0FEE0078, 0x0FEF0837, 0x0FF008C9, 0x0FF10855, 
+        0x0FF408CA, 0x0FF508D7, 0x0FF608D8, 0x0FF70837, 0x0FF80078, 0x0FF90855, 0x0FFC08D9, 0x0FFD08DA, 
+        0x0FFE08D3, 0x0FFF1037, 0x10000805, 0x10011005, 0x10060057, 0x100700C2, 0x10080099, 0x100B0006, 
+        0x100C00DB, 0x100D00B4, 0x100E00DB, 0x100F00B4, 0x10100006, 0x10121006, 0x101400DC, 0x101500DD, 
+        0x101600DE, 0x101700DF, 0x10180007, 0x101A1007, 0x101B1006, 0x101C0006, 0x101D00E0, 0x101E1006, 
+        0x10200038, 0x10210006, 0x102200E1, 0x1023000A, 0x10241006, 0x10250006, 0x10290019, 0x102A0038, 
+        0x102B0006, 0x10300057, 0x10320078, 0x10350057, 0x103878E2, 0x10390078, 0x103A78E3, 0x103B78E4, 
+        0x103C78E5, 0x103D780B, 0x103E7819, 0x103F780A, 0x104070E2, 0x1041705A, 0x104270E3, 0x104370E4, 
+        0x104470E5, 0x1045700B, 0x10467019, 0x1047700A, 0x10487081, 0x104B0078, 0x10500008, 0x10541008, 
+        0x10550008, 0x105B0078, 0x10680083, 0x106F0095, 0x10730083, 0x10760078, 0x10801054, 0x10812877, 
+        0x10820054, 0x10831054, 0x10840054, 0x10852855, 0x10862877, 0x10872855, 0x10882877, 0x108A0054, 
+        0x108B1054, 0x108C0054, 0x108D2877, 0x108F0054, 0x10907854, 0x10922877, 0x109308E6, 0x10942877, 
+        0x109508E7, 0x10962877, 0x10970058, 0x10982877, 0x10990054, 0x109A2855, 0x109B1071, 0x109D0054, 
+        0x109E2855, 0x109F2877, 0x10A028E8, 0x10A10019, 0x10A32855, 0x10A50054, 0x10A70078, 0x10AA305F, 
+        0x10B010E9, 0x10B110EA, 0x10B210EB, 0x10B310EC, 0x10B410ED, 0x10B510EE, 0x10B610EF, 0x10B710F0, 
+        0x10B810F1, 0x10B910F2, 0x10BA10F3, 0x10BB10F4, 0x10BC10F5, 0x10BD10F6, 0x10BE10F7, 0x10BF10F8, 
+        0x10C000F9, 0x10C100FA, 0x10C20078, 0x10C80019, 0x10CB0054, 0x10CD0819, 0x10CE0054, 0x10D00019, 
+        0x10D10054, 0x10D30019, 0x10D40054, 0x10D70819, 0x10D80054, 0x10E70819, 0x10E80054, 0x10E90019, 
+        0x10EB0054, 0x10FA0019, 0x110100E8, 0x110208E8, 0x11030019, 0x110400FB, 0x110608FC, 0x11070019, 
+        0x1109000B, 0x110A0019, 0x110B00E8, 0x110C0019, 0x110D00E8, 0x110F0019, 0x111000E8, 0x111208E8, 
+        0x11140019, 0x111610E8, 0x111700E8, 0x111810E8, 0x111900E8, 0x111A0019, 0x111E00FD, 0x111F00E8, 
+        0x112208E8, 0x112300E8, 0x11270019, 0x112900FD, 0x112B0019, 0x113008E8, 0x113200FD, 0x11360019, 
+        0x113708FD, 0x113900FD, 0x113A08FD, 0x113B00FD, 0x113C08FD, 0x113D00FD, 0x114008FD, 0x114100FD, 
+        0x114208FD, 0x114300FD, 0x114408FD, 0x114500FD, 0x114600E8, 0x11470019, 0x114800FE, 0x114A0019, 
+        0x114C00FF, 0x114D0019, 0x115100FD, 0x11520019, 0x11530100, 0x11540101, 0x115500E8, 0x115608E8, 
+        0x115800FD, 0x115C00E8, 0x115D0019, 0x115F00E8, 0x11600019, 0x116500FE, 0x11670019, 0x116800FD, 
+        0x11690019, 0x116B00FD, 0x117008FD, 0x117200FD, 0x117508FD, 0x11770019, 0x117800FD, 0x11790102, 
+        0x117B0103, 0x117C00E8, 0x117D0104, 0x117F0105, 0x11800054, 0x118400FD, 0x11860054, 0x119000E8, 
+        0x11910054, 0x1195080A, 0x11960054, 0x119B0094, 0x11BE0019, 0x11BF0054, 0x11CE0019, 0x11DA00B4, 
+        0x11DB0006, 0x11DC0054, 0x11EE0078, 0x12000054, 0x12140078, 0x12200054, 0x12260078, 0x12301906, 
+        0x12311907, 0x12321908, 0x12331909, 0x1234190A, 0x1235190B, 0x1236190C, 0x1237190D, 0x1238190E, 
+        0x1239190F, 0x123A1106, 0x123B1107, 0x123C1108, 0x123D1109, 0x123E110A, 0x123F110B, 0x1240110C, 
+        0x1241110D, 0x1242110E, 0x1243110F, 0x1244105D, 0x1245105B, 0x12461110, 0x12471111, 0x12481112, 
+        0x12491113, 0x124A1114, 0x124B1115, 0x124C1116, 0x124D1117, 0x124E1094, 0x125B1918, 0x12681919, 
+        0x127518C3, 0x1276011A, 0x1277011B, 0x1278011C, 0x1279011D, 0x127A011E, 0x127B00C4, 0x127C00C5, 
+        0x127D00C6, 0x127E00C7, 0x127F011F, 0x12800054, 0x12FC0019, 0x13000054, 0x134F0078, 0x13500054, 
+        0x13560094, 0x13570054, 0x13590078, 0x13810054, 0x13850078, 0x13860054, 0x13940078, 0x13950054, 
+        0x13A60078, 0x13A80054, 0x13AA0078, 0x13AB0054, 0x13B00078, 0x13B10054, 0x13B40009, 0x13BB0106, 
+        0x13BC0107, 0x13BD0108, 0x13BE0109, 0x13BF010A, 0x13C00106, 0x13C10107, 0x13C20108, 0x13C30109, 
+        0x13C4010A, 0x13C50106, 0x13C60107, 0x13C70108, 0x13C80109, 0x13C9010A, 0x13CA0054, 0x13CB0078, 
+        0x13CC0054, 0x13D80078, 0x13D90054, 0x13E000E8, 0x13E10019, 0x13E200FE, 0x13E3000A, 0x13E40078, 
+        0x13E80019, 0x13EA00E8, 0x13EB00FE, 0x13EC0019, 0x13EE00E8, 0x13EF00FE, 0x13F00019, 0x13F100FD, 
+        0x13F30009, 0x13F60078, 0x13F80019, 0x14000094, 0x14800019, 0x14C2000A, 0x14C70120, 0x14C80121, 
+        0x14C9000A, 0x14CD0019, 0x14CE00E8, 0x14D80019, 0x14DC0122, 0x14DD0019, 0x14E000FD, 0x14E100E8, 
+        0x14E200FD, 0x14E30019, 0x14E700E8, 0x14E800FE, 0x14EA00FD, 0x14EB0019, 0x14EC0009, 0x14EE00E8, 
+        0x14EF0019, 0x14F200E8, 0x14F30019, 0x14F400E8, 0x14F50019, 0x14FA00E8, 0x14FC00FD, 0x14FD0019, 
+        0x14FE0009, 0x14FF0019, 0x150500E8, 0x150610E8, 0x150700E8, 0x15110019, 0x151200E8, 0x15140019, 
+        0x151600FE, 0x15180019, 0x151A00FD, 0x151B0019, 0x151E00FD, 0x151F00E8, 0x15200019, 0x152C00E8, 
+        0x152D0019, 0x153200FD, 0x15330019, 0x153500E8, 0x15370019, 0x153800E8, 0x15390019, 0x153A10E8, 
+        0x153B1019, 0x153C0019, 0x153D00FE, 0x153E00E8, 0x153F00FE, 0x154300E8, 0x154600FE, 0x154700E8, 
+        0x154900FE, 0x154F00E8, 0x155100FE, 0x15520019, 0x155300FD, 0x15570019, 0x155800FE, 0x155900E8, 
+        0x155A00FE, 0x155B00E8, 0x155E00FE, 0x156400E8, 0x156700FE, 0x156C0019, 0x156E08E8, 0x156F0123, 
+        0x15700019, 0x157100E8, 0x15720124, 0x157300E8, 0x15740019, 0x157600FD, 0x157700E8, 0x15780019, 
+        0x157C00FE, 0x157E0019, 0x15800054, 0x158A0078, 0x16000096, 0x16180098, 0x16300078, 0x16400063, 
+        0x16720055, 0x16730054, 0x16760078, 0x167D0006, 0x16800125, 0x16930078, 0x16980071, 0x16B30078, 
+        0x16C00071, 0x16CC0078, 0x16D00071, 0x16F00078, 0x17000006, 0x17010126, 0x17030006, 0x170500E0, 
+        0x17060126, 0x17070006, 0x170C0078, 0x170E0126, 0x170F0078, 0x17400054, 0x174D0078, 0x174E0054, 
+        0x177A0078, 0x17801054, 0x17EB0078, 0x17F80054, 0x17FE0078, 0x18008805, 0x18010006, 0x18020054, 
+        0x18030071, 0x18040009, 0x18090054, 0x180A0009, 0x180E0099, 0x180F00BF, 0x18100054, 0x18110127, 
+        0x18120128, 0x18130129, 0x1814012A, 0x18150083, 0x18180099, 0x18190081, 0x181B1054, 0x181C112B, 
+        0x181D112C, 0x181E0071, 0x181F0054, 0x18200078, 0x18210071, 0x18260871, 0x18320071, 0x18380871, 
+        0x18390071, 0x183A0871, 0x183C0071, 0x183D0871, 0x183F0071, 0x184A0871, 0x184B0071, 0x184C0078, 
+        0x184D0083, 0x184E1037, 0x184F0881, 0x18500099, 0x18510071, 0x18560871, 0x18620071, 0x18680871, 
+        0x18690071, 0x186A0871, 0x186C0071, 0x186D0871, 0x186F0071, 0x187A0871, 0x187B0071, 0x187C0871, 
+        0x187E0081, 0x187F0881, 0x18800078, 0x18830071, 0x18970078, 0x18991071, 0x18C80094, 0x18C978AD, 
+        0x18CA78AE, 0x18CB7894, 0x18D00071, 0x18DC0078, 0x18E00054, 0x18E80078, 0x18F80071, 0x19001094, 
+        0x190F1054, 0x191010AD, 0x191110AE, 0x1912112D, 0x1913112E, 0x1914112F, 0x19151094, 0x19220078, 
+        0x19286854, 0x19291930, 0x192A1931, 0x192B1932, 0x192C1933, 0x192D1934, 0x192E1935, 0x192F1936, 
+        0x19301894, 0x193E1854, 0x194018AD, 0x194118AE, 0x1942192D, 0x1943192E, 0x1944192F, 0x19451894, 
+        0x19591937, 0x195A1938, 0x195B1939, 0x195C193A, 0x195D193B, 0x195E193C, 0x195F193D, 0x19601094, 
+        0x19666854, 0x19681894, 0x19806894, 0x19AC1094, 0x19B96894, 0x19BC6854, 0x19BE6894, 0x19EF6854, 
+        0x19F01094, 0x1A000071, 0x26DB0078, 0x26E00054, 0x27000071, 0x4FDE0078, 0x50000071, 0x52470078, 
+        0x52480054, 0x52640078, 0x53800037, 0x538C0078, 0x54000071, 0x540100C8, 0x54020071, 0x54030083, 
+        0x54040071, 0x541200A7, 0x54130083, 0x54140054, 0x54160078, 0x56000071, 0x6BD20078, 0x6C00013E, 
+        0x7000013F, 0x7C800871, 0x7D070071, 0x7D080871, 0x7D0A0071, 0x7D0B0871, 0x7D120071, 0x7D130871, 
+        0x7D140071, 0x7D150871, 0x7D170078, 0x7D180871, 0x7D360078, 0x7D380871, 0x7D6D0078, 0x7D801055, 
+        0x7D840078, 0x7D8A1055, 0x7D8C0078, 0x7D8F0083, 0x7D90289B, 0x7D95089B, 0x7DA10078, 0x7DA2089B, 
+        0x7DA8409E, 0x7DAA389E, 0x7DAB409E, 0x7DAC389E, 0x7DAD409E, 0x7DAE389E, 0x7DAF409E, 0x7DB0389E, 
+        0x7DB1409E, 0x7DB2389E, 0x7DB3409E, 0x7DB4389E, 0x7DB5409E, 0x7DB6389E, 0x7DB7409E, 0x7DB8389E, 
+        0x7DB9409E, 0x7DBA389E, 0x7DBB409E, 0x7DBC389E, 0x7DBD409E, 0x7DBE389E, 0x7DBF409E, 0x7DC0389E, 
+        0x7DC1409E, 0x7DC8389E, 0x7DC9409E, 0x7DCA389E, 0x7DCB409E, 0x7DCC389E, 0x7DCD409E, 0x7DCE389E, 
+        0x7DCF409E, 0x7DD1389E, 0x7DD2409E, 0x7DD4389E, 0x7DD5409E, 0x7DD6389E, 0x7DD7409E, 0x7DD90078, 
+        0x7DEA209E, 0x7DEB489E, 0x7DEC209E, 0x7DEF409E, 0x7DF3389E, 0x7DF5409E, 0x7DFC389E, 0x7DFD209E, 
+        0x7DFE409E, 0x7DFF389E, 0x7E00409E, 0x7E32209E, 0x7E4C389E, 0x7E70489E, 0x7E7B409E, 0x7E89209E, 
+        0x7E97389E, 0x7E9A489E, 0x7E9E209E, 0x7E9F00B4, 0x7EA00078, 0x7EA8389E, 0x7EAC209E, 0x7EAE389E, 
+        0x7EAF209E, 0x7EB0389E, 0x7EB1209E, 0x7EB4389E, 0x7EB5209E, 0x7EB8389E, 0x7EBA209E, 0x7EC3389E, 
+        0x7EC80078, 0x7EC9389E, 0x7ECB209E, 0x7ECC389E, 0x7ECD209E, 0x7EDA389E, 0x7EDB209E, 0x7EDC389E, 
+        0x7EDE209E, 0x7EE2389E, 0x7EE3209E, 0x7EE40078, 0x7EF8409E, 0x7EFE4140, 0x7EFF0078, 0x7F000083, 
+        0x7F088006, 0x7F0C80BF, 0x7F0D0078, 0x7F100083, 0x7F120078, 0x7F188006, 0x7F198099, 0x7F1A8038, 
+        0x7F1B80BF, 0x7F230006, 0x7F2480BF, 0x7F251006, 0x7F271038, 0x7F28600C, 0x7F2A6006, 0x7F2C6099, 
+        0x7F2D60BF, 0x7F306006, 0x7F31600B, 0x7F326019, 0x7F346006, 0x7F356007, 0x7F360078, 0x7F38409E, 
+        0x7F41209E, 0x7F46489E, 0x7F47209E, 0x7F49489E, 0x7F4A209E, 0x7F4C489E, 0x7F4D209E, 0x7F4E489E, 
+        0x7F4F209E, 0x7F50489E, 0x7F51209E, 0x7F52489E, 0x7F53209E, 0x7F54489E, 0x7F55209E, 0x7F5A489E, 
+        0x7F5B209E, 0x7F5C489E, 0x7F5D209E, 0x7F5E489E, 0x7F5F209E, 0x7F60489E, 0x7F61209E, 0x7F62489E, 
+        0x7F63209E, 0x7F64489E, 0x7F65209E, 0x7F66489E, 0x7F67209E, 0x7F68489E, 0x7F69209E, 0x7F6A489E, 
+        0x7F6B209E, 0x7F6C489E, 0x7F6D209E, 0x7F6E489E, 0x7F6F209E, 0x7F70489E, 0x7F71209E, 0x7F72489E, 
+        0x7F73209E, 0x7F74489E, 0x7F75209E, 0x7F76489E, 0x7F77209E, 0x7F7A489E, 0x7F7B209E, 0x7F7F0078, 
+        0x7F818806, 0x7F828808, 0x7F838806, 0x7F848809, 0x7F858806, 0x7F86880C, 0x7F88880E, 0x7F898810, 
+        0x7F8A8812, 0x7F8B8814, 0x7F8C8816, 0x7F8D880C, 0x7F8E8818, 0x7F8F881A, 0x7F908806, 0x7F918860, 
+        0x7F9E8806, 0x7F9F8837, 0x7FA18861, 0x7FAE8819, 0x7FB0880A, 0x7FB15009, 0x7FB25006, 0x7FB35071, 
+        0x7FB85081, 0x7FB95071, 0x7FCF5081, 0x7FD05071, 0x7FE00078, 0x7FE15071, 0x7FE40078, 0x7FE55071, 
+        0x7FE80078, 0x7FE95071, 0x7FEC0078, 0x7FED5071, 0x7FEF0078, 0x7FF08808, 0x7FF18819, 0x7FF28854, 
+        0x7FF38808, 0x7FF45054, 0x7FF55019, 0x7FF75054, 0x7FF80078, 0x7FFD0141, 0x7FFE0054, 0x7FFF0078, 
+        0x80000071, 0x80060078, 0x80070071, 0x801F0078, 0x80200071, 0x80270078, 0x80280071, 0x802F0078, 
+        0x80400071, 0x807E0078, 0x80800097, 0x80810094, 0x80820078, 0x808400B6, 0x808500B7, 0x808600B8, 
+        0x808700B9, 0x808800B0, 0x808900BA, 0x808A00BB, 0x808B00BC, 0x808C00BD, 0x808D0142, 0x808E0143, 
+        0x808F0144, 0x80900145, 0x809100B1, 0x80920146, 0x80930147, 0x80940148, 0x80950149, 0x8096014A, 
+        0x8097014B, 0x8098014C, 0x8099014D, 0x809A0078, 0x809C0094, 0x80A0014E, 0x80A1014F, 0x80A20150, 
+        0x80A30151, 0x80A40152, 0x80A50150, 0x80A60153, 0x80A70151, 0x80A80154, 0x80A90155, 0x80AA0156, 
+        0x80AB0157, 0x80AC014F, 0x80AE0158, 0x80B00154, 0x80B30150, 0x80B50155, 0x80B60153, 0x80B90151, 
+        0x80BA0150, 0x80BB005F, 0x80BD0054, 0x80C500C3, 0x80C60078, 0x81800071, 0x819000AD, 0x819100B0, 
+        0x81920078, 0x81980071, 0x81A50159, 0x81A60078, 0x81C00071, 0x81CF0078, 0x81D00071, 0x81E20078, 
+        0x81E40071, 0x81E80094, 0x81E90158, 0x81EA015A, 0x81EB0078, 0x8200015B, 0x8214015C, 0x82280071, 
+        0x824F0078, 0x825000A8, 0x825100A9, 0x825200AA, 0x825300AB, 0x825400AC, 0x82550078, 0x8400009B, 
+        0x84030078, 0x8404009B, 0x841B0078, 0x841C009B, 0x841D0078, 0x841E009B, 0x841F0078, 0x8500009B, 
+        0x85010083, 0x85020078, 0x85030083, 0x85040078, 0x85060083, 0x8508009B, 0x850A0078, 0x850B009B, 
+        0x850C0078, 0x850D009B, 0x851A0078, 0x851C0083, 0x851E0078, 0x8520015D, 0x8521015E, 0x8522015F, 
+        0x85230160, 0x85240078, 0x8528009A, 0x852D0078, 0xE8000094, 0xE87B0078, 0xE8800094, 0xE8940078, 
+        0xE8950094, 0xE8AF0894, 0xE8B300A7, 0xE8B40083, 0xE8B50094, 0xE8B700A7, 0xE8BA0057, 0xE8BE0083, 
+        0xE8C20094, 0xE8C30083, 0xE8C60094, 0xE8D50083, 0xE8D70094, 0xE8DE0894, 0xE8E10094, 0xE8EF0078, 
+        0xE9000054, 0xE9210083, 0xE9230078, 0xE9800054, 0xE9AC0078, 0xEA002877, 0xEA0D2855, 0xEA1A2877, 
+        0xEA272855, 0xEA342877, 0xEA412855, 0xEA4E2877, 0xEA500078, 0xEA512877, 0xEA520078, 0xEA532877, 
+        0xEA540078, 0xEA552877, 0xEA5B2855, 0xEA5D0078, 0xEA5F2855, 0xEA620078, 0xEA632855, 0xEA682877, 
+        0xEA752855, 0xEA822877, 0xEA830078, 0xEA842877, 0xEA860078, 0xEA872877, 0xEA8F2855, 0xEA9C2877, 
+        0xEA9D0078, 0xEA9E2877, 0xEAA40078, 0xEAA52877, 0xEAA92855, 0xEAB62877, 0xEAC32855, 0xEAD02877, 
+        0xEADD2855, 0xEAEA2877, 0xEAF72855, 0xEB042877, 0xEB112855, 0xEB1E2877, 0xEB2B2855, 0xEB382877, 
+        0xEB452855, 0xEB530078, 0xEB542877, 0xEB612855, 0xEB712877, 0xEB7E2855, 0xEB8E2877, 0xEB9B2855, 
+        0xEBAB2877, 0xEBB82855, 0xEBC82877, 0xEBD52855, 0xEBE50078, 0xEBE7280E, 0xEBE82810, 0xEBE92812, 
+        0xEBEA2814, 0xEBEB2816, 0xEBEC280E, 0xEBED2810, 0xEBEE2812, 0xEBEF2814, 0xEBF02816, 0xEBF1280E, 
+        0xEBF22810, 0xEBF32812, 0xEBF42814, 0xEBF52816, 0xEBF6280E, 0xEBF72810, 0xEBF82812, 0xEBF92814, 
+        0xEBFA2816, 0xEBFB280E, 0xEBFC2810, 0xEBFD2812, 0xEBFE2814, 0xEBFF2816, 0xEC000078
+    };
+
+    static const uint32_t a1[] = {
+        0x00000071, 0x536C0078, 0x7C000871, 0x7D0F0078
+    };
+
+    static const uint32_t a7[] = {
+        0x00100057, 0x00400078, 0x00800083, 0x00F80078, 0x8000013F, 0xFFFF0078
+    };
+
+    static const uint32_t a8[] = {
+        0x0000013F, 0x7FFF0078
+    };
+
+    static const uint32_t a16[] = {
+        0x00800865, 0x00880065, 0x00890865, 0x00930065, 0x00940865, 0x00980161, 0x00991065, 0x009A0865, 
+        0x009C0863, 0x009F1063, 0x00A00063, 0x00A10863, 0x00A41055, 0x00A50065, 0x00A60865, 0x00A90065, 
+        0x00AA0865, 0x00B30065, 0x00B40865, 0x00BC0863, 0x00BF1162, 0x00C00163, 0x00C10065, 0x00C30063, 
+        0x00C40068, 0x00C50063, 0x00C60055, 0x00C70164, 0x00C80063, 0x00C90068, 0x00CA0165, 0x00CB0166, 
+        0x00CC0065, 0x00CD0055, 0x00CE0167, 0x00CF0168, 0x00D00865, 0x00D10065, 0x00D30063, 0x00D4006F, 
+        0x00D50055, 0x00D60065, 0x00D70863, 0x00D80070, 0x00D90063, 0x00DB0169, 0x00DC0065, 0x00DD0071, 
+        0x00DE0065, 0x00DF016A, 0x00E00071, 0x00E21074, 0x00E31072, 0x00E41073, 0x00E51074, 0x00E60863, 
+        0x00EE016B, 0x00EF0865, 0x00F20065, 0x00F30865, 0x00F81072, 0x00F91073, 0x00FA0865, 0x00FB016C, 
+        0x00FC0865, 0x010E0065, 0x010F0865, 0x01100055, 0x01110065, 0x01130865, 0x011A0055, 0x011D0063, 
+        0x011E016D, 0x011F0055, 0x0120016E, 0x01210078, 0x01280055, 0x0129016F, 0x012A0055, 0x012B007A, 
+        0x012C0170, 0x012D0171, 0x012E0055, 0x01310172, 0x01320055, 0x01340173, 0x01350055, 0x01370173, 
+        0x01380055, 0x013A0174, 0x013B0055, 0x0141007D, 0x01420055, 0x0145007E, 0x01460055, 0x01587881, 
+        0x015C0082, 0x015D0081, 0x01610037, 0x01630082, 0x01680081, 0x01690037, 0x016C1037, 0x016F0037, 
+        0x01707881, 0x01720037, 0x01800083, 0x01A00883, 0x01A20175, 0x01A30083, 0x01B80078, 0x01BA0037, 
+        0x01BB0078, 0x01C20837, 0x01C30806, 0x01C40885, 0x01C50078, 0x01C70887, 0x01C80060, 0x01D50860, 
+        0x01D60889, 0x01D80061, 0x01E50861, 0x01E6088C, 0x01E70078, 0x01E81176, 0x01E90877, 0x01EA1177, 
+        0x01EB0055, 0x01EC0065, 0x01F81093, 0x01F90055, 0x01FA1178, 0x01FB0063, 0x01FC10D8, 0x01FD0065, 
+        0x01FE0077, 0x02000892, 0x02020092, 0x02030892, 0x02040092, 0x02060892, 0x02070092, 0x02080060, 
+        0x020C0860, 0x020D0060, 0x02180061, 0x021C0861, 0x021D0061, 0x02280893, 0x022A0093, 0x022B0893, 
+        0x022C0093, 0x022E0893, 0x022F0093, 0x02300065, 0x023B0865, 0x023C0065, 0x02410083, 0x02430078, 
+        0x02440095, 0x02450065, 0x02600863, 0x02610063, 0x02670078, 0x02680865, 0x026A0065, 0x026B0865, 
+        0x026C0065, 0x026D0865, 0x02700065, 0x02710865, 0x02740065, 0x02750865, 0x027B0065, 0x027C0865, 
+        0x027D0078, 0x02800065, 0x02880078, 0x02980096, 0x02AB0078, 0x02AC0081, 0x02AD0097, 0x02B00098, 
+        0x02C31055, 0x02C40097, 0x02C50078, 0x02C80083, 0x02E1009A, 0x02E20083, 0x02E40078, 0x02E8009B, 
+        0x02F50078, 0x02F8009B, 0x02F9009A, 0x02FA0078, 0x0300009C, 0x03020078, 0x03050140, 0x0306009D, 
+        0x03070054, 0x03080083, 0x030B0078, 0x030D009D, 0x030E0078, 0x030F009D, 0x0310009E, 0x0311089E, 
+        0x0313009E, 0x031D0078, 0x0320009E, 0x03250083, 0x032F0078, 0x03300179, 0x0331017A, 0x0332017B, 
+        0x0333017C, 0x0334017D, 0x033500A5, 0x0336009D, 0x0337009E, 0x033A109E, 0x033C009E, 0x0369089E, 
+        0x036A009E, 0x036B0083, 0x036E009C, 0x036F0083, 0x0372009F, 0x03730083, 0x03740054, 0x03750083, 
+        0x0377009E, 0x0378000F, 0x03790011, 0x037A0013, 0x037B0015, 0x037C0017, 0x037D009E, 0x037E00A6, 
+        0x037F009E, 0x0380009D, 0x03870057, 0x03880083, 0x0389009E, 0x03980083, 0x03A50078, 0x03A6009E, 
+        0x03B70078, 0x03C0009E, 0x03D30083, 0x03D8009E, 0x03D90078, 0x04800083, 0x048100A7, 0x04820071, 
+        0x04940871, 0x04950071, 0x04980871, 0x04990071, 0x049D0078, 0x049E0071, 0x049F00A7, 0x04A00083, 
+        0x04A400A7, 0x04A60083, 0x04A70078, 0x04A80083, 0x04AA0078, 0x04AC0871, 0x04B00071, 0x04B10083, 
+        0x04B20097, 0x04B3017E, 0x04B4017F, 0x04B50180, 0x04B60181, 0x04B70182, 0x04B80078, 0x04BE0071, 
+        0x04BF0078, 0x04C00083, 0x04C100A7, 0x04C20071, 0x04C60078, 0x04C70071, 0x04C80078, 0x04C90071, 
+        0x04D40078, 0x04D50071, 0x04D80078, 0x04DB0071, 0x04DD0078, 0x04DE0071, 0x04DF00A7, 0x04E00083, 
+        0x04E20078, 0x04E300A7, 0x04E40078, 0x04E508A7, 0x04E60083, 0x04E70078, 0x04EB00A7, 0x04EC0078, 
+        0x04EE0871, 0x04F00071, 0x04F10083, 0x04F20078, 0x04F3017E, 0x04F4017F, 0x04F50180, 0x04F60181, 
+        0x04F70182, 0x04F80071, 0x04F90008, 0x04FA00B6, 0x04FB00B7, 0x04FC0183, 0x04FD0078, 0x05000083, 
+        0x050100A7, 0x05020071, 0x05050078, 0x05070071, 0x05080078, 0x05090071, 0x05140078, 0x05150071, 
+        0x05180078, 0x05190871, 0x051A0071, 0x051B0078, 0x051C0071, 0x051D0078, 0x051F00A7, 0x05200083, 
+        0x05210078, 0x05230083, 0x05240078, 0x05250083, 0x05270078, 0x052C0871, 0x052E0078, 0x0533017E, 
+        0x0534017F, 0x05350180, 0x05360181, 0x05370182, 0x05380083, 0x05390071, 0x053A0078, 0x05400083, 
+        0x054100A7, 0x05420071, 0x05540078, 0x05550071, 0x05580078, 0x05590071, 0x055D0078, 0x055E0071, 
+        0x055F00A7, 0x05600083, 0x056400A7, 0x05660083, 0x05670078, 0x05700071, 0x05710083, 0x05720078, 
+        0x0573017E, 0x0574017F, 0x05750180, 0x05760181, 0x05770182, 0x05780008, 0x05790078, 0x05800083, 
+        0x058100A7, 0x05820071, 0x05860078, 0x05870071, 0x05880078, 0x05890071, 0x05940078, 0x05950071, 
+        0x05980078, 0x05990071, 0x059D0078, 0x059E0071, 0x059F0083, 0x05A20078, 0x05A300A7, 0x05A40078, 
+        0x05A508A7, 0x05A60083, 0x05A70078, 0x05AB00A7, 0x05AC0078, 0x05AE0871, 0x05AF0071, 0x05B10078, 
+        0x05B3017E, 0x05B4017F, 0x05B50180, 0x05B60181, 0x05B70182, 0x05B80071, 0x05B90078, 0x05C10071, 
+        0x05C50078, 0x05C70071, 0x05C80078, 0x05C90071, 0x05CB0078, 0x05CC0071, 0x05CD0078, 0x05CF0071, 
+        0x05D00078, 0x05D10071, 0x05D20078, 0x05D40071, 0x05D50078, 0x05D70071, 0x05DD0078, 0x05DF00A7, 
+        0x05E10078, 0x05E300A7, 0x05E40078, 0x05E508A7, 0x05E60083, 0x05E70078, 0x05EB00A7, 0x05EC0078, 
+        0x05F3017E, 0x05F4017F, 0x05F50180, 0x05F60181, 0x05F70182, 0x05F80184, 0x05F90054, 0x05FC0008, 
+        0x05FD0078, 0x060000A7, 0x06020071, 0x06060078, 0x06070071, 0x06080078, 0x06090071, 0x06140078, 
+        0x06150071, 0x061D0078, 0x061F0083, 0x062000A7, 0x06220078, 0x06230083, 0x06240078, 0x06250083, 
+        0x06270078, 0x062A0083, 0x062B0078, 0x06300071, 0x06310078, 0x0633017E, 0x0634017F, 0x06350180, 
+        0x06360181, 0x06370182, 0x06380078, 0x064100A7, 0x06420071, 0x06460078, 0x06470071, 0x06480078, 
+        0x06490071, 0x06540078, 0x06550071, 0x065D0078, 0x065E0071, 0x065F00B2, 0x066000A7, 0x06620078, 
+        0x066308A7, 0x06640078, 0x066508A7, 0x06660083, 0x06670078, 0x066A00A7, 0x066B0078, 0x06700071, 
+        0x06710078, 0x0673017E, 0x0674017F, 0x06750180, 0x06760181, 0x06770182, 0x06780078, 0x068100A7, 
+        0x06820071, 0x06860078, 0x06870071, 0x06880078, 0x06890071, 0x06940078, 0x06950071, 0x069D0078, 
+        0x069F00A7, 0x06A00083, 0x06A20078, 0x06A300A7, 0x06A40078, 0x06A508A7, 0x06A60083, 0x06A70078, 
+        0x06AB00A7, 0x06AC0078, 0x06B00071, 0x06B10078, 0x06B3017E, 0x06B4017F, 0x06B50180, 0x06B60181, 
+        0x06B70182, 0x06B80078, 0x06C100A7, 0x06C20071, 0x06CB0078, 0x06CD0071, 0x06DF0078, 0x06E00071, 
+        0x06E30078, 0x06E700A7, 0x06E90083, 0x06EA0078, 0x06EC00A7, 0x06EE08A7, 0x06EF00A7, 0x06F00078, 
+        0x06F900A7, 0x06FA0078, 0x07000071, 0x07180083, 0x07191071, 0x071A0083, 0x071D0078, 0x071F0008, 
+        0x07200071, 0x07230083, 0x07270097, 0x0728017E, 0x0729017F, 0x072A0180, 0x072B0181, 0x072C0182, 
+        0x072D0097, 0x072E0078, 0x07400071, 0x07410078, 0x07430071, 0x07440078, 0x07460071, 0x07470078, 
+        0x074A0071, 0x07540078, 0x07550071, 0x07580083, 0x07591071, 0x075A0083, 0x075E0071, 0x075F0078, 
+        0x07600071, 0x07620078, 0x07640083, 0x07670078, 0x0768017E, 0x0769017F, 0x076A0180, 0x076B0181, 
+        0x076C0182, 0x076D0078, 0x076E1071, 0x076F0078, 0x07800094, 0x07820097, 0x07890094, 0x078C0083, 
+        0x078D0094, 0x0790017E, 0x0791017F, 0x07920180, 0x07930181, 0x07940182, 0x079500B3, 0x079A0083, 
+        0x079D00BF, 0x079F00A7, 0x07A00071, 0x07A10871, 0x07A20071, 0x07A60871, 0x07A70071, 0x07AB0871, 
+        0x07AC0071, 0x07B40871, 0x07B50078, 0x07B80083, 0x07B90883, 0x07BB1083, 0x07BD0083, 0x07BF00A7, 
+        0x07C00883, 0x07C10083, 0x07C20097, 0x07C30083, 0x07C40071, 0x07C60078, 0x07C80083, 0x07C90883, 
+        0x07CA0083, 0x07CE0883, 0x07CF0083, 0x07D30883, 0x07D40083, 0x07DC0883, 0x07DD0083, 0x07DE0078, 
+        0x07DF0094, 0x07E60078, 0x07E70094, 0x07E80097, 0x07E90078, 0x08000071, 0x08150078, 0x08160083, 
+        0x081800A7, 0x08190078, 0x081B0083, 0x081D0078, 0x0820017E, 0x0821017F, 0x08220180, 0x08230181, 
+        0x08240182, 0x08250097, 0x08280071, 0x082B00A7, 0x082C0083, 0x082D0078, 0x085000B5, 0x08630078, 
+        0x08680071, 0x087D0097, 0x087E0078, 0x08800071, 0x08AD0078, 0x08AF0071, 0x08D10078, 0x08D40071, 
+        0x08FD0078, 0x09000071, 0x09240078, 0x09250071, 0x09270078, 0x09280071, 0x092B0078, 0x092D0071, 
+        0x092F0078, 0x09300071, 0x09440078, 0x09450071, 0x09470078, 0x09480071, 0x09580078, 0x09590071, 
+        0x095B0078, 0x095C0071, 0x095F0078, 0x09610071, 0x09630078, 0x09640071, 0x096B0078, 0x096C0071, 
+        0x09880078, 0x09890071, 0x098B0078, 0x098C0071, 0x09AD0078, 0x09AF0083, 0x09B00097, 0x09B400AD, 
+        0x09B500AE, 0x09B6012D, 0x09B7012E, 0x09B8012F, 0x09B90185, 0x09BA0186, 0x09BB0187, 0x09BC0188, 
+        0x09BD0184, 0x09BE0078, 0x09C00071, 0x09C80054, 0x09CD0078, 0x09D00071, 0x09FA0078, 0x0A000071, 
+        0x0B360097, 0x0B370071, 0x0B3B0078, 0x0B400071, 0x0B4D00B4, 0x0B4E0078, 0x0B500071, 0x0B750097, 
+        0x0B770189, 0x0B780078, 0x0B800071, 0x0B860078, 0x0B870071, 0x0B890083, 0x0B8A0078, 0x0B900071, 
+        0x0B990083, 0x0B9A0097, 0x0B9B0078, 0x0BA00071, 0x0BA90083, 0x0BAA0078, 0x0BB00071, 0x0BB60078, 
+        0x0BB70071, 0x0BB80078, 0x0BB90083, 0x0BBA0078, 0x0BC00071, 0x0BDA00C2, 0x0BDB0083, 0x0BDF00A7, 
+        0x0BE40083, 0x0BEA0097, 0x0BEB0081, 0x0BEC0097, 0x0BED0008, 0x0BEE0083, 0x0BEF0078, 0x0BF0017E, 
+        0x0BF1017F, 0x0BF20180, 0x0BF30181, 0x0BF40182, 0x0BF50078, 0x0BF80106, 0x0BF90107, 0x0BFA0108, 
+        0x0BFB0109, 0x0BFC010A, 0x0BFD0078, 0x0C000006, 0x0C050083, 0x0C070078, 0x0C08017E, 0x0C09017F, 
+        0x0C0A0180, 0x0C0B0181, 0x0C0C0182, 0x0C0D0078, 0x0C100071, 0x0C210081, 0x0C220071, 0x0C3C0078, 
+        0x0C400071, 0x0C540083, 0x0C550078, 0x0C800071, 0x0C8E0078, 0x0C900083, 0x0C9100A7, 0x0C930083, 
+        0x0C9400C8, 0x0C960078, 0x0C9800A7, 0x0C9C0083, 0x0C9E0078, 0x0CA20006, 0x0CA3017E, 0x0CA4017F, 
+        0x0CA50180, 0x0CA60181, 0x0CA70182, 0x0CA80071, 0x0CB70078, 0x0CB80071, 0x0CBA0078, 0x0CC00071, 
+        0x0CD50078, 0x0CD800A7, 0x0CE00071, 0x0CE400A7, 0x0CE50078, 0x0CE8017E, 0x0CE9017F, 0x0CEA0180, 
+        0x0CEB0181, 0x0CEC0182, 0x0CED0078, 0x0CEF0006, 0x0CF00054, 0x0D000071, 0x0D0B0083, 0x0D0C00A7, 
+        0x0D0E0078, 0x0D0F0097, 0x0D100078, 0x0E800055, 0x0E967881, 0x0E970081, 0x0E987881, 0x0E9D0081, 
+        0x0E9E7881, 0x0EB17055, 0x0EB50055, 0x0ECD7881, 0x0EE00083, 0x0EE20078, 0x0F000865, 0x0F4B0855, 
+        0x0F4D098A, 0x0F4E0078, 0x0F500865, 0x0F7D0078, 0x0F8008C9, 0x0F8408CA, 0x0F8808C9, 0x0F8B0078, 
+        0x0F8C08CA, 0x0F8F0078, 0x0F9008C9, 0x0F9408CA, 0x0F9808C9, 0x0F9C08CA, 0x0FA008C9, 0x0FA30078, 
+        0x0FA408CA, 0x0FA70078, 0x0FA808C9, 0x0FAC08CA, 0x0FB008C9, 0x0FB408CA, 0x0FB808CB, 0x0FB908CC, 
+        0x0FBB08CD, 0x0FBC08CE, 0x0FBD08CF, 0x0FBE08D0, 0x0FBF0078, 0x0FC008C9, 0x0FC408D1, 0x0FC808C9, 
+        0x0FCC08D1, 0x0FD008C9, 0x0FD408D1, 0x0FD808C9, 0x0FD9098B, 0x0FDA0078, 0x0FDB0855, 0x0FDC08CA, 
+        0x0FDD08D2, 0x0FDE1037, 0x0FE00837, 0x0FE1098B, 0x0FE20078, 0x0FE30855, 0x0FE408D5, 0x0FE60837, 
+        0x0FE808C9, 0x0FE90855, 0x0FEA0078, 0x0FEB0855, 0x0FEC08CA, 0x0FED08D6, 0x0FEE0837, 0x0FF008C9, 
+        0x0FF10855, 0x0FF20890, 0x0FF30855, 0x0FF408CA, 0x0FF508D7, 0x0FF60837, 0x0FF80078, 0x0FF9098B, 
+        0x0FFA0078, 0x0FFB0855, 0x0FFC08D9, 0x0FFD08DA, 0x0FFE0837, 0x0FFF0078, 0x10000805, 0x10011005, 
+        0x10035805, 0x10041005, 0x10050057, 0x1007018C, 0x10085899, 0x10090099, 0x100B1006, 0x100C018D, 
+        0x100D00DB, 0x100E018D, 0x100F00DB, 0x10100006, 0x10121006, 0x10130006, 0x1014018E, 0x1015018F, 
+        0x10160190, 0x10175853, 0x10180007, 0x10191007, 0x101A0006, 0x101B1006, 0x101C0126, 0x101D0006, 
+        0x101F0038, 0x10200006, 0x10220009, 0x10231006, 0x10250006, 0x102B1006, 0x102C0006, 0x102F1005, 
+        0x10300057, 0x10320078, 0x10350057, 0x10387855, 0x10390078, 0x103A7910, 0x103B7911, 0x103C7912, 
+        0x103D780B, 0x103E7809, 0x103F7855, 0x1040705D, 0x1041705B, 0x10427110, 0x10437111, 0x10447112, 
+        0x1045700B, 0x10467009, 0x10470078, 0x10487081, 0x104A0078, 0x10500008, 0x105B0078, 0x10680083, 
+        0x106E0095, 0x10700083, 0x10710095, 0x10720083, 0x10760078, 0x10801054, 0x10831077, 0x10841054, 
+        0x10852877, 0x10872855, 0x10882877, 0x10892855, 0x108A2877, 0x108B0054, 0x108C2877, 0x108F0054, 
+        0x10901054, 0x10910054, 0x10950991, 0x10962877, 0x10972855, 0x10982877, 0x109A1071, 0x109C2855, 
+        0x109D1054, 0x109E2855, 0x109F2877, 0x10A00019, 0x10A22877, 0x10A32855, 0x10A50019, 0x10A60078, 
+        0x10A9305F, 0x10AF3106, 0x10B01192, 0x10B11193, 0x10B21194, 0x10B31195, 0x10B41196, 0x10B51197, 
+        0x10B61198, 0x10B71199, 0x10B8119A, 0x10B9119B, 0x10BA119C, 0x10BB119D, 0x10BC119E, 0x10BD119F, 
+        0x10BE11A0, 0x10BF11A1, 0x10C001A2, 0x10C101A3, 0x10C20078, 0x10C80019, 0x10CA0054, 0x10CD0819, 
+        0x10CE0054, 0x10D10019, 0x10D20054, 0x10E60854, 0x10E70819, 0x10E80054, 0x10FA0019, 0x110000E8, 
+        0x11020019, 0x110408FB, 0x110500FC, 0x11070019, 0x110800E8, 0x11090059, 0x110A01A4, 0x110B0019, 
+        0x110D00E8, 0x11110019, 0x111500E8, 0x111610E8, 0x111800E8, 0x111A0019, 0x111C00E8, 0x111E00FE, 
+        0x111F00E8, 0x112008E8, 0x112101A5, 0x112200E8, 0x112308E8, 0x112500E8, 0x11260019, 0x112900FE, 
+        0x112B0019, 0x112F00E8, 0x11300019, 0x113200FE, 0x11360819, 0x113708FE, 0x113900FE, 0x113A08FE, 
+        0x113B00FE, 0x113C08FE, 0x113D00FE, 0x114008FE, 0x114100FE, 0x114208FE, 0x114300FE, 0x114408FE, 
+        0x114500FE, 0x11460019, 0x114700FD, 0x11490019, 0x115100FE, 0x11520019, 0x115300E8, 0x115401A6, 
+        0x115608E8, 0x115800FE, 0x115C0019, 0x115F00E8, 0x11600019, 0x116400FD, 0x116601A7, 0x11670019, 
+        0x116800FE, 0x11690019, 0x116B00FE, 0x117008FE, 0x117200FE, 0x117508FE, 0x11770019, 0x117800FE, 
+        0x11790102, 0x117A00E8, 0x117B0103, 0x117C00E8, 0x117D0104, 0x117E0105, 0x117F00E8, 0x11800054, 
+        0x118400FE, 0x11860054, 0x119000E8, 0x11910054, 0x11940809, 0x11950054, 0x119B0094, 0x11BD0054, 
+        0x11CA0094, 0x11CB0054, 0x11CD0019, 0x11DA00BF, 0x11DB0054, 0x11EE0078, 0x12000054, 0x12130078, 
+        0x12200054, 0x12250078, 0x123018C4, 0x123118C5, 0x123218C6, 0x123318C7, 0x1234191F, 0x1235191A, 
+        0x1236191B, 0x1237191C, 0x1238191D, 0x1239191E, 0x123A10C4, 0x123B10C5, 0x123C10C6, 0x123D10C7, 
+        0x123E111F, 0x123F111A, 0x1240111B, 0x1241111C, 0x1242111D, 0x1243111E, 0x1244105A, 0x124510E3, 
+        0x124610E4, 0x124710E5, 0x124811A8, 0x124911A9, 0x124A11AA, 0x124B11AB, 0x124C11AC, 0x124D11AD, 
+        0x124E1094, 0x125B1918, 0x12681919, 0x1275010B, 0x1276010C, 0x1277010D, 0x1278010E, 0x1279010F, 
+        0x127A0106, 0x127B0107, 0x127C0108, 0x127D0109, 0x127E010A, 0x127F00C3, 0x12800054, 0x12DB0019, 
+        0x12DC0054, 0x12E00019, 0x12E10054, 0x12FC0019, 0x13000054, 0x13370019, 0x13380054, 0x134E0078, 
+        0x13500054, 0x13590078, 0x13800054, 0x13820078, 0x13830054, 0x13850078, 0x13860054, 0x13A90078, 
+        0x13AC0054, 0x13AF0078, 0x13B00054, 0x13B4000A, 0x13BB00C4, 0x13BC00C5, 0x13BD00C6, 0x13BE00C7, 
+        0x13BF011F, 0x13C000C4, 0x13C100C5, 0x13C200C6, 0x13C300C7, 0x13C4011F, 0x13C500C4, 0x13C600C5, 
+        0x13C700C6, 0x13C800C7, 0x13C9011F, 0x13CA0078, 0x13CC0054, 0x13DF0078, 0x13E00019, 0x13E100FD, 
+        0x13E20009, 0x13E30078, 0x13E80019, 0x13E900E8, 0x13EA00FD, 0x13EB0019, 0x13EE00FD, 0x13EF0019, 
+        0x13F100FE, 0x13F3000A, 0x13F60078, 0x13F80019, 0x14000094, 0x14800019, 0x14C10009, 0x14C601AE, 
+        0x14C701AF, 0x14C80009, 0x14CC0019, 0x14CD00E8, 0x14D80019, 0x14E000FE, 0x14E100E8, 0x14E200FE, 
+        0x14E30019, 0x14E400E8, 0x14E50019, 0x14E700FD, 0x14E90019, 0x14EA00FE, 0x14EB0019, 0x14EC000A, 
+        0x14EE0019, 0x14F000E8, 0x14F30019, 0x14F400E8, 0x14F50019, 0x14FA01B0, 0x14FB00E8, 0x14FC00FE, 
+        0x14FD0019, 0x14FE000A, 0x14FF0019, 0x150500E8, 0x150E0019, 0x150F00E8, 0x15110019, 0x151400E8, 
+        0x151500FD, 0x15170019, 0x151A00FE, 0x151B0019, 0x151E00FE, 0x151F0019, 0x152B00E8, 0x152C0019, 
+        0x153200FE, 0x15330019, 0x153500E8, 0x15380019, 0x153900E8, 0x153A1019, 0x153B0019, 0x153C00FD, 
+        0x153D00E8, 0x153E00FD, 0x154200E8, 0x154500FD, 0x154600E8, 0x154800FD, 0x154E00E8, 0x155000FD, 
+        0x155100E8, 0x15520019, 0x155300FE, 0x155700FD, 0x155800E8, 0x155900FD, 0x155A00E8, 0x155D00FD, 
+        0x156300E8, 0x156600FD, 0x156B0019, 0x157101B1, 0x15730019, 0x157600FE, 0x15770019, 0x157900E8, 
+        0x157A0019, 0x157B00FD, 0x157D00E8, 0x157F0019, 0x15800054, 0x158A0078, 0x16000096, 0x16170078, 
+        0x16180098, 0x162F0078, 0x16400065, 0x16720054, 0x16750078, 0x167C0006, 0x167E005F, 0x167F0006, 
+        0x16800125, 0x16930078, 0x16980071, 0x16B30078, 0x16B77881, 0x16B80078, 0x16C00071, 0x16CB0078, 
+        0x16D00071, 0x16D30078, 0x16D40071, 0x16D70078, 0x16D80071, 0x16DB0078, 0x16DC0071, 0x16DF0078, 
+        0x16E00071, 0x16E30078, 0x16E40071, 0x16E70078, 0x16E80071, 0x16EB0078, 0x16EC0071, 0x16EF0078, 
+        0x17000006, 0x170100E0, 0x17030006, 0x17040126, 0x17050006, 0x170600E0, 0x17070006, 0x170B0099, 
+        0x170C0078, 0x170E00E0, 0x170F0078, 0x17400054, 0x174F1054, 0x17500054, 0x17791054, 0x177A0078, 
+        0x17801054, 0x17EB0078, 0x17F80054, 0x17FE0078, 0x18000006, 0x18020081, 0x180301B2, 0x1804000A, 
+        0x18090054, 0x180A000A, 0x180E00B4, 0x180F00BF, 0x181001B3, 0x181101B4, 0x181201B5, 0x181301B6, 
+        0x181401B7, 0x18150083, 0x18180081, 0x181B0054, 0x181C11B8, 0x181D0081, 0x181E0006, 0x181F0054, 
+        0x18200071, 0x18320871, 0x18350071, 0x18380871, 0x183A0071, 0x183B0871, 0x183D0071, 0x183E0871, 
+        0x183F0071, 0x184B0078, 0x184C0083, 0x184D1037, 0x184E0081, 0x184F8071, 0x18500071, 0x18620871, 
+        0x18650071, 0x18680871, 0x186A0071, 0x186B0871, 0x186D0071, 0x186E0871, 0x186F0071, 0x187B0871, 
+        0x187D0006, 0x187E0081, 0x187F8071, 0x18800078, 0x18820071, 0x18960078, 0x18981071, 0x18C70078, 
+        0x18C80094, 0x18C978B6, 0x18CA78B7, 0x18CB7894, 0x18D00071, 0x18DC0078, 0x18E00054, 0x18E80078, 
+        0x18F80071, 0x19001094, 0x190E1054, 0x190F0078, 0x191010B6, 0x191110B7, 0x191210B8, 0x191310B9, 
+        0x191410B0, 0x19151094, 0x19220078, 0x192819B9, 0x192919BA, 0x192A19BB, 0x192B19BC, 0x192C19BD, 
+        0x192D19BE, 0x192E19BF, 0x192F19C0, 0x19301894, 0x193E1854, 0x193F0094, 0x194018B6, 0x194118B7, 
+        0x194218B8, 0x194318B9, 0x194418B0, 0x19451894, 0x195819C1, 0x195919C2, 0x195A19C3, 0x195B19C4, 
+        0x195C19C5, 0x195D19C6, 0x195E19C7, 0x195F19C8, 0x19601094, 0x19666854, 0x19681894, 0x197F0078, 
+        0x19806894, 0x19AC1094, 0x19B86894, 0x19BB6854, 0x19BD6894, 0x19EF6854, 0x19F01094, 0x19FF6854, 
+        0x1A000071, 0x26DB0078, 0x26E00054, 0x27000071, 0x4FDE0078, 0x50000071, 0x500A0081, 0x500B0071, 
+        0x52460078, 0x52480054, 0x52630078, 0x53800037, 0x538B0078, 0x54000071, 0x54050083, 0x54060071, 
+        0x541100A7, 0x54120083, 0x541300A7, 0x54140054, 0x54160078, 0x56000071, 0x6BD20078, 0x6C00013E, 
+        0x7000013F, 0x7C800871, 0x7D070071, 0x7D0A0871, 0x7D0F0071, 0x7D120871, 0x7D130071, 0x7D150871, 
+        0x7D170078, 0x7D180871, 0x7D350078, 0x7D380871, 0x7D6D0078, 0x7D801055, 0x7D830078, 0x7D891055, 
+        0x7D8C0078, 0x7D8E089B, 0x7D90289B, 0x7D94280B, 0x7D95089B, 0x7D9B0078, 0x7D9C089B, 0x7D9E0078, 
+        0x7DA0089B, 0x7DA20078, 0x7DA3089B, 0x7DA7109B, 0x7DA8209E, 0x7DAA489E, 0x7DAB209E, 0x7DAC489E, 
+        0x7DAD209E, 0x7DAE489E, 0x7DAF209E, 0x7DB0489E, 0x7DB1209E, 0x7DB2489E, 0x7DB3209E, 0x7DB4489E, 
+        0x7DB5209E, 0x7DB6489E, 0x7DB7209E, 0x7DB8489E, 0x7DB9209E, 0x7DBA489E, 0x7DBB209E, 0x7DBC489E, 
+        0x7DBD209E, 0x7DBE489E, 0x7DBF209E, 0x7DC0489E, 0x7DC1209E, 0x7DC8489E, 0x7DC9209E, 0x7DCA489E, 
+        0x7DCB209E, 0x7DCC489E, 0x7DCD209E, 0x7DCE489E, 0x7DCF209E, 0x7DD1489E, 0x7DD2209E, 0x7DD4489E, 
+        0x7DD5209E, 0x7DD6489E, 0x7DD7209E, 0x7DD90078, 0x7DE9409E, 0x7DEA389E, 0x7DEB409E, 0x7DEF209E, 
+        0x7DF3489E, 0x7DF5209E, 0x7DFC409E, 0x7DFD389E, 0x7DFE209E, 0x7DFF489E, 0x7E00409E, 0x7E32209E, 
+        0x7E4B389E, 0x7E6F489E, 0x7E7A409E, 0x7E88209E, 0x7E96389E, 0x7E9A489E, 0x7E9E409E, 0x7E9F00BF, 
+        0x7EA00078, 0x7EA8209E, 0x7EA9389E, 0x7EAD209E, 0x7EAE389E, 0x7EAF209E, 0x7EB0389E, 0x7EB3209E, 
+        0x7EB5389E, 0x7EB7209E, 0x7EB9389E, 0x7EBA209E, 0x7EBB389E, 0x7EBC209E, 0x7EBE389E, 0x7EBF209E, 
+        0x7EC1389E, 0x7EC2209E, 0x7EC4389E, 0x7EC5209E, 0x7EC6389E, 0x7EC80078, 0x7EC9389E, 0x7ECB209E, 
+        0x7ECE389E, 0x7ECF209E, 0x7EDA389E, 0x7EDB209E, 0x7EE1389E, 0x7EE3209E, 0x7EE40078, 0x7EF8409E, 
+        0x7EFE0054, 0x7EFF0078, 0x7F000083, 0x7F088006, 0x7F0B80B4, 0x7F0C8006, 0x7F0D0078, 0x7F100083, 
+        0x7F120078, 0x7F188099, 0x7F198038, 0x7F1A80B4, 0x7F220006, 0x7F2380B4, 0x7F241006, 0x7F261038, 
+        0x7F286006, 0x7F290078, 0x7F2A600C, 0x7F2B6006, 0x7F2C60B4, 0x7F2F6007, 0x7F306006, 0x7F31600D, 
+        0x7F326019, 0x7F330078, 0x7F346008, 0x7F356006, 0x7F360078, 0x7F38489E, 0x7F39009E, 0x7F3A0078, 
+        0x7F3B489E, 0x7F40409E, 0x7F45389E, 0x7F46409E, 0x7F48389E, 0x7F49409E, 0x7F4B389E, 0x7F4C409E, 
+        0x7F4D389E, 0x7F4E409E, 0x7F4F389E, 0x7F50409E, 0x7F51389E, 0x7F52409E, 0x7F53389E, 0x7F54409E, 
+        0x7F59389E, 0x7F5A409E, 0x7F5B389E, 0x7F5C409E, 0x7F5D389E, 0x7F5E409E, 0x7F5F389E, 0x7F60409E, 
+        0x7F61389E, 0x7F62409E, 0x7F63389E, 0x7F64409E, 0x7F65389E, 0x7F66409E, 0x7F67389E, 0x7F68409E, 
+        0x7F69389E, 0x7F6A409E, 0x7F6B389E, 0x7F6C409E, 0x7F6D389E, 0x7F6E409E, 0x7F6F389E, 0x7F70409E, 
+        0x7F71389E, 0x7F72409E, 0x7F73389E, 0x7F74409E, 0x7F75389E, 0x7F76409E, 0x7F79389E, 0x7F7A409E, 
+        0x7F7E0078, 0x7F7F0057, 0x7F808806, 0x7F818807, 0x7F838806, 0x7F84880A, 0x7F85880B, 0x7F86880D, 
+        0x7F87880C, 0x7F88880F, 0x7F898811, 0x7F8A8813, 0x7F8B8815, 0x7F8C8817, 0x7F8D8806, 0x7F8E8819, 
+        0x7F8F8806, 0x7F908860, 0x7F9D8835, 0x7F9E8836, 0x7F9F8838, 0x7FA08861, 0x7FAD8835, 0x7FAE8836, 
+        0x7FAF8809, 0x7FB05006, 0x7FB1500A, 0x7FB25006, 0x7FB35071, 0x7FCF5081, 0x7FD05071, 0x7FDF0078, 
+        0x7FE15071, 0x7FE40078, 0x7FE55071, 0x7FE80078, 0x7FE95071, 0x7FEC0078, 0x7FED5071, 0x7FEE0078, 
+        0x7FF08808, 0x7FF18837, 0x7FF28808, 0x7FF30078, 0x7FF45019, 0x7FF65054, 0x7FF70078, 0x7FFC0141, 
+        0x7FFE0054, 0x7FFF0078, 0x80000071, 0x80130078, 0x80140071, 0x801D0078, 0x801E0071, 0x80270078, 
+        0x80280071, 0x802F0078, 0x80400071, 0x807D0078, 0x80800006, 0x80810078, 0x808300AD, 0x808400AE, 
+        0x8085012D, 0x8086012E, 0x8087012F, 0x80880185, 0x80890186, 0x808A0187, 0x808B0188, 0x808C0184, 
+        0x808D01C9, 0x808E01CA, 0x808F01CB, 0x809001CC, 0x809101CD, 0x809201CE, 0x809301CF, 0x809401D0, 
+        0x809500BE, 0x809601D1, 0x809701D2, 0x809801D3, 0x809901D4, 0x809A0078, 0x809B0094, 0x80A0014E, 
+        0x80A10152, 0x80A20153, 0x80A30157, 0x80A40154, 0x80A50155, 0x80A60156, 0x80A70152, 0x80A80150, 
+        0x80A90153, 0x80AA01D5, 0x80AB0154, 0x80AC014F, 0x80AD0158, 0x80AF0152, 0x80B00154, 0x80B201D6, 
+        0x80B30150, 0x80B501D7, 0x80B60153, 0x80B80156, 0x80B90152, 0x80BA005F, 0x80BC0054, 0x80C50078, 
+        0x81800071, 0x818F0078, 0x8190012D, 0x819100BB, 0x81920078, 0x81980071, 0x81A50078, 0x81C00071, 
+        0x81CF0097, 0x81D00071, 0x81E20078, 0x81E40071, 0x81E8014F, 0x81E90154, 0x81EA0155, 0x81EB0078, 
+        0x8200015B, 0x8214015C, 0x82280071, 0x824F0078, 0x8250017E, 0x8251017F, 0x82520180, 0x82530181, 
+        0x82540182, 0x82550078, 0x8400009B, 0x84030078, 0x8405009B, 0x841C0078, 0x841F009B, 0x84200078, 
+        0x85000083, 0x85030078, 0x85060083, 0x8508009B, 0x851A0078, 0x851C0083, 0x851D0078, 0x851F0083, 
+        0x852001D8, 0x852101D9, 0x852201DA, 0x852301DB, 0x85240078, 0x8528009A, 0x852C0078, 0xE8000094, 
+        0xE87B0078, 0xE8800094, 0xE8930078, 0xE8950094, 0xE8AF0894, 0xE8B200A7, 0xE8B30083, 0xE8B50094, 
+        0xE8B600A7, 0xE8B90057, 0xE8BD0083, 0xE8C10094, 0xE8C20083, 0xE8C60094, 0xE8D50083, 0xE8D70094, 
+        0xE8DD0894, 0xE8E00094, 0xE8EF0078, 0xE9000054, 0xE9210083, 0xE9220054, 0xE9230078, 0xE9800054, 
+        0xE9AB0078, 0xEA002877, 0xEA0D2855, 0xEA1A2877, 0xEA272855, 0xEA2A0078, 0xEA2B2855, 0xEA342877, 
+        0xEA412855, 0xEA4E0078, 0xEA4F2877, 0xEA500078, 0xEA522877, 0xEA530078, 0xEA542877, 0xEA560078, 
+        0xEA572877, 0xEA5B2855, 0xEA682877, 0xEA752855, 0xEA822877, 0xEA850078, 0xEA862877, 0xEA8A0078, 
+        0xEA8B2877, 0xEA8E0078, 0xEA8F2855, 0xEA9C2877, 0xEA9F0078, 0xEAA02877, 0xEAA20078, 0xEAA52877, 
+        0xEAA80078, 0xEAA92855, 0xEAB62877, 0xEAC32855, 0xEAD02877, 0xEADD2855, 0xEAEA2877, 0xEAF72855, 
+        0xEB042877, 0xEB112855, 0xEB1E2877, 0xEB2B2855, 0xEB382877, 0xEB452855, 0xEB530078, 0xEB542877, 
+        0xEB6029DC, 0xEB612855, 0xEB6D29DC, 0xEB6E2855, 0xEB712877, 0xEB7D29DC, 0xEB7E2855, 0xEB8A29DC, 
+        0xEB8B2855, 0xEB8E2877, 0xEB9A29DC, 0xEB9B2855, 0xEBA729DC, 0xEBA82855, 0xEBAB2877, 0xEBB729DC, 
+        0xEBB82855, 0xEBC429DC, 0xEBC52855, 0xEBC82877, 0xEBD429DC, 0xEBD52855, 0xEBE129DC, 0xEBE22855, 
+        0xEBE50078, 0xEBE7280F, 0xEBE82811, 0xEBE92813, 0xEBEA2815, 0xEBEB2817, 0xEBEC280F, 0xEBED2811, 
+        0xEBEE2813, 0xEBEF2815, 0xEBF02817, 0xEBF1280F, 0xEBF22811, 0xEBF32813, 0xEBF42815, 0xEBF52817, 
+        0xEBF6280F, 0xEBF72811, 0xEBF82813, 0xEBF92815, 0xEBFA2817, 0xEBFB280F, 0xEBFC2811, 0xEBFD2813, 
+        0xEBFE2815, 0xEBFF2817, 0xEC000078
+    };
+
+    static const uint32_t a17[] = {
+        0x00000071, 0x536B0078, 0x7C000871, 0x7D0F0078
+    };
+
+    static const uint32_t a23[] = {
+        0x00000057, 0x00010078, 0x00100057, 0x00400078, 0x00800083, 0x00F80078, 0x8000013F, 0xFFFF0078
+    };
+
+    static const uint32_t a24[] = {
+        0x0000013F, 0x7FFF0078
+    };
+
+
+    // The full set of all arrays to be searched.
+    static const Range FULL_DATA[] = {
+        {sizeof(a0)/sizeof(uint32_t), a0},
+        {sizeof(a1)/sizeof(uint32_t), a1},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {sizeof(a7)/sizeof(uint32_t), a7},
+        {sizeof(a8)/sizeof(uint32_t), a8},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {sizeof(a16)/sizeof(uint32_t), a16},
+        {sizeof(a17)/sizeof(uint32_t), a17},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {sizeof(a23)/sizeof(uint32_t), a23},
+        {sizeof(a24)/sizeof(uint32_t), a24},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {0, 0},
+        {0, 0}
+    };
+
+    // Array of uppercase differences
+    static const short UCDIFF[] = {
+            0,   -32,   743,   121,    -1,  -232,  -300,    97, 
+          163,   130,    56,    -2,   -79,  -210,  -206,  -205, 
+         -202,  -203,  -207,  -209,  -211,  -213,  -214,  -218, 
+         -217,  -219,   -83,    84,   -38,   -37,   -31,   -64, 
+          -63,   -62,   -57,   -47,   -54,   -86,   -80,     7, 
+          -96,   -48,   -59,     8,    74,    86,   100,   128, 
+          112,   126,     9, -7205,   -16,   -26, -7264,   -40
+    };
+
+    // Array of lowercase differences
+    static const short LCDIFF[] = {
+            0,    32,     1,  -199,  -121,   210,   206,   205, 
+           79,   202,   203,   207,   211,   209,   213,   214, 
+          218,   217,   219,     2,   -97,   -56,  -130,  -163, 
+           83,    38,    37,    64,    63,   -60,    -7,    80, 
+           48,  7264,    -8,   -74,    -9,   -86,  -100,  -112, 
+         -128,  -126, -7517, -8383, -8262,    16,    26,    40
+    };
+
+    // Array of titlecase differences
+    static const short TCDIFF[] = {
+            3,     1,     0,    -1
+    };
+
+    // Array of mirrored character differences
+    static const short MIRROR_DIFF[] = {
+            0,     1,    -1,     2,    -2,    16,   -16,     3, 
+           -3,  2016,   138,  1824,  2104,  2108,  2106,  -138, 
+            8,     7,    -8,    -7, -1824, -2016, -2104, -2106, 
+        -2108
+    };
+
+   // Array of all possible numeric values
+   static const int NUMERICS[] = {
+            -1,      0,      1,      2,      3,      4,      5,      6, 
+             7,      8,      9,     10,     11,     12,     13,     14, 
+            15,     16,     17,     18,     19,     20,     21,     22, 
+            23,     24,     25,     26,     27,     28,     29,     30, 
+            31,     32,     33,     34,     35,     -2,    100,   1000, 
+            40,     50,     60,     70,     80,     90,  10000,    500, 
+          5000,     36,     37,     38,     39,     41,     42,     43, 
+            44,     45,     46,     47,     48,     49,    200,    300, 
+           400,    600,    700,    800,    900,   2000,   3000,   4000, 
+          6000,   7000,   8000,   9000,  20000,  30000,  40000,  50000, 
+         60000,  70000,  80000,  90000
+    };
+
+    // All possible packed data values, no duplicates
+    static const uint32_t PACKED_DATA[] = {
+        0x00000000, 0x0000012F, 0x0000016F, 0x0000014F, 0x0000018F, 0x0000018C, 0x000001B8, 0x000000B8, 
+        0x000000BA, 0x020005B5, 0x040005B6, 0x00000099, 0x000000F8, 0x00000094, 0x02000069, 0x04000069, 
+        0x06000069, 0x08000069, 0x0A000069, 0x0C000069, 0x0E000069, 0x10000069, 0x12000069, 0x14000069, 
+        0x060005B9, 0x000001B9, 0x080005B9, 0x16020001, 0x18020001, 0x1A020001, 0x1C020001, 0x1E020001, 
+        0x20020001, 0x22020001, 0x24020001, 0x26020001, 0x28020001, 0x2A020001, 0x2C020001, 0x2E020001, 
+        0x30020001, 0x32020001, 0x34020001, 0x36020001, 0x38020001, 0x3A020001, 0x3C020001, 0x3E020001, 
+        0x40020001, 0x42020001, 0x44020001, 0x46020001, 0x48020001, 0x060005B5, 0x080005B6, 0x000001BB, 
+        0x000001B7, 0x16000802, 0x18000802, 0x1A000802, 0x1C000802, 0x1E000802, 0x20000802, 0x22000802, 
+        0x24000802, 0x26000802, 0x28000802, 0x2A000802, 0x2C000802, 0x2E000802, 0x30000802, 0x32000802, 
+        0x34000802, 0x36000802, 0x38000802, 0x3A000802, 0x3C000802, 0x3E000802, 0x40000802, 0x42000802, 
+        0x44000802, 0x46000802, 0x48000802, 0x000000EC, 0x000001BC, 0x00000002, 0x0A0005BD, 0x00000130, 
+        0x000000BC, 0x000000B9, 0x0600006B, 0x0800006B, 0x00001002, 0x0400006B, 0x0C0005BE, 0x4A0001AB, 
+        0x00020001, 0x00000802, 0x00001802, 0x00040001, 0x00060001, 0x00002002, 0x00080001, 0x000C0001, 
+        0x000E0001, 0x00100001, 0x00140001, 0x00160001, 0x00180001, 0x00004002, 0x00004802, 0x00200001, 
+        0x00220001, 0x00000005, 0x00A60001, 0x01805802, 0x01042003, 0x00280001, 0x002C0001, 0x00000001, 
+        0x00000000, 0x00007002, 0x00007802, 0x00009802, 0x0000A802, 0x0000B802, 0x0000C002, 0x0000C802, 
+        0x0000D002, 0x00000004, 0x000001A4, 0x00000106, 0x00320001, 0x00340001, 0x00360001, 0x00380001, 
+        0x0000E002, 0x0000E802, 0x0000F002, 0x0000F802, 0x00010002, 0x00010802, 0x00012002, 0x00012802, 
+        0x00013802, 0x003A0001, 0x003E0001, 0x00013002, 0x0000001C, 0x00000107, 0x00400001, 0x00000018, 
+        0x00014802, 0x000001B4, 0x00000038, 0x00000025, 0x00000050, 0x00000058, 0x00000045, 0x00000044, 
+        0x020000C9, 0x060000C9, 0x0A0000C9, 0x0E0000C9, 0x120000C9, 0x000000D8, 0x0000005C, 0x00000008, 
+        0x02000009, 0x06000009, 0x0A000009, 0x0E000009, 0x12000009, 0x0400000B, 0x0800000B, 0x0000000B, 
+        0x1600000B, 0x4E00000B, 0x00000006, 0x4A00000B, 0x000001B5, 0x00420001, 0x0600000B, 0x0A00000B, 
+        0x0E00000B, 0x1200000B, 0x3E00000B, 0x5200000B, 0x5600000B, 0x5A00000B, 0x5C00000B, 0x000001B6, 
+        0x2400000A, 0x2800000A, 0x00000010, 0x020001AB, 0x060001AB, 0x0A0001AB, 0x0E0001AB, 0x120001AB, 
+        0x00000108, 0x00015802, 0x00440001, 0x00016002, 0x00016802, 0x00017002, 0x00017802, 0x00018002, 
+        0x00018802, 0x00440003, 0x00460001, 0x00480003, 0x00019802, 0x004A0001, 0x004C0001, 0x004E0001, 
+        0x003C0001, 0x00500001, 0x00520001, 0x000001BD, 0x0000018D, 0x000001D0, 0x00000250, 0x00000230, 
+        0x040005BE, 0x000000F9, 0x0200006B, 0x0A00006B, 0x0E00006B, 0x1200006B, 0x00540001, 0x00560001, 
+        0x000005B9, 0x045A000A, 0x085A000A, 0x0C5A000A, 0x105A000A, 0x145A000A, 0x185A000A, 0x525A000A, 
+        0x5E5A000A, 0x0401A00A, 0x0801A00A, 0x0C01A00A, 0x1001A00A, 0x1401A00A, 0x1801A00A, 0x5201A00A, 
+        0x5E01A00A, 0x4E00000A, 0x5C00000A, 0x0E0005B9, 0x100005B9, 0x020005B9, 0x040005B9, 0x160005B9, 
+        0x180005B9, 0x1A0005B9, 0x200005B9, 0x220005B9, 0x240005B9, 0x260005B9, 0x040001AB, 0x080001AB, 
+        0x0C0001AB, 0x100001AB, 0x140001AB, 0x180001AB, 0x1C0001AB, 0x200001AB, 0x240001AB, 0x280001AB, 
+        0x0C00006B, 0x1000006B, 0x1400006B, 0x1800006B, 0x1C00006B, 0x2000006B, 0x2400006B, 0x2800006B, 
+        0x005C001C, 0x0001A81C, 0x1A0001AB, 0x1E0001AB, 0x220001AB, 0x260001AB, 0x2A0001AB, 0x160001AB, 
+        0x020005B6, 0x100005B6, 0x280005B9, 0x2C0005B9, 0x300005B9, 0x0001B002, 0x020005BD, 0x0600000A, 
+        0x0A00000A, 0x0E00000A, 0x1200000A, 0x1600000A, 0x3E00000A, 0x0C00000B, 0x1000000B, 0x1400000B, 
+        0x2E0001AB, 0x320001AB, 0x360001AB, 0x3A0001AB, 0x3E0001AB, 0x420001AB, 0x460001AB, 0x640001AB, 
+        0x680001AB, 0x6A0001AB, 0x6E0001AB, 0x720001AB, 0x760001AB, 0x7A0001AB, 0x00000013, 0x00000012, 
+        0x0000005A, 0x000001B0, 0x7C00000B, 0x8000000B, 0x8200000B, 0x8600000B, 0x8C00000B, 0x6000000B, 
+        0x9200000B, 0x9600000B, 0x9800000B, 0x9C00000B, 0xA000000B, 0xA400000B, 0x4A0001AA, 0x040001AA, 
+        0x520001AA, 0x600001AA, 0x0C0001AA, 0x5E0001AA, 0x160001AA, 0x4C0001AA, 0x4E0001AA, 0x9E0001AA, 
+        0x060001AA, 0x8800000A, 0x2A0001AA, 0x005E0001, 0x0001B802, 0x0400002B, 0x0800002B, 0x1600002B, 
+        0x4C00002B, 0x00002802, 0x00003002, 0x000A0001, 0x00120001, 0x00003802, 0x001A0001, 0x001C0001, 
+        0x001E0001, 0x00240001, 0x00005002, 0x00006002, 0x002A0001, 0x002E0001, 0x00300001, 0x00006802, 
+        0x00008002, 0x00008802, 0x00009002, 0x0000A002, 0x0000B002, 0x0000D906, 0x00011002, 0x00011802, 
+        0x00014002, 0x040000C9, 0x080000C9, 0x0C0000C9, 0x100000C9, 0x140000C9, 0x04000009, 0x08000009, 
+        0x0C000009, 0x10000009, 0x14000009, 0x2200000B, 0x4C00000B, 0x2A00000B, 0x5000000B, 0x5400000B, 
+        0x5800000B, 0x2600000A, 0x00015002, 0x00019002, 0x00000030, 0x000001BE, 0x0000014E, 0x00000210, 
+        0x000001F0, 0x00580001, 0x065A000A, 0x0A5A000A, 0x0E5A000A, 0x125A000A, 0x165A000A, 0x1A5A000A, 
+        0x4C5A000A, 0x4E5A000A, 0x0601A00A, 0x0A01A00A, 0x0E01A00A, 0x1201A00A, 0x1601A00A, 0x1A01A00A, 
+        0x4C01A00A, 0x4E01A00A, 0x6000000A, 0x0000000A, 0x120005B9, 0x140005B9, 0x1C0005B9, 0x1E0005B9, 
+        0x1600006B, 0x1A00006B, 0x1E00006B, 0x2200006B, 0x2600006B, 0x2A00006B, 0x0E0005B5, 0x040005B5, 
+        0x2A0005B9, 0x2E0005B9, 0x0200000A, 0x0400000A, 0x0800000A, 0x0C00000A, 0x1000000A, 0x1400000A, 
+        0x2A00000A, 0x2C0001AB, 0x300001AB, 0x340001AB, 0x380001AB, 0x3C0001AB, 0x400001AB, 0x440001AB, 
+        0x480001AB, 0x620001AB, 0x660001AB, 0x500001AB, 0x6C0001AB, 0x700001AB, 0x740001AB, 0x780001AB, 
+        0x520001AB, 0x7E00000B, 0x5E00000B, 0x8400000B, 0x8800000B, 0x8A00000B, 0x8E00000B, 0x9000000B, 
+        0x9400000B, 0x9A00000B, 0x9E00000B, 0xA200000B, 0xA600000B, 0x5C0001AA, 0x3E0001AA, 0x7E0001AA, 
+        0x0600002B, 0x0A00002B, 0x2A00002B, 0x4E00002B, 0x00000019
+    };
+}
diff --git a/libs/utils/executablepath_darwin.cpp b/libs/utils/executablepath_darwin.cpp
new file mode 100644
index 0000000..2e3c3a0
--- /dev/null
+++ b/libs/utils/executablepath_darwin.cpp
@@ -0,0 +1,31 @@
+/*
+ * 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 <utils/executablepath.h>
+#import <Carbon/Carbon.h>
+#include <unistd.h>
+
+void executablepath(char s[PATH_MAX])
+{
+    ProcessSerialNumber psn;
+    GetCurrentProcess(&psn);
+    CFDictionaryRef dict;
+    dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
+    CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
+                CFSTR("CFBundleExecutable"));
+    CFStringGetCString(value, s, PATH_MAX+1, kCFStringEncodingUTF8);
+}
+
diff --git a/libs/utils/executablepath_linux.cpp b/libs/utils/executablepath_linux.cpp
new file mode 100644
index 0000000..b8d2a3d
--- /dev/null
+++ b/libs/utils/executablepath_linux.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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 <utils/executablepath.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdio.h>
+
+void executablepath(char exe[PATH_MAX])
+{
+    char proc[100];
+    sprintf(proc, "/proc/%d/exe", getpid());
+    
+    int err = readlink(proc, exe, PATH_MAX);
+}
+
diff --git a/libs/utils/futex_synchro.c b/libs/utils/futex_synchro.c
new file mode 100644
index 0000000..ba19520
--- /dev/null
+++ b/libs/utils/futex_synchro.c
@@ -0,0 +1,175 @@
+/*
+ * 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 <stdio.h>
+#include <limits.h>
+
+#include <sys/time.h>
+#include <sched.h>
+
+#include <errno.h>
+
+#include <private/utils/futex_synchro.h>
+
+
+// This futex glue code is need on desktop linux, but is already part of bionic.
+#if !defined(HAVE_FUTEX_WRAPPERS)
+
+#include <sys/syscall.h>
+typedef unsigned int u32;
+#define asmlinkage
+#define __user
+#include <linux/futex.h>
+#include <utils/Atomic.h>
+
+
+int futex (int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3)
+{
+    int err = syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
+    return err == 0 ? 0 : -errno;
+}
+
+int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout)
+{
+    return futex((int*)ftx, FUTEX_WAIT, val, timeout, NULL, 0);
+}
+
+int __futex_wake(volatile void *ftx, int count)
+{
+    return futex((int*)ftx, FUTEX_WAKE, count, NULL, NULL, 0);
+}
+
+int __atomic_cmpxchg(int old, int _new, volatile int *ptr)
+{
+    return android_atomic_cmpxchg(old, _new, ptr);
+}
+
+int __atomic_swap(int _new, volatile int *ptr)
+{
+    return android_atomic_swap(_new, ptr);
+}
+
+int __atomic_dec(volatile int *ptr)
+{
+    return android_atomic_dec(ptr);
+}
+
+#else // !defined(__arm__)
+
+int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout);
+int __futex_wake(volatile void *ftx, int count);
+
+int __atomic_cmpxchg(int old, int _new, volatile int *ptr);
+int __atomic_swap(int _new, volatile int *ptr);
+int __atomic_dec(volatile int *ptr);
+
+#endif // !defined(HAVE_FUTEX_WRAPPERS)
+
+
+// lock states
+//
+// 0: unlocked
+// 1: locked, no waiters
+// 2: locked, maybe waiters
+
+void futex_mutex_init(futex_mutex_t *m)
+{
+    m->value = 0;
+}
+
+int futex_mutex_lock(futex_mutex_t *m, unsigned msec)
+{
+    if(__atomic_cmpxchg(0, 1, &m->value) == 0) {
+        return 0;
+    }
+    if(msec == FUTEX_WAIT_INFINITE) {
+        while(__atomic_swap(2, &m->value) != 0) {
+            __futex_wait(&m->value, 2, 0);
+        }
+    } else {
+        struct timespec ts;
+        ts.tv_sec = msec / 1000;
+        ts.tv_nsec = (msec % 1000) * 1000000;
+        while(__atomic_swap(2, &m->value) != 0) {
+            if(__futex_wait(&m->value, 2, &ts) == -ETIMEDOUT) {
+                return -1;
+            }
+        }
+    }
+    return 0;
+}
+
+int futex_mutex_trylock(futex_mutex_t *m)
+{
+    if(__atomic_cmpxchg(0, 1, &m->value) == 0) {
+        return 0;
+    }
+    return -1;
+}
+
+void futex_mutex_unlock(futex_mutex_t *m)
+{
+    if(__atomic_dec(&m->value) != 1) {
+        m->value = 0;
+        __futex_wake(&m->value, 1);
+    }
+}
+
+/* XXX *technically* there is a race condition that could allow
+ * XXX a signal to be missed.  If thread A is preempted in _wait()
+ * XXX after unlocking the mutex and before waiting, and if other
+ * XXX threads call signal or broadcast UINT_MAX times (exactly),
+ * XXX before thread A is scheduled again and calls futex_wait(),
+ * XXX then the signal will be lost.
+ */
+
+void futex_cond_init(futex_cond_t *c)
+{
+    c->value = 0;
+}
+
+int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec)
+{
+    if(msec == FUTEX_WAIT_INFINITE){
+        int oldvalue = c->value;
+        futex_mutex_unlock(m);
+        __futex_wait(&c->value, oldvalue, 0);
+        futex_mutex_lock(m, FUTEX_WAIT_INFINITE);
+        return 0;
+    } else {
+        int oldvalue = c->value;
+        struct timespec ts;        
+        ts.tv_sec = msec / 1000;
+        ts.tv_nsec = (msec % 1000) * 1000000;
+        futex_mutex_unlock(m);
+        const int err = __futex_wait(&c->value, oldvalue, &ts);
+        futex_mutex_lock(m, FUTEX_WAIT_INFINITE);
+        return err;
+    }
+}
+
+void futex_cond_signal(futex_cond_t *c)
+{
+    __atomic_dec(&c->value);
+    __futex_wake(&c->value, 1);
+}
+
+void futex_cond_broadcast(futex_cond_t *c)
+{
+    __atomic_dec(&c->value);
+    __futex_wake(&c->value, INT_MAX);
+}
+
diff --git a/libs/utils/misc.cpp b/libs/utils/misc.cpp
new file mode 100644
index 0000000..dc89d15
--- /dev/null
+++ b/libs/utils/misc.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Miscellaneous utility functions.
+//
+#include <utils/misc.h>
+
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdio.h>
+
+using namespace android;
+
+namespace android {
+
+/*
+ * Like strdup(), but uses C++ "new" operator instead of malloc.
+ */
+char* strdupNew(const char* str)
+{
+    char* newStr;
+    int len;
+
+    if (str == NULL)
+        return NULL;
+
+    len = strlen(str);
+    newStr = new char[len+1];
+    memcpy(newStr, str, len+1);
+
+    return newStr;
+}
+
+/*
+ * Concatenate an argument vector.
+ */
+char* concatArgv(int argc, const char* const argv[])
+{
+    char* newStr = NULL;
+    int len, totalLen, posn, idx;
+
+    /*
+     * First, figure out the total length.
+     */
+    totalLen = idx = 0;
+    while (1) {
+        if (idx == argc || argv[idx] == NULL)
+            break;
+        if (idx)
+            totalLen++;  // leave a space between args
+        totalLen += strlen(argv[idx]);
+        idx++;
+    }
+
+    /*
+     * Alloc the string.
+     */
+    newStr = new char[totalLen +1];
+    if (newStr == NULL)
+        return NULL;
+
+    /*
+     * Finally, allocate the string and copy data over.
+     */
+    idx = posn = 0;
+    while (1) {
+        if (idx == argc || argv[idx] == NULL)
+            break;
+        if (idx)
+            newStr[posn++] = ' ';
+
+        len = strlen(argv[idx]);
+        memcpy(&newStr[posn], argv[idx], len);
+        posn += len;
+
+        idx++;
+    }
+
+    assert(posn == totalLen);
+    newStr[posn] = '\0';
+
+    return newStr;
+}
+
+/*
+ * Count the #of args in an argument vector.  Don't count the final NULL.
+ */
+int countArgv(const char* const argv[])
+{
+    int count = 0;
+
+    while (argv[count] != NULL)
+        count++;
+
+    return count;
+}
+
+
+#include <stdio.h>
+/*
+ * Get a file's type.
+ */
+FileType getFileType(const char* fileName)
+{
+    struct stat sb;
+
+    if (stat(fileName, &sb) < 0) {
+        if (errno == ENOENT || errno == ENOTDIR)
+            return kFileTypeNonexistent;
+        else {
+            fprintf(stderr, "getFileType got errno=%d on '%s'\n",
+                errno, fileName);
+            return kFileTypeUnknown;
+        }
+    } else {
+        if (S_ISREG(sb.st_mode))
+            return kFileTypeRegular;
+        else if (S_ISDIR(sb.st_mode))
+            return kFileTypeDirectory;
+        else if (S_ISCHR(sb.st_mode))
+            return kFileTypeCharDev;
+        else if (S_ISBLK(sb.st_mode))
+            return kFileTypeBlockDev;
+        else if (S_ISFIFO(sb.st_mode))
+            return kFileTypeFifo;
+#ifdef HAVE_SYMLINKS            
+        else if (S_ISLNK(sb.st_mode))
+            return kFileTypeSymlink;
+        else if (S_ISSOCK(sb.st_mode))
+            return kFileTypeSocket;
+#endif            
+        else
+            return kFileTypeUnknown;
+    }
+}
+
+/*
+ * Get a file's modification date.
+ */
+time_t getFileModDate(const char* fileName)
+{
+    struct stat sb;
+
+    if (stat(fileName, &sb) < 0)
+        return (time_t) -1;
+
+    return sb.st_mtime;
+}
+
+/*
+ * Round up to the next highest power of 2.
+ *
+ * Found on http://graphics.stanford.edu/~seander/bithacks.html.
+ */
+unsigned int roundUpPower2(unsigned int val)
+{
+    val--;
+    val |= val >> 1;
+    val |= val >> 2;
+    val |= val >> 4;
+    val |= val >> 8;
+    val |= val >> 16;
+    val++;
+
+    return val;
+}
+
+}; // namespace android
+
diff --git a/libs/utils/ported.cpp b/libs/utils/ported.cpp
new file mode 100644
index 0000000..656e46f
--- /dev/null
+++ b/libs/utils/ported.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Ports of standard functions that don't exist on a specific platform.
+//
+// Note these are NOT in the "android" namespace.
+//
+#include <utils/ported.h>
+
+#if defined(NEED_GETTIMEOFDAY) || defined(NEED_USLEEP)
+# include <sys/time.h>
+# include <windows.h>
+#endif
+
+
+#if defined(NEED_GETTIMEOFDAY)
+/*
+ * Replacement gettimeofday() for Windows environments (primarily MinGW).
+ *
+ * Ignores "tz".
+ */
+int gettimeofday(struct timeval* ptv, struct timezone* tz)
+{
+    long long nsTime;   // time in 100ns units since Jan 1 1601
+    FILETIME ft;
+
+    if (tz != NULL) {
+        // oh well
+    }
+
+    ::GetSystemTimeAsFileTime(&ft);
+    nsTime = (long long) ft.dwHighDateTime << 32 |
+             (long long) ft.dwLowDateTime;
+    // convert to time in usec since Jan 1 1970
+    ptv->tv_usec = (long) ((nsTime / 10LL) % 1000000LL);
+    ptv->tv_sec = (long) ((nsTime - 116444736000000000LL) / 10000000LL);
+
+    return 0;
+}
+#endif
+
+#if defined(NEED_USLEEP)
+//
+// Replacement usleep for Windows environments (primarily MinGW).
+//
+void usleep(unsigned long usec)
+{
+    // Win32 API function Sleep() takes milliseconds
+    ::Sleep((usec + 500) / 1000);
+}
+#endif
+
+#if 0 //defined(NEED_PIPE)
+//
+// Replacement pipe() command for MinGW
+//
+// The _O_NOINHERIT flag sets bInheritHandle to FALSE in the
+// SecurityAttributes argument to CreatePipe().  This means the handles
+// aren't inherited when a new process is created.  The examples I've seen
+// use it, possibly because there's a lot of junk going on behind the
+// scenes.  (I'm assuming "process" and "thread" are different here, so
+// we should be okay spinning up a thread.)  The recommended practice is
+// to dup() the descriptor you want the child to have.
+//
+// It appears that unnamed pipes can't do non-blocking ("overlapped") I/O.
+// You can't use select() either, since that only works on sockets.  The
+// Windows API calls that are useful here all operate on a HANDLE, not
+// an integer file descriptor, and I don't think you can get there from
+// here.  The "named pipe" stuff is insane.
+//
+int pipe(int filedes[2])
+{
+    return _pipe(filedes, 0, _O_BINARY | _O_NOINHERIT);
+}
+#endif
+
+#if defined(NEED_SETENV)
+/*
+ * MinGW lacks these.  For now, just stub them out so the code compiles.
+ */
+int setenv(const char* name, const char* value, int overwrite)
+{
+    return 0;
+}
+void unsetenv(const char* name)
+{
+}
+char* getenv(const char* name)
+{
+    return NULL;
+}
+#endif
diff --git a/opengl/include/EGL/egl.h b/opengl/include/EGL/egl.h
new file mode 100644
index 0000000..c269976
--- /dev/null
+++ b/opengl/include/EGL/egl.h
@@ -0,0 +1,330 @@
+/* -*- mode: c; tab-width: 8; -*- */
+/* vi: set sw=4 ts=8: */
+/* Reference version of egl.h for EGL 1.4.
+ * $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $
+ */
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#ifndef __egl_h_
+#define __egl_h_
+
+/* All platform-dependent types and macro boilerplate (such as EGLAPI
+ * and EGLAPIENTRY) should go in eglplatform.h.
+ */
+#include <EGL/eglplatform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* EGL Types */
+/* EGLint is defined in eglplatform.h */
+typedef unsigned int EGLBoolean;
+typedef unsigned int EGLenum;
+typedef void *EGLConfig;
+typedef void *EGLContext;
+typedef void *EGLDisplay;
+typedef void *EGLSurface;
+typedef void *EGLClientBuffer;
+
+/* EGL Versioning */
+#define EGL_VERSION_1_0			1
+#define EGL_VERSION_1_1			1
+#define EGL_VERSION_1_2			1
+#define EGL_VERSION_1_3			1
+#define EGL_VERSION_1_4			1
+
+/* EGL Enumerants. Bitmasks and other exceptional cases aside, most
+ * enums are assigned unique values starting at 0x3000.
+ */
+
+/* EGL aliases */
+#define EGL_FALSE			0
+#define EGL_TRUE			1
+
+/* Out-of-band handle values */
+#define EGL_DEFAULT_DISPLAY		((EGLNativeDisplayType)0)
+#define EGL_NO_CONTEXT			((EGLContext)0)
+#define EGL_NO_DISPLAY			((EGLDisplay)0)
+#define EGL_NO_SURFACE			((EGLSurface)0)
+
+/* Out-of-band attribute value */
+#define EGL_DONT_CARE			((EGLint)-1)
+
+/* Errors / GetError return values */
+#define EGL_SUCCESS			0x3000
+#define EGL_NOT_INITIALIZED		0x3001
+#define EGL_BAD_ACCESS			0x3002
+#define EGL_BAD_ALLOC			0x3003
+#define EGL_BAD_ATTRIBUTE		0x3004
+#define EGL_BAD_CONFIG			0x3005
+#define EGL_BAD_CONTEXT			0x3006
+#define EGL_BAD_CURRENT_SURFACE		0x3007
+#define EGL_BAD_DISPLAY			0x3008
+#define EGL_BAD_MATCH			0x3009
+#define EGL_BAD_NATIVE_PIXMAP		0x300A
+#define EGL_BAD_NATIVE_WINDOW		0x300B
+#define EGL_BAD_PARAMETER		0x300C
+#define EGL_BAD_SURFACE			0x300D
+#define EGL_CONTEXT_LOST		0x300E	/* EGL 1.1 - IMG_power_management */
+
+/* Reserved 0x300F-0x301F for additional errors */
+
+/* Config attributes */
+#define EGL_BUFFER_SIZE			0x3020
+#define EGL_ALPHA_SIZE			0x3021
+#define EGL_BLUE_SIZE			0x3022
+#define EGL_GREEN_SIZE			0x3023
+#define EGL_RED_SIZE			0x3024
+#define EGL_DEPTH_SIZE			0x3025
+#define EGL_STENCIL_SIZE		0x3026
+#define EGL_CONFIG_CAVEAT		0x3027
+#define EGL_CONFIG_ID			0x3028
+#define EGL_LEVEL			0x3029
+#define EGL_MAX_PBUFFER_HEIGHT		0x302A
+#define EGL_MAX_PBUFFER_PIXELS		0x302B
+#define EGL_MAX_PBUFFER_WIDTH		0x302C
+#define EGL_NATIVE_RENDERABLE		0x302D
+#define EGL_NATIVE_VISUAL_ID		0x302E
+#define EGL_NATIVE_VISUAL_TYPE		0x302F
+#define EGL_PRESERVED_RESOURCES		0x3030
+#define EGL_SAMPLES			0x3031
+#define EGL_SAMPLE_BUFFERS		0x3032
+#define EGL_SURFACE_TYPE		0x3033
+#define EGL_TRANSPARENT_TYPE		0x3034
+#define EGL_TRANSPARENT_BLUE_VALUE	0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE	0x3036
+#define EGL_TRANSPARENT_RED_VALUE	0x3037
+#define EGL_NONE			0x3038	/* Attrib list terminator */
+#define EGL_BIND_TO_TEXTURE_RGB		0x3039
+#define EGL_BIND_TO_TEXTURE_RGBA	0x303A
+#define EGL_MIN_SWAP_INTERVAL		0x303B
+#define EGL_MAX_SWAP_INTERVAL		0x303C
+#define EGL_LUMINANCE_SIZE		0x303D
+#define EGL_ALPHA_MASK_SIZE		0x303E
+#define EGL_COLOR_BUFFER_TYPE		0x303F
+#define EGL_RENDERABLE_TYPE		0x3040
+#define EGL_MATCH_NATIVE_PIXMAP		0x3041	/* Pseudo-attribute (not queryable) */
+#define EGL_CONFORMANT			0x3042
+
+/* Reserved 0x3041-0x304F for additional config attributes */
+
+/* Config attribute values */
+#define EGL_SLOW_CONFIG			0x3050	/* EGL_CONFIG_CAVEAT value */
+#define EGL_NON_CONFORMANT_CONFIG	0x3051	/* EGL_CONFIG_CAVEAT value */
+#define EGL_TRANSPARENT_RGB		0x3052	/* EGL_TRANSPARENT_TYPE value */
+#define EGL_RGB_BUFFER			0x308E	/* EGL_COLOR_BUFFER_TYPE value */
+#define EGL_LUMINANCE_BUFFER		0x308F	/* EGL_COLOR_BUFFER_TYPE value */
+
+/* More config attribute values, for EGL_TEXTURE_FORMAT */
+#define EGL_NO_TEXTURE			0x305C
+#define EGL_TEXTURE_RGB			0x305D
+#define EGL_TEXTURE_RGBA		0x305E
+#define EGL_TEXTURE_2D			0x305F
+
+/* Config attribute mask bits */
+#define EGL_PBUFFER_BIT			0x0001	/* EGL_SURFACE_TYPE mask bits */
+#define EGL_PIXMAP_BIT			0x0002	/* EGL_SURFACE_TYPE mask bits */
+#define EGL_WINDOW_BIT			0x0004	/* EGL_SURFACE_TYPE mask bits */
+#define EGL_VG_COLORSPACE_LINEAR_BIT	0x0020	/* EGL_SURFACE_TYPE mask bits */
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT	0x0040	/* EGL_SURFACE_TYPE mask bits */
+#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200	/* EGL_SURFACE_TYPE mask bits */
+#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400	/* EGL_SURFACE_TYPE mask bits */
+
+#define EGL_OPENGL_ES_BIT		0x0001	/* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENVG_BIT			0x0002	/* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENGL_ES2_BIT		0x0004	/* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENGL_BIT			0x0008	/* EGL_RENDERABLE_TYPE mask bits */
+
+/* QueryString targets */
+#define EGL_VENDOR			0x3053
+#define EGL_VERSION			0x3054
+#define EGL_EXTENSIONS			0x3055
+#define EGL_CLIENT_APIS			0x308D
+
+/* QuerySurface / SurfaceAttrib / CreatePbufferSurface targets */
+#define EGL_HEIGHT			0x3056
+#define EGL_WIDTH			0x3057
+#define EGL_LARGEST_PBUFFER		0x3058
+#define EGL_TEXTURE_FORMAT		0x3080
+#define EGL_TEXTURE_TARGET		0x3081
+#define EGL_MIPMAP_TEXTURE		0x3082
+#define EGL_MIPMAP_LEVEL		0x3083
+#define EGL_RENDER_BUFFER		0x3086
+#define EGL_VG_COLORSPACE		0x3087
+#define EGL_VG_ALPHA_FORMAT		0x3088
+#define EGL_HORIZONTAL_RESOLUTION	0x3090
+#define EGL_VERTICAL_RESOLUTION		0x3091
+#define EGL_PIXEL_ASPECT_RATIO		0x3092
+#define EGL_SWAP_BEHAVIOR		0x3093
+#define EGL_MULTISAMPLE_RESOLVE		0x3099
+
+/* EGL_RENDER_BUFFER values / BindTexImage / ReleaseTexImage buffer targets */
+#define EGL_BACK_BUFFER			0x3084
+#define EGL_SINGLE_BUFFER		0x3085
+
+/* OpenVG color spaces */
+#define EGL_VG_COLORSPACE_sRGB		0x3089	/* EGL_VG_COLORSPACE value */
+#define EGL_VG_COLORSPACE_LINEAR	0x308A	/* EGL_VG_COLORSPACE value */
+
+/* OpenVG alpha formats */
+#define EGL_VG_ALPHA_FORMAT_NONPRE	0x308B	/* EGL_ALPHA_FORMAT value */
+#define EGL_VG_ALPHA_FORMAT_PRE		0x308C	/* EGL_ALPHA_FORMAT value */
+
+/* Constant scale factor by which fractional display resolutions &
+ * aspect ratio are scaled when queried as integer values.
+ */
+#define EGL_DISPLAY_SCALING		10000
+
+/* Unknown display resolution/aspect ratio */
+#define EGL_UNKNOWN			((EGLint)-1)
+
+/* Back buffer swap behaviors */
+#define EGL_BUFFER_PRESERVED		0x3094	/* EGL_SWAP_BEHAVIOR value */
+#define EGL_BUFFER_DESTROYED		0x3095	/* EGL_SWAP_BEHAVIOR value */
+
+/* CreatePbufferFromClientBuffer buffer types */
+#define EGL_OPENVG_IMAGE		0x3096
+
+/* QueryContext targets */
+#define EGL_CONTEXT_CLIENT_TYPE		0x3097
+
+/* CreateContext attributes */
+#define EGL_CONTEXT_CLIENT_VERSION	0x3098
+
+/* Multisample resolution behaviors */
+#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A	/* EGL_MULTISAMPLE_RESOLVE value */
+#define EGL_MULTISAMPLE_RESOLVE_BOX	0x309B	/* EGL_MULTISAMPLE_RESOLVE value */
+
+/* BindAPI/QueryAPI targets */
+#define EGL_OPENGL_ES_API		0x30A0
+#define EGL_OPENVG_API			0x30A1
+#define EGL_OPENGL_API			0x30A2
+
+/* GetCurrentSurface targets */
+#define EGL_DRAW			0x3059
+#define EGL_READ			0x305A
+
+/* WaitNative engines */
+#define EGL_CORE_NATIVE_ENGINE		0x305B
+
+/* EGL 1.2 tokens renamed for consistency in EGL 1.3 */
+#define EGL_COLORSPACE			EGL_VG_COLORSPACE
+#define EGL_ALPHA_FORMAT		EGL_VG_ALPHA_FORMAT
+#define EGL_COLORSPACE_sRGB		EGL_VG_COLORSPACE_sRGB
+#define EGL_COLORSPACE_LINEAR		EGL_VG_COLORSPACE_LINEAR
+#define EGL_ALPHA_FORMAT_NONPRE		EGL_VG_ALPHA_FORMAT_NONPRE
+#define EGL_ALPHA_FORMAT_PRE		EGL_VG_ALPHA_FORMAT_PRE
+
+/* EGL extensions must request enum blocks from the Khronos
+ * API Registrar, who maintains the enumerant registry. Submit
+ * a bug in Khronos Bugzilla against task "Registry".
+ */
+
+
+
+/* EGL Functions */
+
+EGLAPI EGLint EGLAPIENTRY eglGetError(void);
+
+EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy);
+
+EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs,
+			 EGLint config_size, EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
+			   EGLConfig *configs, EGLint config_size,
+			   EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+			      EGLint attribute, EGLint *value);
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
+				  EGLNativeWindowType win,
+				  const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
+				   const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
+				  EGLNativePixmapType pixmap,
+				  const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
+			   EGLint attribute, EGLint *value);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api);
+EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void);
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(
+	      EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+	      EGLConfig config, const EGLint *attrib_list);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
+			    EGLint attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval);
+
+
+EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config,
+			    EGLContext share_context,
+			    const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
+			  EGLSurface read, EGLContext ctx);
+
+EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void);
+EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx,
+			   EGLint attribute, EGLint *value);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface,
+			  EGLNativePixmapType target);
+
+/* This is a generic function pointer type, whose name indicates it must
+ * be cast to the proper type *and calling convention* before use.
+ */
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+
+/* Now, define eglGetProcAddress using the generic function ptr. type */
+EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY
+       eglGetProcAddress(const char *procname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __egl_h_ */
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
new file mode 100644
index 0000000..25cfcb8
--- /dev/null
+++ b/opengl/include/EGL/eglext.h
@@ -0,0 +1,138 @@
+#ifndef __eglext_h_
+#define __eglext_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#include <EGL/eglplatform.h>
+
+/*************************************************************/
+
+/* Header file version number */
+/* Current version at http://www.khronos.org/registry/egl/ */
+/* $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $ */
+#define EGL_EGLEXT_VERSION 3
+
+#ifndef EGL_KHR_config_attribs
+#define EGL_KHR_config_attribs 1
+#define EGL_CONFORMANT_KHR			0x3042	/* EGLConfig attribute */
+#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR	0x0020	/* EGL_SURFACE_TYPE bitfield */
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR		0x0040	/* EGL_SURFACE_TYPE bitfield */
+#endif
+
+#ifndef EGL_KHR_lock_surface
+#define EGL_KHR_lock_surface 1
+#define EGL_READ_SURFACE_BIT_KHR		0x0001	/* EGL_LOCK_USAGE_HINT_KHR bitfield */
+#define EGL_WRITE_SURFACE_BIT_KHR		0x0002	/* EGL_LOCK_USAGE_HINT_KHR bitfield */
+#define EGL_LOCK_SURFACE_BIT_KHR		0x0080	/* EGL_SURFACE_TYPE bitfield */
+#define EGL_OPTIMAL_FORMAT_BIT_KHR		0x0100	/* EGL_SURFACE_TYPE bitfield */
+#define EGL_MATCH_FORMAT_KHR			0x3043	/* EGLConfig attribute */
+#define EGL_FORMAT_RGB_565_EXACT_KHR		0x30C0	/* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGB_565_KHR			0x30C1	/* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGBA_8888_EXACT_KHR		0x30C2	/* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGBA_8888_KHR		0x30C3	/* EGL_MATCH_FORMAT_KHR value */
+#define EGL_MAP_PRESERVE_PIXELS_KHR		0x30C4	/* eglLockSurfaceKHR attribute */
+#define EGL_LOCK_USAGE_HINT_KHR			0x30C5	/* eglLockSurfaceKHR attribute */
+#define EGL_BITMAP_POINTER_KHR			0x30C6	/* eglQuerySurface attribute */
+#define EGL_BITMAP_PITCH_KHR			0x30C7	/* eglQuerySurface attribute */
+#define EGL_BITMAP_ORIGIN_KHR			0x30C8	/* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR		0x30C9	/* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR	0x30CA	/* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR	0x30CB	/* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR	0x30CC	/* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR	0x30CD	/* eglQuerySurface attribute */
+#define EGL_LOWER_LEFT_KHR			0x30CE	/* EGL_BITMAP_ORIGIN_KHR value */
+#define EGL_UPPER_LEFT_KHR			0x30CF	/* EGL_BITMAP_ORIGIN_KHR value */
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay display, EGLSurface surface);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface);
+#endif
+
+#ifndef EGL_KHR_image
+#define EGL_KHR_image 1
+#define EGL_NATIVE_PIXMAP_KHR			0x30B0	/* eglCreateImageKHR target */
+typedef void *EGLImageKHR;
+#define EGL_NO_IMAGE_KHR			((EGLImageKHR)0)
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
+#endif
+
+#ifndef EGL_KHR_vg_parent_image
+#define EGL_KHR_vg_parent_image 1
+#define EGL_VG_PARENT_IMAGE_KHR			0x30BA	/* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_gl_texture_2D_image
+#define EGL_KHR_gl_texture_2D_image 1
+#define EGL_GL_TEXTURE_2D_KHR			0x30B1	/* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_LEVEL_KHR		0x30BC	/* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_gl_texture_cubemap_image
+#define EGL_KHR_gl_texture_cubemap_image 1
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR	0x30B3	/* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR	0x30B4	/* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR	0x30B5	/* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR	0x30B6	/* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR	0x30B7	/* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR	0x30B8	/* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_gl_texture_3D_image
+#define EGL_KHR_gl_texture_3D_image 1
+#define EGL_GL_TEXTURE_3D_KHR			0x30B2	/* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_ZOFFSET_KHR		0x30BD	/* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_gl_renderbuffer_image
+#define EGL_KHR_gl_renderbuffer_image 1
+#define EGL_GL_RENDERBUFFER_KHR			0x30B9	/* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_image_base
+#define EGL_KHR_image_base 1
+/* Most interfaces defined by EGL_KHR_image_pixmap above */
+#define EGL_IMAGE_PRESERVED_KHR			0x30D2	/* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_image_pixmap
+#define EGL_KHR_image_pixmap 1
+/* Interfaces defined by EGL_KHR_image above */
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/opengl/include/EGL/eglnatives.h b/opengl/include/EGL/eglnatives.h
new file mode 100644
index 0000000..21622dc
--- /dev/null
+++ b/opengl/include/EGL/eglnatives.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_EGLNATIVES_H
+#define ANDROID_EGLNATIVES_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+/* flags returned from swapBuffer */
+#define EGL_NATIVES_FLAG_SIZE_CHANGED       0x00000001
+
+/* surface flags */
+#define EGL_NATIVES_FLAG_DESTROY_BACKBUFFER 0x00000001
+
+enum native_pixel_format_t
+{
+    NATIVE_PIXEL_FORMAT_RGBA_8888   = 1,
+    NATIVE_PIXEL_FORMAT_RGB_565     = 4,
+    NATIVE_PIXEL_FORMAT_BGRA_8888   = 5,
+    NATIVE_PIXEL_FORMAT_RGBA_5551   = 6,
+    NATIVE_PIXEL_FORMAT_RGBA_4444   = 7,
+    NATIVE_PIXEL_FORMAT_YCbCr_422_SP= 0x10,
+    NATIVE_PIXEL_FORMAT_YCbCr_420_SP= 0x11,
+};
+
+enum native_memory_type_t
+{
+    NATIVE_MEMORY_TYPE_PMEM         = 0,
+    NATIVE_MEMORY_TYPE_GPU          = 1,
+    NATIVE_MEMORY_TYPE_FB           = 2,
+    NATIVE_MEMORY_TYPE_HEAP         = 128
+};
+
+
+struct egl_native_window_t
+{
+    /*
+     * magic must be set to 0x600913
+     */
+    uint32_t    magic;
+    
+    /*
+     * must be sizeof(egl_native_window_t)
+     */
+    uint32_t    version;
+
+    /*
+     * ident is reserved for the Android platform
+     */
+    uint32_t    ident;
+    
+    /*
+     * width, height and stride of the window in pixels
+     * Any of these value can be nul in which case GL commands are
+     * accepted and processed as usual, but not rendering occurs.
+     */
+    int         width;      // w=h=0 is legal
+    int         height;
+    int         stride;
+
+    /*
+     * format of the native window (see ui/PixelFormat.h)
+     */
+    int         format;
+    
+    /*
+     * Offset of the bits in the VRAM
+     */
+    intptr_t    offset;
+    
+    /*
+     * flags describing some attributes of this surface
+     * EGL_NATIVES_FLAG_DESTROY_BACKBUFFER: backbuffer not preserved after 
+     * eglSwapBuffers
+     */
+    uint32_t    flags;
+    
+    /*
+     * horizontal and vertical resolution in DPI
+     */
+    float       xdpi;
+    float       ydpi;
+    
+    /*
+     * refresh rate in frames per second (Hz)
+     */
+    float       fps;
+    
+    
+    /*
+     *  Base memory virtual address of the surface in the CPU side
+     */
+    intptr_t    base;
+    
+    /*
+     *  Heap the offset above is based from
+     */
+    int         fd;
+    
+    /*
+     *  Memory type the surface resides into
+     */
+    uint8_t     memory_type;
+    
+    /*
+     * Reserved for future use. MUST BE ZERO.
+     */
+    uint8_t     reserved_pad[3];
+    int         reserved[8];
+    
+    /*
+     * Vertical stride (only relevant with planar formats) 
+     */
+    
+    int         vstride;
+
+    /*
+     * Hook called by EGL to hold a reference on this structure
+     */
+    void        (*incRef)(struct egl_native_window_t* window);
+
+    /*
+     * Hook called by EGL to release a reference on this structure
+     */
+    void        (*decRef)(struct egl_native_window_t* window);
+
+    /*
+     * Hook called by EGL to perform a page flip. This function
+     * may update the size attributes above, in which case it returns
+     * the EGL_NATIVES_FLAG_SIZE_CHANGED bit set.
+     */
+    uint32_t    (*swapBuffers)(struct egl_native_window_t* window);
+    
+    /*
+     * Reserved for future use. MUST BE ZERO.
+     */
+    void        (*reserved_proc_0)(void);
+
+    /*
+     * Reserved for future use. MUST BE ZERO.
+     */
+    void        (*reserved_proc_1)(void);
+    
+    /*
+     * Reserved for future use. MUST BE ZERO.
+     */
+    void        (*reserved_proc_2)(void);
+
+    
+    /*
+     * Hook called by EGL when the native surface is associated to EGL
+     * (eglCreateWindowSurface). Can be NULL.
+     */
+    void        (*connect)(struct egl_native_window_t* window);
+
+    /*
+     * Hook called by EGL when eglDestroySurface is called.  Can be NULL.
+     */
+    void        (*disconnect)(struct egl_native_window_t* window);
+    
+    /*
+     * Reserved for future use. MUST BE ZERO.
+     */
+    void        (*reserved_proc[11])(void);
+    
+    /*
+     *  Some storage reserved for the oem driver.
+     */
+    intptr_t    oem[4];
+};
+
+
+struct egl_native_pixmap_t
+{
+    int32_t     version;    /* must be 32 */
+    int32_t     width;
+    int32_t     height;
+    int32_t     stride;
+    uint8_t*    data;
+    uint8_t     format;
+    uint8_t     rfu[3];
+    union {
+        uint32_t    compressedFormat;
+        int32_t     vstride;
+    };
+    int32_t     reserved;
+};
+
+/*****************************************************************************/
+
+/* 
+ * This a convenience function to create a NativeWindowType surface
+ * that maps to the whole screen
+ * This function is actually implemented in libui.so
+ */
+
+struct egl_native_window_t* android_createDisplaySurface();
+
+/*****************************************************************************/
+
+
+/*
+ * OEM's egl's library (libhgl.so) must imlement these hooks to allocate
+ * the GPU memory they need  
+ */
+
+
+typedef struct
+{
+    // for internal use
+    void*   user;
+    // virtual address of this area
+    void*   base;
+    // size of this area in bytes
+    size_t  size;
+    // physical address of this area
+    void*   phys;
+    // offset in this area available to the GPU
+    size_t  offset;
+    // fd of this area
+    int     fd;
+} gpu_area_t;
+
+typedef struct
+{
+    // area where GPU registers are mapped
+    gpu_area_t regs;
+    // number of extra areas (currently limited to 2)
+    int32_t count;
+    // extra GPU areas (currently limited to 2)
+    gpu_area_t gpu[2];
+} request_gpu_t;
+
+
+typedef request_gpu_t* (*OEM_EGL_acquire_gpu_t)(void* user);
+typedef int (*OEM_EGL_release_gpu_t)(void* user, request_gpu_t* handle);
+typedef void (*register_gpu_t)
+        (void* user, OEM_EGL_acquire_gpu_t, OEM_EGL_release_gpu_t);
+
+void oem_register_gpu(
+        void* user,
+        OEM_EGL_acquire_gpu_t acquire,
+        OEM_EGL_release_gpu_t release);
+
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ANDROID_EGLNATIVES_H */
diff --git a/opengl/include/EGL/eglplatform.h b/opengl/include/EGL/eglplatform.h
new file mode 100644
index 0000000..ac00901
--- /dev/null
+++ b/opengl/include/EGL/eglplatform.h
@@ -0,0 +1,117 @@
+#ifndef __eglplatform_h_
+#define __eglplatform_h_
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Platform-specific types and definitions for egl.h
+ * $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file.  Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "EGL" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+/* Macros used in EGL function prototype declarations.
+ *
+ * EGL functions should be prototyped as:
+ *
+ * EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
+ * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
+ *
+ * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
+ */
+
+#ifndef EGLAPI
+#define EGLAPI KHRONOS_APICALL
+#endif
+
+#define EGLAPIENTRY  KHRONOS_APIENTRY
+#define EGLAPIENTRYP KHRONOS_APIENTRY*
+
+/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
+ * are aliases of window-system-dependent types, such as X Display * or
+ * Windows Device Context. They must be defined in platform-specific
+ * code below. The EGL-prefixed versions of Native*Type are the same
+ * types, renamed in EGL 1.3 so all types in the API start with "EGL".
+ */
+
+#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+
+typedef HDC     EGLNativeDisplayType;
+typedef HBITMAP EGLNativePixmapType;
+typedef HWND    EGLNativeWindowType;
+
+#elif defined(__WINSCW__) || defined(__SYMBIAN32__)  /* Symbian */
+
+typedef int   EGLNativeDisplayType;
+typedef void *EGLNativeWindowType;
+typedef void *EGLNativePixmapType;
+
+#elif defined(__unix__) && !defined(ANDROID)
+
+/* X11 (tentative)  */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef Display *EGLNativeDisplayType;
+typedef Pixmap   EGLNativePixmapType;
+typedef Window   EGLNativeWindowType;
+
+
+#elif defined(ANDROID)
+
+#include <EGL/eglnatives.h>
+
+typedef struct egl_native_window_t*     EGLNativeWindowType;
+typedef struct egl_native_pixmap_t*     EGLNativePixmapType;
+typedef void*                           EGLNativeDisplayType;
+
+#else
+#error "Platform not recognized"
+#endif
+
+/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
+typedef EGLNativeDisplayType NativeDisplayType;
+typedef EGLNativePixmapType  NativePixmapType;
+typedef EGLNativeWindowType  NativeWindowType;
+
+
+/* Define EGLint. This must be a signed integral type large enough to contain
+ * all legal attribute names and values passed into and out of EGL, whether
+ * their type is boolean, bitmask, enumerant (symbolic constant), integer,
+ * handle, or other.  While in general a 32-bit integer will suffice, if
+ * handles are 64 bit types, then EGLint should be defined as a signed 64-bit
+ * integer type.
+ */
+typedef khronos_int32_t EGLint;
+
+#endif /* __eglplatform_h */
diff --git a/opengl/include/GLES/egl.h b/opengl/include/GLES/egl.h
new file mode 100644
index 0000000..5778e00
--- /dev/null
+++ b/opengl/include/GLES/egl.h
@@ -0,0 +1,15 @@
+/*
+ * Skeleton egl.h to provide compatibility for early GLES 1.0
+ * applications. Several early implementations included gl.h
+ * in egl.h leading applications to include only egl.h
+ *
+ * $Revision: 6252 $ on $Date:: 2008-08-06 16:35:08 -0700 #$
+ */
+
+#ifndef __legacy_egl_h_
+#define __legacy_egl_h_
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+
+#endif /* __legacy_egl_h_ */
diff --git a/opengl/include/GLES/gl.h b/opengl/include/GLES/gl.h
new file mode 100644
index 0000000..2e8b971
--- /dev/null
+++ b/opengl/include/GLES/gl.h
@@ -0,0 +1,769 @@
+#ifndef __gl_h_
+#define __gl_h_
+
+/* $Revision: 7172 $ on $Date:: 2009-01-09 11:17:41 -0800 #$ */
+
+#include <GLES/glplatform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+typedef void             GLvoid;
+typedef unsigned int     GLenum;
+typedef unsigned char    GLboolean;
+typedef unsigned int     GLbitfield;
+typedef khronos_int8_t   GLbyte;
+typedef short            GLshort;
+typedef int              GLint;
+typedef int              GLsizei;
+typedef khronos_uint8_t  GLubyte;
+typedef unsigned short   GLushort;
+typedef unsigned int     GLuint;
+typedef khronos_float_t  GLfloat;
+typedef khronos_float_t  GLclampf;
+typedef khronos_int32_t  GLfixed;
+typedef khronos_int32_t  GLclampx;
+
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t  GLsizeiptr;
+
+
+/*************************************************************/
+
+/* OpenGL ES core versions */
+#define GL_VERSION_ES_CM_1_0          1
+#define GL_VERSION_ES_CL_1_0          1
+#define GL_VERSION_ES_CM_1_1          1
+#define GL_VERSION_ES_CL_1_1          1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT               0x00000100
+#define GL_STENCIL_BUFFER_BIT             0x00000400
+#define GL_COLOR_BUFFER_BIT               0x00004000
+
+/* Boolean */
+#define GL_FALSE                          0
+#define GL_TRUE                           1
+
+/* BeginMode */
+#define GL_POINTS                         0x0000
+#define GL_LINES                          0x0001
+#define GL_LINE_LOOP                      0x0002
+#define GL_LINE_STRIP                     0x0003
+#define GL_TRIANGLES                      0x0004
+#define GL_TRIANGLE_STRIP                 0x0005
+#define GL_TRIANGLE_FAN                   0x0006
+
+/* AlphaFunction */
+#define GL_NEVER                          0x0200
+#define GL_LESS                           0x0201
+#define GL_EQUAL                          0x0202
+#define GL_LEQUAL                         0x0203
+#define GL_GREATER                        0x0204
+#define GL_NOTEQUAL                       0x0205
+#define GL_GEQUAL                         0x0206
+#define GL_ALWAYS                         0x0207
+
+/* BlendingFactorDest */
+#define GL_ZERO                           0
+#define GL_ONE                            1
+#define GL_SRC_COLOR                      0x0300
+#define GL_ONE_MINUS_SRC_COLOR            0x0301
+#define GL_SRC_ALPHA                      0x0302
+#define GL_ONE_MINUS_SRC_ALPHA            0x0303
+#define GL_DST_ALPHA                      0x0304
+#define GL_ONE_MINUS_DST_ALPHA            0x0305
+
+/* BlendingFactorSrc */
+/*      GL_ZERO */
+/*      GL_ONE */
+#define GL_DST_COLOR                      0x0306
+#define GL_ONE_MINUS_DST_COLOR            0x0307
+#define GL_SRC_ALPHA_SATURATE             0x0308
+/*      GL_SRC_ALPHA */
+/*      GL_ONE_MINUS_SRC_ALPHA */
+/*      GL_DST_ALPHA */
+/*      GL_ONE_MINUS_DST_ALPHA */
+
+/* ClipPlaneName */
+#define GL_CLIP_PLANE0                    0x3000
+#define GL_CLIP_PLANE1                    0x3001
+#define GL_CLIP_PLANE2                    0x3002
+#define GL_CLIP_PLANE3                    0x3003
+#define GL_CLIP_PLANE4                    0x3004
+#define GL_CLIP_PLANE5                    0x3005
+
+/* ColorMaterialFace */
+/*      GL_FRONT_AND_BACK */
+
+/* ColorMaterialParameter */
+/*      GL_AMBIENT_AND_DIFFUSE */
+
+/* ColorPointerType */
+/*      GL_UNSIGNED_BYTE */
+/*      GL_FLOAT */
+/*      GL_FIXED */
+
+/* CullFaceMode */
+#define GL_FRONT                          0x0404
+#define GL_BACK                           0x0405
+#define GL_FRONT_AND_BACK                 0x0408
+
+/* DepthFunction */
+/*      GL_NEVER */
+/*      GL_LESS */
+/*      GL_EQUAL */
+/*      GL_LEQUAL */
+/*      GL_GREATER */
+/*      GL_NOTEQUAL */
+/*      GL_GEQUAL */
+/*      GL_ALWAYS */
+
+/* EnableCap */
+#define GL_FOG                            0x0B60
+#define GL_LIGHTING                       0x0B50
+#define GL_TEXTURE_2D                     0x0DE1
+#define GL_CULL_FACE                      0x0B44
+#define GL_ALPHA_TEST                     0x0BC0
+#define GL_BLEND                          0x0BE2
+#define GL_COLOR_LOGIC_OP                 0x0BF2
+#define GL_DITHER                         0x0BD0
+#define GL_STENCIL_TEST                   0x0B90
+#define GL_DEPTH_TEST                     0x0B71
+/*      GL_LIGHT0 */
+/*      GL_LIGHT1 */
+/*      GL_LIGHT2 */
+/*      GL_LIGHT3 */
+/*      GL_LIGHT4 */
+/*      GL_LIGHT5 */
+/*      GL_LIGHT6 */
+/*      GL_LIGHT7 */
+#define GL_POINT_SMOOTH                   0x0B10
+#define GL_LINE_SMOOTH                    0x0B20
+#define GL_SCISSOR_TEST                   0x0C11
+#define GL_COLOR_MATERIAL                 0x0B57
+#define GL_NORMALIZE                      0x0BA1
+#define GL_RESCALE_NORMAL                 0x803A
+#define GL_POLYGON_OFFSET_FILL            0x8037
+#define GL_VERTEX_ARRAY                   0x8074
+#define GL_NORMAL_ARRAY                   0x8075
+#define GL_COLOR_ARRAY                    0x8076
+#define GL_TEXTURE_COORD_ARRAY            0x8078
+#define GL_MULTISAMPLE                    0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE       0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE            0x809F
+#define GL_SAMPLE_COVERAGE                0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR                       0
+#define GL_INVALID_ENUM                   0x0500
+#define GL_INVALID_VALUE                  0x0501
+#define GL_INVALID_OPERATION              0x0502
+#define GL_STACK_OVERFLOW                 0x0503
+#define GL_STACK_UNDERFLOW                0x0504
+#define GL_OUT_OF_MEMORY                  0x0505
+
+/* FogMode */
+/*      GL_LINEAR */
+#define GL_EXP                            0x0800
+#define GL_EXP2                           0x0801
+
+/* FogParameter */
+#define GL_FOG_DENSITY                    0x0B62
+#define GL_FOG_START                      0x0B63
+#define GL_FOG_END                        0x0B64
+#define GL_FOG_MODE                       0x0B65
+#define GL_FOG_COLOR                      0x0B66
+
+/* FrontFaceDirection */
+#define GL_CW                             0x0900
+#define GL_CCW                            0x0901
+
+/* GetPName */
+#define GL_CURRENT_COLOR                  0x0B00
+#define GL_CURRENT_NORMAL                 0x0B02
+#define GL_CURRENT_TEXTURE_COORDS         0x0B03
+#define GL_POINT_SIZE                     0x0B11
+#define GL_POINT_SIZE_MIN                 0x8126
+#define GL_POINT_SIZE_MAX                 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE      0x8128
+#define GL_POINT_DISTANCE_ATTENUATION     0x8129
+#define GL_SMOOTH_POINT_SIZE_RANGE        0x0B12
+#define GL_LINE_WIDTH                     0x0B21
+#define GL_SMOOTH_LINE_WIDTH_RANGE        0x0B22
+#define GL_ALIASED_POINT_SIZE_RANGE       0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE       0x846E
+#define GL_CULL_FACE_MODE                 0x0B45
+#define GL_FRONT_FACE                     0x0B46
+#define GL_SHADE_MODEL                    0x0B54
+#define GL_DEPTH_RANGE                    0x0B70
+#define GL_DEPTH_WRITEMASK                0x0B72
+#define GL_DEPTH_CLEAR_VALUE              0x0B73
+#define GL_DEPTH_FUNC                     0x0B74
+#define GL_STENCIL_CLEAR_VALUE            0x0B91
+#define GL_STENCIL_FUNC                   0x0B92
+#define GL_STENCIL_VALUE_MASK             0x0B93
+#define GL_STENCIL_FAIL                   0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL        0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS        0x0B96
+#define GL_STENCIL_REF                    0x0B97
+#define GL_STENCIL_WRITEMASK              0x0B98
+#define GL_MATRIX_MODE                    0x0BA0
+#define GL_VIEWPORT                       0x0BA2
+#define GL_MODELVIEW_STACK_DEPTH          0x0BA3
+#define GL_PROJECTION_STACK_DEPTH         0x0BA4
+#define GL_TEXTURE_STACK_DEPTH            0x0BA5
+#define GL_MODELVIEW_MATRIX               0x0BA6
+#define GL_PROJECTION_MATRIX              0x0BA7
+#define GL_TEXTURE_MATRIX                 0x0BA8
+#define GL_ALPHA_TEST_FUNC                0x0BC1
+#define GL_ALPHA_TEST_REF                 0x0BC2
+#define GL_BLEND_DST                      0x0BE0
+#define GL_BLEND_SRC                      0x0BE1
+#define GL_LOGIC_OP_MODE                  0x0BF0
+#define GL_SCISSOR_BOX                    0x0C10
+#define GL_SCISSOR_TEST                   0x0C11
+#define GL_COLOR_CLEAR_VALUE              0x0C22
+#define GL_COLOR_WRITEMASK                0x0C23
+#define GL_UNPACK_ALIGNMENT               0x0CF5
+#define GL_PACK_ALIGNMENT                 0x0D05
+#define GL_MAX_LIGHTS                     0x0D31
+#define GL_MAX_CLIP_PLANES                0x0D32
+#define GL_MAX_TEXTURE_SIZE               0x0D33
+#define GL_MAX_MODELVIEW_STACK_DEPTH      0x0D36
+#define GL_MAX_PROJECTION_STACK_DEPTH     0x0D38
+#define GL_MAX_TEXTURE_STACK_DEPTH        0x0D39
+#define GL_MAX_VIEWPORT_DIMS              0x0D3A
+#define GL_MAX_TEXTURE_UNITS              0x84E2
+#define GL_SUBPIXEL_BITS                  0x0D50
+#define GL_RED_BITS                       0x0D52
+#define GL_GREEN_BITS                     0x0D53
+#define GL_BLUE_BITS                      0x0D54
+#define GL_ALPHA_BITS                     0x0D55
+#define GL_DEPTH_BITS                     0x0D56
+#define GL_STENCIL_BITS                   0x0D57
+#define GL_POLYGON_OFFSET_UNITS           0x2A00
+#define GL_POLYGON_OFFSET_FILL            0x8037
+#define GL_POLYGON_OFFSET_FACTOR          0x8038
+#define GL_TEXTURE_BINDING_2D             0x8069
+#define GL_VERTEX_ARRAY_SIZE              0x807A
+#define GL_VERTEX_ARRAY_TYPE              0x807B
+#define GL_VERTEX_ARRAY_STRIDE            0x807C
+#define GL_NORMAL_ARRAY_TYPE              0x807E
+#define GL_NORMAL_ARRAY_STRIDE            0x807F
+#define GL_COLOR_ARRAY_SIZE               0x8081
+#define GL_COLOR_ARRAY_TYPE               0x8082
+#define GL_COLOR_ARRAY_STRIDE             0x8083
+#define GL_TEXTURE_COORD_ARRAY_SIZE       0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE       0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE     0x808A
+#define GL_VERTEX_ARRAY_POINTER           0x808E
+#define GL_NORMAL_ARRAY_POINTER           0x808F
+#define GL_COLOR_ARRAY_POINTER            0x8090
+#define GL_TEXTURE_COORD_ARRAY_POINTER    0x8092
+#define GL_SAMPLE_BUFFERS                 0x80A8
+#define GL_SAMPLES                        0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE          0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT         0x80AB
+
+/* GetTextureParameter */
+/*      GL_TEXTURE_MAG_FILTER */
+/*      GL_TEXTURE_MIN_FILTER */
+/*      GL_TEXTURE_WRAP_S */
+/*      GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS     0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE                      0x1100
+#define GL_FASTEST                        0x1101
+#define GL_NICEST                         0x1102
+
+/* HintTarget */
+#define GL_PERSPECTIVE_CORRECTION_HINT    0x0C50
+#define GL_POINT_SMOOTH_HINT              0x0C51
+#define GL_LINE_SMOOTH_HINT               0x0C52
+#define GL_FOG_HINT                       0x0C54
+#define GL_GENERATE_MIPMAP_HINT           0x8192
+
+/* LightModelParameter */
+#define GL_LIGHT_MODEL_AMBIENT            0x0B53
+#define GL_LIGHT_MODEL_TWO_SIDE           0x0B52
+
+/* LightParameter */
+#define GL_AMBIENT                        0x1200
+#define GL_DIFFUSE                        0x1201
+#define GL_SPECULAR                       0x1202
+#define GL_POSITION                       0x1203
+#define GL_SPOT_DIRECTION                 0x1204
+#define GL_SPOT_EXPONENT                  0x1205
+#define GL_SPOT_CUTOFF                    0x1206
+#define GL_CONSTANT_ATTENUATION           0x1207
+#define GL_LINEAR_ATTENUATION             0x1208
+#define GL_QUADRATIC_ATTENUATION          0x1209
+
+/* DataType */
+#define GL_BYTE                           0x1400
+#define GL_UNSIGNED_BYTE                  0x1401
+#define GL_SHORT                          0x1402
+#define GL_UNSIGNED_SHORT                 0x1403
+#define GL_FLOAT                          0x1406
+#define GL_FIXED                          0x140C
+
+/* LogicOp */
+#define GL_CLEAR                          0x1500
+#define GL_AND                            0x1501
+#define GL_AND_REVERSE                    0x1502
+#define GL_COPY                           0x1503
+#define GL_AND_INVERTED                   0x1504
+#define GL_NOOP                           0x1505
+#define GL_XOR                            0x1506
+#define GL_OR                             0x1507
+#define GL_NOR                            0x1508
+#define GL_EQUIV                          0x1509
+#define GL_INVERT                         0x150A
+#define GL_OR_REVERSE                     0x150B
+#define GL_COPY_INVERTED                  0x150C
+#define GL_OR_INVERTED                    0x150D
+#define GL_NAND                           0x150E
+#define GL_SET                            0x150F
+
+/* MaterialFace */
+/*      GL_FRONT_AND_BACK */
+
+/* MaterialParameter */
+#define GL_EMISSION                       0x1600
+#define GL_SHININESS                      0x1601
+#define GL_AMBIENT_AND_DIFFUSE            0x1602
+/*      GL_AMBIENT */
+/*      GL_DIFFUSE */
+/*      GL_SPECULAR */
+
+/* MatrixMode */
+#define GL_MODELVIEW                      0x1700
+#define GL_PROJECTION                     0x1701
+#define GL_TEXTURE                        0x1702
+
+/* NormalPointerType */
+/*      GL_BYTE */
+/*      GL_SHORT */
+/*      GL_FLOAT */
+/*      GL_FIXED */
+
+/* PixelFormat */
+#define GL_ALPHA                          0x1906
+#define GL_RGB                            0x1907
+#define GL_RGBA                           0x1908
+#define GL_LUMINANCE                      0x1909
+#define GL_LUMINANCE_ALPHA                0x190A
+
+/* PixelStoreParameter */
+#define GL_UNPACK_ALIGNMENT               0x0CF5
+#define GL_PACK_ALIGNMENT                 0x0D05
+
+/* PixelType */
+/*      GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4         0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1         0x8034
+#define GL_UNSIGNED_SHORT_5_6_5           0x8363
+
+/* ShadingModel */
+#define GL_FLAT                           0x1D00
+#define GL_SMOOTH                         0x1D01
+
+/* StencilFunction */
+/*      GL_NEVER */
+/*      GL_LESS */
+/*      GL_EQUAL */
+/*      GL_LEQUAL */
+/*      GL_GREATER */
+/*      GL_NOTEQUAL */
+/*      GL_GEQUAL */
+/*      GL_ALWAYS */
+
+/* StencilOp */
+/*      GL_ZERO */
+#define GL_KEEP                           0x1E00
+#define GL_REPLACE                        0x1E01
+#define GL_INCR                           0x1E02
+#define GL_DECR                           0x1E03
+/*      GL_INVERT */
+
+/* StringName */
+#define GL_VENDOR                         0x1F00
+#define GL_RENDERER                       0x1F01
+#define GL_VERSION                        0x1F02
+#define GL_EXTENSIONS                     0x1F03
+
+/* TexCoordPointerType */
+/*      GL_SHORT */
+/*      GL_FLOAT */
+/*      GL_FIXED */
+/*      GL_BYTE */
+
+/* TextureEnvMode */
+#define GL_MODULATE                       0x2100
+#define GL_DECAL                          0x2101
+/*      GL_BLEND */
+#define GL_ADD                            0x0104
+/*      GL_REPLACE */
+
+/* TextureEnvParameter */
+#define GL_TEXTURE_ENV_MODE               0x2200
+#define GL_TEXTURE_ENV_COLOR              0x2201
+
+/* TextureEnvTarget */
+#define GL_TEXTURE_ENV                    0x2300
+
+/* TextureMagFilter */
+#define GL_NEAREST                        0x2600
+#define GL_LINEAR                         0x2601
+
+/* TextureMinFilter */
+/*      GL_NEAREST */
+/*      GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST         0x2700
+#define GL_LINEAR_MIPMAP_NEAREST          0x2701
+#define GL_NEAREST_MIPMAP_LINEAR          0x2702
+#define GL_LINEAR_MIPMAP_LINEAR           0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER             0x2800
+#define GL_TEXTURE_MIN_FILTER             0x2801
+#define GL_TEXTURE_WRAP_S                 0x2802
+#define GL_TEXTURE_WRAP_T                 0x2803
+#define GL_GENERATE_MIPMAP                0x8191
+
+/* TextureTarget */
+/*      GL_TEXTURE_2D */
+
+/* TextureUnit */
+#define GL_TEXTURE0                       0x84C0
+#define GL_TEXTURE1                       0x84C1
+#define GL_TEXTURE2                       0x84C2
+#define GL_TEXTURE3                       0x84C3
+#define GL_TEXTURE4                       0x84C4
+#define GL_TEXTURE5                       0x84C5
+#define GL_TEXTURE6                       0x84C6
+#define GL_TEXTURE7                       0x84C7
+#define GL_TEXTURE8                       0x84C8
+#define GL_TEXTURE9                       0x84C9
+#define GL_TEXTURE10                      0x84CA
+#define GL_TEXTURE11                      0x84CB
+#define GL_TEXTURE12                      0x84CC
+#define GL_TEXTURE13                      0x84CD
+#define GL_TEXTURE14                      0x84CE
+#define GL_TEXTURE15                      0x84CF
+#define GL_TEXTURE16                      0x84D0
+#define GL_TEXTURE17                      0x84D1
+#define GL_TEXTURE18                      0x84D2
+#define GL_TEXTURE19                      0x84D3
+#define GL_TEXTURE20                      0x84D4
+#define GL_TEXTURE21                      0x84D5
+#define GL_TEXTURE22                      0x84D6
+#define GL_TEXTURE23                      0x84D7
+#define GL_TEXTURE24                      0x84D8
+#define GL_TEXTURE25                      0x84D9
+#define GL_TEXTURE26                      0x84DA
+#define GL_TEXTURE27                      0x84DB
+#define GL_TEXTURE28                      0x84DC
+#define GL_TEXTURE29                      0x84DD
+#define GL_TEXTURE30                      0x84DE
+#define GL_TEXTURE31                      0x84DF
+#define GL_ACTIVE_TEXTURE                 0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE          0x84E1
+
+/* TextureWrapMode */
+#define GL_REPEAT                         0x2901
+#define GL_CLAMP_TO_EDGE                  0x812F
+
+/* VertexPointerType */
+/*      GL_SHORT */
+/*      GL_FLOAT */
+/*      GL_FIXED */
+/*      GL_BYTE */
+
+/* LightName */
+#define GL_LIGHT0                         0x4000
+#define GL_LIGHT1                         0x4001
+#define GL_LIGHT2                         0x4002
+#define GL_LIGHT3                         0x4003
+#define GL_LIGHT4                         0x4004
+#define GL_LIGHT5                         0x4005
+#define GL_LIGHT6                         0x4006
+#define GL_LIGHT7                         0x4007
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER                   0x8892
+#define GL_ELEMENT_ARRAY_BUFFER           0x8893
+
+#define GL_ARRAY_BUFFER_BINDING               0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING       0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING        0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING        0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING         0x8898
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
+
+#define GL_STATIC_DRAW                    0x88E4
+#define GL_DYNAMIC_DRAW                   0x88E8
+
+#define GL_BUFFER_SIZE                    0x8764
+#define GL_BUFFER_USAGE                   0x8765
+
+/* Texture combine + dot3 */
+#define GL_SUBTRACT                       0x84E7
+#define GL_COMBINE                        0x8570
+#define GL_COMBINE_RGB                    0x8571
+#define GL_COMBINE_ALPHA                  0x8572
+#define GL_RGB_SCALE                      0x8573
+#define GL_ADD_SIGNED                     0x8574
+#define GL_INTERPOLATE                    0x8575
+#define GL_CONSTANT                       0x8576
+#define GL_PRIMARY_COLOR                  0x8577
+#define GL_PREVIOUS                       0x8578
+#define GL_OPERAND0_RGB                   0x8590
+#define GL_OPERAND1_RGB                   0x8591
+#define GL_OPERAND2_RGB                   0x8592
+#define GL_OPERAND0_ALPHA                 0x8598
+#define GL_OPERAND1_ALPHA                 0x8599
+#define GL_OPERAND2_ALPHA                 0x859A
+
+#define GL_ALPHA_SCALE                    0x0D1C
+
+#define GL_SRC0_RGB                       0x8580
+#define GL_SRC1_RGB                       0x8581
+#define GL_SRC2_RGB                       0x8582
+#define GL_SRC0_ALPHA                     0x8588
+#define GL_SRC1_ALPHA                     0x8589
+#define GL_SRC2_ALPHA                     0x858A
+
+#define GL_DOT3_RGB                       0x86AE
+#define GL_DOT3_RGBA                      0x86AF
+
+/*------------------------------------------------------------------------*
+ * required OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* OES_read_format */
+#ifndef GL_OES_read_format
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES                   0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES                 0x8B9B
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_PALETTE4_RGB8_OES                                    0x8B90
+#define GL_PALETTE4_RGBA8_OES                                   0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES                                0x8B92
+#define GL_PALETTE4_RGBA4_OES                                   0x8B93
+#define GL_PALETTE4_RGB5_A1_OES                                 0x8B94
+#define GL_PALETTE8_RGB8_OES                                    0x8B95
+#define GL_PALETTE8_RGBA8_OES                                   0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES                                0x8B97
+#define GL_PALETTE8_RGBA4_OES                                   0x8B98
+#define GL_PALETTE8_RGB5_A1_OES                                 0x8B99
+#endif
+
+/* OES_point_size_array */
+#ifndef GL_OES_point_size_array
+#define GL_POINT_SIZE_ARRAY_OES                                 0x8B9C
+#define GL_POINT_SIZE_ARRAY_TYPE_OES                            0x898A
+#define GL_POINT_SIZE_ARRAY_STRIDE_OES                          0x898B
+#define GL_POINT_SIZE_ARRAY_POINTER_OES                         0x898C
+#define GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES                  0x8B9F
+#endif
+
+/* GL_OES_point_sprite */
+#ifndef GL_OES_point_sprite
+#define GL_POINT_SPRITE_OES                                     0x8861
+#define GL_COORD_REPLACE_OES                                    0x8862
+#endif
+
+/*************************************************************/
+
+/* Available only in Common profile */
+GL_API void GL_APIENTRY glAlphaFunc (GLenum func, GLclampf ref);
+GL_API void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_API void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_API void GL_APIENTRY glClipPlanef (GLenum plane, const GLfloat *equation);
+GL_API void GL_APIENTRY glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GL_API void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_API void GL_APIENTRY glFogf (GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glFogfv (GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glFrustumf (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glGetClipPlanef (GLenum pname, GLfloat eqn[4]);
+GL_API void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetLightfv (GLenum light, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetMaterialfv (GLenum face, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetTexEnvfv (GLenum env, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glLightModelf (GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glLightModelfv (GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glLightf (GLenum light, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glLightfv (GLenum light, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glLineWidth (GLfloat width);
+GL_API void GL_APIENTRY glLoadMatrixf (const GLfloat *m);
+GL_API void GL_APIENTRY glMaterialf (GLenum face, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glMaterialfv (GLenum face, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glMultMatrixf (const GLfloat *m);
+GL_API void GL_APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+GL_API void GL_APIENTRY glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz);
+GL_API void GL_APIENTRY glOrthof (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glPointParameterf (GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glPointSize (GLfloat size);
+GL_API void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_API void GL_APIENTRY glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+GL_API void GL_APIENTRY glScalef (GLfloat x, GLfloat y, GLfloat z);
+GL_API void GL_APIENTRY glTexEnvf (GLenum target, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glTranslatef (GLfloat x, GLfloat y, GLfloat z);
+
+/* Available in both Common and Common-Lite profiles */
+GL_API void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_API void GL_APIENTRY glAlphaFuncx (GLenum func, GLclampx ref);
+GL_API void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_API void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_API void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_API void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
+GL_API void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
+GL_API void GL_APIENTRY glClear (GLbitfield mask);
+GL_API void GL_APIENTRY glClearColorx (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
+GL_API void GL_APIENTRY glClearDepthx (GLclampx depth);
+GL_API void GL_APIENTRY glClearStencil (GLint s);
+GL_API void GL_APIENTRY glClientActiveTexture (GLenum texture);
+GL_API void GL_APIENTRY glClipPlanex (GLenum plane, const GLfixed *equation);
+GL_API void GL_APIENTRY glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+GL_API void GL_APIENTRY glColor4x (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GL_API void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_API void GL_APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+GL_API void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+GL_API void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_API void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glCullFace (GLenum mode);
+GL_API void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
+GL_API void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
+GL_API void GL_APIENTRY glDepthFunc (GLenum func);
+GL_API void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_API void GL_APIENTRY glDepthRangex (GLclampx zNear, GLclampx zFar);
+GL_API void GL_APIENTRY glDisable (GLenum cap);
+GL_API void GL_APIENTRY glDisableClientState (GLenum array);
+GL_API void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_API void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+GL_API void GL_APIENTRY glEnable (GLenum cap);
+GL_API void GL_APIENTRY glEnableClientState (GLenum array);
+GL_API void GL_APIENTRY glFinish (void);
+GL_API void GL_APIENTRY glFlush (void);
+GL_API void GL_APIENTRY glFogx (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glFogxv (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glFrontFace (GLenum mode);
+GL_API void GL_APIENTRY glFrustumx (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *params);
+GL_API void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetClipPlanex (GLenum pname, GLfixed eqn[4]);
+GL_API void GL_APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
+GL_API void GL_APIENTRY glGenTextures (GLsizei n, GLuint *textures);
+GL_API GLenum GL_APIENTRY glGetError (void);
+GL_API void GL_APIENTRY glGetFixedv (GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetLightxv (GLenum light, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetMaterialxv (GLenum face, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetPointerv (GLenum pname, void **params);
+GL_API const GLubyte * GL_APIENTRY glGetString (GLenum name);
+GL_API void GL_APIENTRY glGetTexEnviv (GLenum env, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetTexEnvxv (GLenum env, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetTexParameterxv (GLenum target, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_API GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_API GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_API GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_API void GL_APIENTRY glLightModelx (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightModelxv (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLightx (GLenum light, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightxv (GLenum light, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLineWidthx (GLfixed width);
+GL_API void GL_APIENTRY glLoadIdentity (void);
+GL_API void GL_APIENTRY glLoadMatrixx (const GLfixed *m);
+GL_API void GL_APIENTRY glLogicOp (GLenum opcode);
+GL_API void GL_APIENTRY glMaterialx (GLenum face, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glMaterialxv (GLenum face, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glMatrixMode (GLenum mode);
+GL_API void GL_APIENTRY glMultMatrixx (const GLfixed *m);
+GL_API void GL_APIENTRY glMultiTexCoord4x (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GL_API void GL_APIENTRY glNormal3x (GLfixed nx, GLfixed ny, GLfixed nz);
+GL_API void GL_APIENTRY glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glOrthox (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_API void GL_APIENTRY glPointParameterx (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glPointParameterxv (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glPointSizex (GLfixed size);
+GL_API void GL_APIENTRY glPolygonOffsetx (GLfixed factor, GLfixed units);
+GL_API void GL_APIENTRY glPopMatrix (void);
+GL_API void GL_APIENTRY glPushMatrix (void);
+GL_API void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+GL_API void GL_APIENTRY glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_API void GL_APIENTRY glSampleCoveragex (GLclampx value, GLboolean invert);
+GL_API void GL_APIENTRY glScalex (GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glShadeModel (GLenum mode);
+GL_API void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_API void GL_APIENTRY glStencilMask (GLuint mask);
+GL_API void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_API void GL_APIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glTexEnvi (GLenum target, GLenum pname, GLint param);
+GL_API void GL_APIENTRY glTexEnvx (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexEnviv (GLenum target, GLenum pname, const GLint *params);
+GL_API void GL_APIENTRY glTexEnvxv (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+GL_API void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_API void GL_APIENTRY glTexParameterx (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params);
+GL_API void GL_APIENTRY glTexParameterxv (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+GL_API void GL_APIENTRY glTranslatex (GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+/*------------------------------------------------------------------------*
+ * Required OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_read_format */
+#ifndef GL_OES_read_format
+#define GL_OES_read_format 1
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#endif
+
+/* GL_OES_point_size_array */
+#ifndef GL_OES_point_size_array
+#define GL_OES_point_size_array 1
+GL_API void GL_APIENTRY glPointSizePointerOES (GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+/* GL_OES_point_sprite */
+#ifndef GL_OES_point_sprite
+#define GL_OES_point_sprite 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl_h_ */
+
diff --git a/opengl/include/GLES/glext.h b/opengl/include/GLES/glext.h
new file mode 100644
index 0000000..4c01871
--- /dev/null
+++ b/opengl/include/GLES/glext.h
@@ -0,0 +1,622 @@
+#ifndef __glext_h_
+#define __glext_h_
+
+/* $Revision: 7172 $ on $Date:: 2009-01-09 11:17:41 -0800 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef GL_APIENTRYP
+#   define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_blend_equation_separate */
+#ifndef GL_OES_blend_equation_separate
+/* BLEND_EQUATION_RGB_OES same as BLEND_EQUATION_OES */
+#define GL_BLEND_EQUATION_RGB_OES                               0x8009
+#define GL_BLEND_EQUATION_ALPHA_OES                             0x883D
+#endif
+
+/* GL_OES_blend_func_separate */
+#ifndef GL_OES_blend_func_separate
+#define GL_BLEND_DST_RGB_OES                                    0x80C8
+#define GL_BLEND_SRC_RGB_OES                                    0x80C9
+#define GL_BLEND_DST_ALPHA_OES                                  0x80CA
+#define GL_BLEND_SRC_ALPHA_OES                                  0x80CB
+#endif
+
+/* GL_OES_blend_subtract */
+#ifndef GL_OES_blend_subtract
+#define GL_BLEND_EQUATION_OES                                   0x8009
+#define GL_FUNC_ADD_OES                                         0x8006
+#define GL_FUNC_SUBTRACT_OES                                    0x800A
+#define GL_FUNC_REVERSE_SUBTRACT_OES                            0x800B
+#endif
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_ETC1_RGB8_OES                                        0x8D64
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_DEPTH_COMPONENT24_OES                                0x81A6
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_DEPTH_COMPONENT32_OES                                0x81A7
+#endif
+
+/* GL_OES_draw_texture */
+#ifndef GL_OES_draw_texture
+#define GL_TEXTURE_CROP_RECT_OES                                0x8B9D
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+/* GL_OES_fixed_point */
+#ifndef GL_OES_fixed_point
+#define GL_FIXED_OES                                            0x140C
+#endif
+
+/* GL_OES_framebuffer_object */
+#ifndef GL_OES_framebuffer_object
+#define GL_NONE_OES                                             0
+#define GL_FRAMEBUFFER_OES                                      0x8D40
+#define GL_RENDERBUFFER_OES                                     0x8D41
+#define GL_RGBA4_OES                                            0x8056
+#define GL_RGB5_A1_OES                                          0x8057
+#define GL_RGB565_OES                                           0x8D62
+#define GL_DEPTH_COMPONENT16_OES                                0x81A5
+#define GL_RENDERBUFFER_WIDTH_OES                               0x8D42
+#define GL_RENDERBUFFER_HEIGHT_OES                              0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT_OES                     0x8D44
+#define GL_RENDERBUFFER_RED_SIZE_OES                            0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE_OES                          0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE_OES                           0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE_OES                          0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE_OES                          0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE_OES                        0x8D55
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES               0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES               0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES             0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES     0x8CD3
+#define GL_COLOR_ATTACHMENT0_OES                                0x8CE0
+#define GL_DEPTH_ATTACHMENT_OES                                 0x8D00
+#define GL_STENCIL_ATTACHMENT_OES                               0x8D20
+#define GL_FRAMEBUFFER_COMPLETE_OES                             0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES                0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES        0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES                0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES                   0x8CDA
+#define GL_FRAMEBUFFER_UNSUPPORTED_OES                          0x8CDD
+#define GL_FRAMEBUFFER_BINDING_OES                              0x8CA6
+#define GL_RENDERBUFFER_BINDING_OES                             0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE_OES                            0x84E8
+#define GL_INVALID_FRAMEBUFFER_OPERATION_OES                    0x0506
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_WRITE_ONLY_OES                                       0x88B9
+#define GL_BUFFER_ACCESS_OES                                    0x88BB
+#define GL_BUFFER_MAPPED_OES                                    0x88BC
+#define GL_BUFFER_MAP_POINTER_OES                               0x88BD
+#endif
+
+/* GL_OES_matrix_get */
+#ifndef GL_OES_matrix_get
+#define GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES               0x898D
+#define GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES              0x898E
+#define GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES                 0x898F
+#endif
+
+/* GL_OES_matrix_palette */
+#ifndef GL_OES_matrix_palette
+#define GL_MAX_VERTEX_UNITS_OES                                 0x86A4
+#define GL_MAX_PALETTE_MATRICES_OES                             0x8842
+#define GL_MATRIX_PALETTE_OES                                   0x8840
+#define GL_MATRIX_INDEX_ARRAY_OES                               0x8844
+#define GL_WEIGHT_ARRAY_OES                                     0x86AD
+#define GL_CURRENT_PALETTE_MATRIX_OES                           0x8843
+#define GL_MATRIX_INDEX_ARRAY_SIZE_OES                          0x8846
+#define GL_MATRIX_INDEX_ARRAY_TYPE_OES                          0x8847
+#define GL_MATRIX_INDEX_ARRAY_STRIDE_OES                        0x8848
+#define GL_MATRIX_INDEX_ARRAY_POINTER_OES                       0x8849
+#define GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES                0x8B9E
+#define GL_WEIGHT_ARRAY_SIZE_OES                                0x86AB
+#define GL_WEIGHT_ARRAY_TYPE_OES                                0x86A9
+#define GL_WEIGHT_ARRAY_STRIDE_OES                              0x86AA
+#define GL_WEIGHT_ARRAY_POINTER_OES                             0x86AC
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_OES                      0x889E
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_DEPTH_STENCIL_OES                                    0x84F9
+#define GL_UNSIGNED_INT_24_8_OES                                0x84FA
+#define GL_DEPTH24_STENCIL8_OES                                 0x88F0
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_RGB8_OES                                             0x8051
+#define GL_RGBA8_OES                                            0x8058
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_STENCIL_INDEX1_OES                                   0x8D46
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_STENCIL_INDEX4_OES                                   0x8D47
+#endif
+
+/* GL_OES_stencil8 */
+#ifndef GL_OES_stencil8
+#define GL_STENCIL_INDEX8_OES                                   0x8D48
+#endif
+
+/* GL_OES_stencil_wrap */
+#ifndef GL_OES_stencil_wrap
+#define GL_INCR_WRAP_OES                                        0x8507
+#define GL_DECR_WRAP_OES                                        0x8508
+#endif
+
+/* GL_OES_texture_cube_map */
+#ifndef GL_OES_texture_cube_map
+#define GL_NORMAL_MAP_OES                                       0x8511
+#define GL_REFLECTION_MAP_OES                                   0x8512
+#define GL_TEXTURE_CUBE_MAP_OES                                 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_OES                         0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES                      0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES                      0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES                      0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES                      0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES                      0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES                      0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES                        0x851C
+#define GL_TEXTURE_GEN_MODE_OES                                 0x2500
+#define GL_TEXTURE_GEN_STR_OES                                  0x8D60
+#endif
+
+/* GL_OES_texture_mirrored_repeat */
+#ifndef GL_OES_texture_mirrored_repeat
+#define GL_MIRRORED_REPEAT_OES                                  0x8370
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_3DC_X_AMD                                            0x87F9
+#define GL_3DC_XY_AMD                                           0x87FA
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD                                          0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD                          0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD                      0x87EE
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT                           0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT                       0x84FF
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_blend_equation_separate */
+#ifndef GL_OES_blend_equation_separate
+#define GL_OES_blend_equation_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glBlendEquationSeparateOES (GLenum modeRGB, GLenum modeAlpha);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEOESPROC) (GLenum modeRGB, GLenum modeAlpha);
+#endif
+
+/* GL_OES_blend_func_separate */
+#ifndef GL_OES_blend_func_separate
+#define GL_OES_blend_func_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glBlendFuncSeparateOES (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEOESPROC) (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+#endif
+
+/* GL_OES_blend_subtract */
+#ifndef GL_OES_blend_subtract
+#define GL_OES_blend_subtract 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glBlendEquationOES (GLenum mode);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONOESPROC) (GLenum mode);
+#endif
+
+/* GL_OES_byte_coordinates */
+#ifndef GL_OES_byte_coordinates
+#define GL_OES_byte_coordinates 1
+#endif
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_OES_compressed_ETC1_RGB8_texture 1
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_OES_depth24 1
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_OES_depth32 1
+#endif
+
+/* GL_OES_draw_texture */
+#ifndef GL_OES_draw_texture
+#define GL_OES_draw_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glDrawTexsOES (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height);
+GL_API void GL_APIENTRY glDrawTexiOES (GLint x, GLint y, GLint z, GLint width, GLint height);
+GL_API void GL_APIENTRY glDrawTexxOES (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height);
+GL_API void GL_APIENTRY glDrawTexsvOES (const GLshort *coords);
+GL_API void GL_APIENTRY glDrawTexivOES (const GLint *coords);
+GL_API void GL_APIENTRY glDrawTexxvOES (const GLfixed *coords);
+GL_API void GL_APIENTRY glDrawTexfOES (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height);
+GL_API void GL_APIENTRY glDrawTexfvOES (const GLfloat *coords);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWTEXSOESPROC) (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXIOESPROC) (GLint x, GLint y, GLint z, GLint width, GLint height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXXOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXSVOESPROC) (const GLshort *coords);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXIVOESPROC) (const GLint *coords);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXXVOESPROC) (const GLfixed *coords);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXFOESPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXFVOESPROC) (const GLfloat *coords);
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_API void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_OES_element_index_uint 1
+#endif
+
+/* GL_OES_extended_matrix_palette */
+#ifndef GL_OES_extended_matrix_palette
+#define GL_OES_extended_matrix_palette 1
+#endif
+
+/* GL_OES_fbo_render_mipmap */
+#ifndef GL_OES_fbo_render_mipmap
+#define GL_OES_fbo_render_mipmap 1
+#endif
+
+/* GL_OES_fixed_point */
+#ifndef GL_OES_fixed_point
+#define GL_OES_fixed_point 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glAlphaFuncxOES (GLenum func, GLclampx ref);
+GL_API void GL_APIENTRY glClearColorxOES (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
+GL_API void GL_APIENTRY glClearDepthxOES (GLclampx depth);
+GL_API void GL_APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation);
+GL_API void GL_APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GL_API void GL_APIENTRY glDepthRangexOES (GLclampx zNear, GLclampx zFar);
+GL_API void GL_APIENTRY glFogxOES (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glFogxvOES (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glFrustumxOES (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glGetClipPlanexOES (GLenum pname, GLfixed eqn[4]);
+GL_API void GL_APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetLightxvOES (GLenum light, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetMaterialxvOES (GLenum face, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetTexEnvxvOES (GLenum env, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glLightModelxOES (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLineWidthxOES (GLfixed width);
+GL_API void GL_APIENTRY glLoadMatrixxOES (const GLfixed *m);
+GL_API void GL_APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glMultMatrixxOES (const GLfixed *m);
+GL_API void GL_APIENTRY glMultiTexCoord4xOES (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GL_API void GL_APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz);
+GL_API void GL_APIENTRY glOrthoxOES (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glPointParameterxOES (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glPointSizexOES (GLfixed size);
+GL_API void GL_APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units);
+GL_API void GL_APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glSampleCoveragexOES (GLclampx value, GLboolean invert);
+GL_API void GL_APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z);
+#endif
+typedef void (GL_APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLclampx ref);
+typedef void (GL_APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
+typedef void (GL_APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLclampx depth);
+typedef void (GL_APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation);
+typedef void (GL_APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (GL_APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLclampx zNear, GLclampx zFar);
+typedef void (GL_APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+typedef void (GL_APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum pname, GLfixed eqn[4]);
+typedef void (GL_APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETLIGHTXVOESPROC) (GLenum light, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETMATERIALXVOESPROC) (GLenum face, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum env, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width);
+typedef void (GL_APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m);
+typedef void (GL_APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m);
+typedef void (GL_APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+typedef void (GL_APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz);
+typedef void (GL_APIENTRYP PFNGLORTHOXOESPROC) (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+typedef void (GL_APIENTRYP PFNGLPOINTPARAMETERXOESPROC) (GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size);
+typedef void (GL_APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units);
+typedef void (GL_APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+typedef void (GL_APIENTRYP PFNGLSAMPLECOVERAGEXOESPROC) (GLclampx value, GLboolean invert);
+typedef void (GL_APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (GL_APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+#endif
+
+/* GL_OES_framebuffer_object */
+#ifndef GL_OES_framebuffer_object
+#define GL_OES_framebuffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API GLboolean GL_APIENTRY glIsRenderbufferOES (GLuint renderbuffer);
+GL_API void GL_APIENTRY glBindRenderbufferOES (GLenum target, GLuint renderbuffer);
+GL_API void GL_APIENTRY glDeleteRenderbuffersOES (GLsizei n, const GLuint* renderbuffers);
+GL_API void GL_APIENTRY glGenRenderbuffersOES (GLsizei n, GLuint* renderbuffers);
+GL_API void GL_APIENTRY glRenderbufferStorageOES (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glGetRenderbufferParameterivOES (GLenum target, GLenum pname, GLint* params);
+GL_API GLboolean GL_APIENTRY glIsFramebufferOES (GLuint framebuffer);
+GL_API void GL_APIENTRY glBindFramebufferOES (GLenum target, GLuint framebuffer);
+GL_API void GL_APIENTRY glDeleteFramebuffersOES (GLsizei n, const GLuint* framebuffers);
+GL_API void GL_APIENTRY glGenFramebuffersOES (GLsizei n, GLuint* framebuffers);
+GL_API GLenum GL_APIENTRY glCheckFramebufferStatusOES (GLenum target);
+GL_API void GL_APIENTRY glFramebufferRenderbufferOES (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_API void GL_APIENTRY glFramebufferTexture2DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_API void GL_APIENTRY glGetFramebufferAttachmentParameterivOES (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_API void GL_APIENTRY glGenerateMipmapOES (GLenum target);
+#endif
+typedef GLboolean (GL_APIENTRYP PFNGLISRENDERBUFFEROESPROC) (GLuint renderbuffer);
+typedef void (GL_APIENTRYP PFNGLBINDRENDERBUFFEROESPROC) (GLenum target, GLuint renderbuffer);
+typedef void (GL_APIENTRYP PFNGLDELETERENDERBUFFERSOESPROC) (GLsizei n, const GLuint* renderbuffers);
+typedef void (GL_APIENTRYP PFNGLGENRENDERBUFFERSOESPROC) (GLsizei n, GLuint* renderbuffers);
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVOESPROC) (GLenum target, GLenum pname, GLint* params);
+typedef GLboolean (GL_APIENTRYP PFNGLISFRAMEBUFFEROESPROC) (GLuint framebuffer);
+typedef void (GL_APIENTRYP PFNGLBINDFRAMEBUFFEROESPROC) (GLenum target, GLuint framebuffer);
+typedef void (GL_APIENTRYP PFNGLDELETEFRAMEBUFFERSOESPROC) (GLsizei n, const GLuint* framebuffers);
+typedef void (GL_APIENTRYP PFNGLGENFRAMEBUFFERSOESPROC) (GLsizei n, GLuint* framebuffers);
+typedef GLenum (GL_APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSOESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEROESPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVOESPROC) (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+typedef void (GL_APIENTRYP PFNGLGENERATEMIPMAPOESPROC) (GLenum target);
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_OES_mapbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_API GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_API void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, void** params);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void** params);
+#endif
+
+/* GL_OES_matrix_get */
+#ifndef GL_OES_matrix_get
+#define GL_OES_matrix_get 1
+#endif
+
+/* GL_OES_matrix_palette */
+#ifndef GL_OES_matrix_palette
+#define GL_OES_matrix_palette 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glCurrentPaletteMatrixOES (GLuint matrixpaletteindex);
+GL_API void GL_APIENTRY glLoadPaletteFromModelViewMatrixOES (void);
+GL_API void GL_APIENTRY glMatrixIndexPointerOES (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glWeightPointerOES (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+typedef void (GL_APIENTRYP PFNGLCURRENTPALETTEMATRIXOESPROC) (GLuint matrixpaletteindex);
+typedef void (GL_APIENTRYP PFNGLLOADPALETTEFROMMODELVIEWMATRIXOESPROC) (void);
+typedef void (GL_APIENTRYP PFNGLMATRIXINDEXPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GL_APIENTRYP PFNGLWEIGHTPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_OES_packed_depth_stencil 1
+#endif
+
+/* GL_OES_query_matrix */
+#ifndef GL_OES_query_matrix
+#define GL_OES_query_matrix 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API GLbitfield GL_APIENTRY glQueryMatrixxOES (GLfixed mantissa[16], GLint exponent[16]);
+#endif
+typedef GLbitfield (GL_APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed mantissa[16], GLint exponent[16]);
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_OES_rgb8_rgba8 1
+#endif
+
+/* GL_OES_single_precision */
+#ifndef GL_OES_single_precision
+#define GL_OES_single_precision 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glDepthRangefOES (GLclampf zNear, GLclampf zFar);
+GL_API void GL_APIENTRY glFrustumfOES (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glOrthofOES (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation);
+GL_API void GL_APIENTRY glGetClipPlanefOES (GLenum pname, GLfloat eqn[4]);
+GL_API void GL_APIENTRY glClearDepthfOES (GLclampf depth);
+#endif
+typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf zNear, GLclampf zFar);
+typedef void (GL_APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+typedef void (GL_APIENTRYP PFNGLORTHOFOESPROC) (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+typedef void (GL_APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);
+typedef void (GL_APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum pname, GLfloat eqn[4]);
+typedef void (GL_APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth);
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_OES_stencil1 1
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_OES_stencil4 1
+#endif
+
+/* GL_OES_stencil8 */
+#ifndef GL_OES_stencil8
+#define GL_OES_stencil8 1
+#endif
+
+/* GL_OES_stencil_wrap */
+#ifndef GL_OES_stencil_wrap
+#define GL_OES_stencil_wrap 1
+#endif
+
+/* GL_OES_texture_cube_map */
+#ifndef GL_OES_texture_cube_map
+#define GL_OES_texture_cube_map 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glTexGenfOES (GLenum coord, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glTexGenfvOES (GLenum coord, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glTexGeniOES (GLenum coord, GLenum pname, GLint param);
+GL_API void GL_APIENTRY glTexGenivOES (GLenum coord, GLenum pname, const GLint *params);
+GL_API void GL_APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glGetTexGenfvOES (GLenum coord, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetTexGenivOES (GLenum coord, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXGENFOESPROC) (GLenum coord, GLenum pname, GLfloat param);
+typedef void (GL_APIENTRYP PFNGLTEXGENFVOESPROC) (GLenum coord, GLenum pname, const GLfloat *params);
+typedef void (GL_APIENTRYP PFNGLTEXGENIOESPROC) (GLenum coord, GLenum pname, GLint param);
+typedef void (GL_APIENTRYP PFNGLTEXGENIVOESPROC) (GLenum coord, GLenum pname, const GLint *params);
+typedef void (GL_APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXGENFVOESPROC) (GLenum coord, GLenum pname, GLfloat *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXGENIVOESPROC) (GLenum coord, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params);
+#endif
+
+/* GL_OES_texture_env_crossbar */
+#ifndef GL_OES_texture_env_crossbar
+#define GL_OES_texture_env_crossbar 1
+#endif
+
+/* GL_OES_texture_mirrored_repeat */
+#ifndef GL_OES_texture_mirrored_repeat
+#define GL_OES_texture_mirrored_repeat 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_AMD_compressed_3DC_texture 1
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_AMD_compressed_ATC_texture 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * dalvik extension functions
+ *------------------------------------------------------------------------*/
+#ifdef ANDROID
+void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+        const GLvoid *ptr, GLsizei count);
+void glNormalPointerBounds(GLenum type, GLsizei stride,
+        const GLvoid *pointer, GLsizei count);
+void glTexCoordPointerBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+void glVertexPointerBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __glext_h_ */
+
diff --git a/opengl/include/GLES/glplatform.h b/opengl/include/GLES/glplatform.h
new file mode 100644
index 0000000..0924cae
--- /dev/null
+++ b/opengl/include/GLES/glplatform.h
@@ -0,0 +1,39 @@
+#ifndef __glplatform_h_
+#define __glplatform_h_
+
+/* $Revision: 7172 $ on $Date:: 2009-01-09 11:17:41 -0800 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 1.X  gl.h
+ * Last modified on 2008/12/19
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file.  Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+#ifndef GL_API
+#define GL_API      KHRONOS_APICALL
+#endif
+
+#if defined(ANDROID)
+
+#define GL_APIENTRY KHRONOS_APIENTRY
+
+// XXX: this should probably not be here
+#define GL_DIRECT_TEXTURE_2D_QUALCOMM               0x7E80
+
+// XXX: not sure how this is intended to be used
+#define GL_GLEXT_PROTOTYPES
+
+#endif
+
+#endif /* __glplatform_h_ */
diff --git a/opengl/include/KHR/khrplatform.h b/opengl/include/KHR/khrplatform.h
new file mode 100644
index 0000000..4cc27c5
--- /dev/null
+++ b/opengl/include/KHR/khrplatform.h
@@ -0,0 +1,241 @@
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Platform-specific types and definitions.
+ * $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $
+ * 
+ * Adopters may modify this file to suit their platform. Adopters are
+ * encouraged to submit platform specific modifications to the Khronos
+ * group so that they can be included in future versions of this file.
+ * Please submit changes by sending them to the public Khronos Bugzilla
+ * (http://khronos.org/bugzilla) by filing a bug against product
+ * "Khronos (general)" component "Registry".
+ *
+ * A predefined template which fills in some of the bug fields can be
+ * reached using http://tinyurl.com/khrplatform-h-bugreport, but you
+ * must create a Bugzilla login first.
+ * 
+ *
+ * See the Implementer's Guidelines for information about where this file
+ * should be located on your system.
+ *    http://www.khronos.org/registry/implementers_guide.pdf
+ *
+ * 
+ * This file should be included as
+ *        #include <KHR/khrplatform.h>
+ * by the Khronos API header file that uses its types and defines.
+ *
+ * The types in this file should only be used to define API-specific types.
+ * Types defined in this file:
+ *    khronos_int8_t              signed   8  bit
+ *    khronos_uint8_t             unsigned 8  bit
+ *    khronos_int16_t             signed   16 bit
+ *    khronos_uint16_t            unsigned 16 bit
+ *    khronos_int32_t             signed   32 bit
+ *    khronos_uint32_t            unsigned 32 bit
+ *    khronos_int64_t             signed   64 bit
+ *    khronos_uint64_t            unsigned 64 bit
+ *    khronos_intptr_t            signed   same number of bits as a pointer
+ *    khronos_uintptr_t           unsigned same number of bits as a pointer
+ *    khronos_ssize_t             signed   size
+ *    khronos_usize_t             unsigned size
+ *    khronos_float_t             signed   32 bit floating point
+ *    khronos_time_ns_t           unsigned 64 bit time in nanoseconds
+ *    khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+ *                                         nanoseconds
+ *    khronos_stime_nanoseconds_t signed time interval in nanoseconds
+ *
+ * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+ * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+ * 
+ *
+ * Macros defined in this file:
+ *    KHRONOS_APICALL
+ *    KHRONOS_APIENTRY
+ *    KHRONOS_APIATTRIBUTES
+ * These may be used in function prototypes as:
+ *      KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
+ *                                  int arg1,
+ *                                  int arg2) KHRONOS_APIATTRIBUTES;
+ */
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APICALL
+ *-------------------------------------------------------------------------
+ * This precedes the return type of the function in the function prototype.
+ */
+#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
+#   define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+#   define KHRONOS_APICALL IMPORT_C
+#else
+#   define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIENTRY
+ *-------------------------------------------------------------------------
+ * This follows the return type of the function  and precedes the function
+ * name in the function prototype.
+ */
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
+    /* Win32 but not WinCE */
+#   define KHRONOS_APIENTRY __stdcall
+#else
+#   define KHRONOS_APIENTRY
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIATTRIBUTES
+ *-------------------------------------------------------------------------
+ * This follows the closing parenthesis of the function prototype arguments.
+ */
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+ * basic type definitions
+ *-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+ * Using <stdint.h>
+ */
+#include <stdint.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+ * Using <inttypes.h>
+ */
+#include <inttypes.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+ * Win32
+ */
+typedef __int32                 khronos_int32_t;
+typedef unsigned __int32        khronos_uint32_t;
+typedef __int64                 khronos_int64_t;
+typedef unsigned __int64        khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+ * Sun or Digital
+ */
+typedef int                     khronos_int32_t;
+typedef unsigned int            khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int                khronos_int64_t;
+typedef unsigned long int       khronos_uint64_t;
+#else
+typedef long long int           khronos_int64_t;
+typedef unsigned long long int  khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif 0
+
+/*
+ * Hypothetical platform with no float or int64 support
+ */
+typedef int                     khronos_int32_t;
+typedef unsigned int            khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64   0
+#define KHRONOS_SUPPORT_FLOAT   0
+
+#else
+
+/*
+ * Generic fallback
+ */
+#include <stdint.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#endif
+
+
+/*
+ * Types that are (so far) the same on all platforms
+ */
+typedef signed   char          khronos_int8_t;
+typedef unsigned char          khronos_uint8_t;
+typedef signed   short int     khronos_int16_t;
+typedef unsigned short int     khronos_uint16_t;
+typedef signed   long  int     khronos_intptr_t;
+typedef unsigned long  int     khronos_uintptr_t;
+typedef signed   long  int     khronos_ssize_t;
+typedef unsigned long  int     khronos_usize_t;
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+ * Float type
+ */
+typedef          float         khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+ *
+ * These types can be used to represent a time interval in nanoseconds or 
+ * an absolute Unadjusted System Time.  Unadjusted System Time is the number 
+ * of nanoseconds since some arbitrary system event (e.g. since the last 
+ * time the system booted).  The Unadjusted System Time is an unsigned 
+ * 64 bit value that wraps back to 0 every 584 years.  Time intervals 
+ * may be either signed or unsigned.
+ */
+typedef khronos_uint64_t       khronos_utime_nanoseconds_t;
+typedef khronos_int64_t        khronos_stime_nanoseconds_t;
+#endif
+
+
+#endif /* __khrplatform_h_ */
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
new file mode 100644
index 0000000..99efe4c
--- /dev/null
+++ b/opengl/libagl/Android.mk
@@ -0,0 +1,39 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Build the software OpenGL ES library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	egl.cpp                     \
+	state.cpp		            \
+	texture.cpp		            \
+    Tokenizer.cpp               \
+    TokenManager.cpp            \
+    TextureObjectManager.cpp    \
+    BufferObjectManager.cpp     \
+	array.cpp.arm		        \
+	fp.cpp.arm		            \
+	light.cpp.arm		        \
+	matrix.cpp.arm		        \
+	mipmap.cpp.arm		        \
+	primitives.cpp.arm	        \
+	vertex.cpp.arm
+
+ifeq ($(TARGET_ARCH),arm)
+	LOCAL_SRC_FILES += fixed_asm.S iterators.S
+	LOCAL_CFLAGS += -fstrict-aliasing
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+    # we need to access the private Bionic header <bionic_tls.h>
+    LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+endif
+
+LOCAL_SHARED_LIBRARIES := libcutils libutils libpixelflinger
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libagl
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libagl/BufferObjectManager.cpp b/opengl/libagl/BufferObjectManager.cpp
new file mode 100644
index 0000000..6bf28ee
--- /dev/null
+++ b/opengl/libagl/BufferObjectManager.cpp
@@ -0,0 +1,103 @@
+/*
+ ** Copyright 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 <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Errors.h>
+
+#include <GLES/gl.h>
+
+#include "BufferObjectManager.h"
+
+
+namespace android {
+
+using namespace gl;
+
+// ----------------------------------------------------------------------------
+
+EGLBufferObjectManager::EGLBufferObjectManager() 
+: TokenManager(), mCount(0)
+{
+}
+
+EGLBufferObjectManager::~EGLBufferObjectManager()
+{
+    // destroy all the buffer objects and their storage
+    GLsizei n = mBuffers.size();
+    for (GLsizei i=0 ; i<n ; i++) {
+        buffer_t* bo = mBuffers.valueAt(i);
+        free(bo->data);
+        delete bo;
+    }
+}
+
+buffer_t const* EGLBufferObjectManager::bind(GLuint buffer)
+{
+    Mutex::Autolock _l(mLock);
+    int32_t i = mBuffers.indexOfKey(buffer);
+    if (i >= 0) {
+        return mBuffers.valueAt(i);
+    }
+    buffer_t* bo = new buffer_t;
+    bo->data = 0;
+    bo->usage = GL_STATIC_DRAW;
+    bo->size = 0;
+    bo->name = buffer;
+    mBuffers.add(buffer, bo);
+    return bo;
+}
+
+int EGLBufferObjectManager::allocateStore(buffer_t* bo,
+        GLsizeiptr size, GLenum usage)
+{
+    Mutex::Autolock _l(mLock);
+    if (size != bo->size) {
+       uint8_t* data = (uint8_t*)malloc(size);
+        if (data == 0)
+            return -1;
+        free(bo->data);
+        bo->data = data;
+        bo->size = size;
+    }
+    bo->usage = usage;
+    return 0;
+}
+
+void EGLBufferObjectManager::deleteBuffers(GLsizei n, const GLuint* buffers)
+{
+    Mutex::Autolock _l(mLock);
+    while (n--) {
+        const GLuint t = *buffers++;
+        if (t) {
+            int32_t index = mBuffers.indexOfKey(t);
+            if (index >= 0) {
+                buffer_t* bo = mBuffers.valueAt(index);
+                free(bo->data);
+                mBuffers.removeItemsAt(index);
+                delete bo;
+            }
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/opengl/libagl/BufferObjectManager.h b/opengl/libagl/BufferObjectManager.h
new file mode 100644
index 0000000..9e9340a
--- /dev/null
+++ b/opengl/libagl/BufferObjectManager.h
@@ -0,0 +1,85 @@
+/*
+ **
+ ** Copyright 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.
+ */
+
+#ifndef ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H
+#define ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Errors.h>
+
+#include <GLES/gl.h>
+
+#include "Tokenizer.h"
+#include "TokenManager.h"
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+namespace gl {
+
+struct buffer_t {
+    GLsizeiptr      size;
+    GLenum          usage;
+    uint8_t*        data;
+    uint32_t        name;
+};
+
+};
+
+class EGLBufferObjectManager : public TokenManager
+{
+public:
+    EGLBufferObjectManager();
+    ~EGLBufferObjectManager();
+
+    // protocol for sp<>
+    inline  void    incStrong(const void* id) const;
+    inline  void    decStrong(const void* id) const;
+    typedef void    weakref_type;
+
+    gl::buffer_t const* bind(GLuint buffer);
+    int                 allocateStore(gl::buffer_t* bo, GLsizeiptr size, GLenum usage);
+    void                deleteBuffers(GLsizei n, const GLuint* buffers);
+
+private:
+    mutable volatile int32_t            mCount;
+    mutable Mutex                       mLock;
+    KeyedVector<GLuint, gl::buffer_t*>  mBuffers;
+};
+
+void EGLBufferObjectManager::incStrong(const void* id) const {
+    android_atomic_inc(&mCount);
+}
+void EGLBufferObjectManager::decStrong(const void* id) const {
+    if (android_atomic_dec(&mCount) == 1) {
+        delete this;
+    }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H
+
diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp
new file mode 100644
index 0000000..ce31854
--- /dev/null
+++ b/opengl/libagl/TextureObjectManager.cpp
@@ -0,0 +1,309 @@
+/*
+ ** Copyright 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 <stdlib.h>
+#include "context.h"
+#include "TextureObjectManager.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+EGLTextureObject::EGLTextureObject()
+    : mCount(0), mSize(0)
+{
+    init();
+}
+
+EGLTextureObject::~EGLTextureObject()
+{
+    if (!direct) {
+        if (mSize && surface.data)
+            free(surface.data);
+        if (mMipmaps)
+            freeMipmaps();
+    }
+}
+
+void EGLTextureObject::init()
+{
+    memset(&surface, 0, sizeof(surface));
+    surface.version = sizeof(surface);
+    mMipmaps = 0;
+    mNumExtraLod = 0;
+    mIsComplete = false;
+    wraps = GL_REPEAT;
+    wrapt = GL_REPEAT;
+    min_filter = GL_LINEAR;
+    mag_filter = GL_LINEAR;
+    internalformat = 0;
+    memset(crop_rect, 0, sizeof(crop_rect));
+    generate_mipmap = GL_FALSE;
+    direct = GL_FALSE;
+}
+
+void EGLTextureObject::copyParameters(const sp<EGLTextureObject>& old)
+{
+    wraps = old->wraps;
+    wrapt = old->wrapt;
+    min_filter = old->min_filter;
+    mag_filter = old->mag_filter;
+    memcpy(crop_rect, old->crop_rect, sizeof(crop_rect));
+    generate_mipmap = old->generate_mipmap;
+    direct = old->direct;
+}
+
+status_t EGLTextureObject::allocateMipmaps()
+{
+    // here, by construction, mMipmaps=0 && mNumExtraLod=0
+
+    if (!surface.data)
+        return NO_INIT;
+
+    int w = surface.width;
+    int h = surface.height;
+    const int numLods = 31 - gglClz(max(w,h));
+    if (numLods <= 0)
+        return NO_ERROR;
+
+    mMipmaps = (GGLSurface*)malloc(numLods * sizeof(GGLSurface));
+    if (!mMipmaps)
+        return NO_MEMORY;
+
+    memset(mMipmaps, 0, numLods * sizeof(GGLSurface));
+    mNumExtraLod = numLods;
+    return NO_ERROR;
+}
+
+void EGLTextureObject::freeMipmaps()
+{
+    if (mMipmaps) {
+        for (int i=0 ; i<mNumExtraLod ; i++) {
+            if (mMipmaps[i].data) {
+                free(mMipmaps[i].data);
+            }
+        }
+        free(mMipmaps);
+        mMipmaps = 0;
+        mNumExtraLod = 0;
+    }
+}
+
+const GGLSurface& EGLTextureObject::mip(int lod) const
+{
+    if (lod<=0 || !mMipmaps)
+        return surface;
+    lod = min(lod-1, mNumExtraLod-1);
+    return mMipmaps[lod];
+}
+
+GGLSurface& EGLTextureObject::editMip(int lod)
+{
+    return const_cast<GGLSurface&>(mip(lod));
+}
+
+status_t EGLTextureObject::setSurface(GGLSurface const* s)
+{
+    // XXX: glFlush() on 's'
+    if (mSize && surface.data) {
+        free(surface.data);
+    }
+    surface = *s;
+    internalformat = 0;
+
+    // we should keep the crop_rect, but it's delicate because
+    // the new size of the surface could make it invalid.
+    // so for now, we just loose it.
+    memset(crop_rect, 0, sizeof(crop_rect));
+
+    // it would be nice if we could keep the generate_mipmap flag,
+    // we would have to generate them right now though.
+    generate_mipmap = GL_FALSE;
+
+    direct = GL_TRUE;
+    mSize = 0;  // we don't own this surface
+    if (mMipmaps)
+        freeMipmaps();
+    mIsComplete = true;
+    return NO_ERROR;
+}
+
+status_t EGLTextureObject::reallocate(
+        GLint level, int w, int h, int s,
+        int format, int compressedFormat, int bpr)
+{
+    const size_t size = h * bpr;
+    if (level == 0) 
+    {
+        if (size!=mSize || !surface.data) {
+            if (mSize && surface.data) {
+                free(surface.data);
+            }
+            surface.data = (GGLubyte*)malloc(size);
+            if (!surface.data) {
+                mSize = 0;
+                mIsComplete = false;
+                return NO_MEMORY;
+            }
+            mSize = size;
+        }
+        surface.version = sizeof(GGLSurface);
+        surface.width  = w;
+        surface.height = h;
+        surface.stride = s;
+        surface.format = format;
+        surface.compressedFormat = compressedFormat;
+        if (mMipmaps)
+            freeMipmaps();
+        mIsComplete = true;
+    }
+    else
+    {
+        if (!mMipmaps) {
+            if (allocateMipmaps() != NO_ERROR)
+                return NO_MEMORY;
+        }
+
+        LOGW_IF(level-1 >= mNumExtraLod, 
+                "specifying mipmap level %d, but # of level is %d",
+                level, mNumExtraLod+1);        
+
+        GGLSurface& mipmap = editMip(level);
+        if (mipmap.data)
+            free(mipmap.data);
+
+        mipmap.data = (GGLubyte*)malloc(size);
+        if (!mipmap.data) {
+            memset(&mipmap, 0, sizeof(GGLSurface));
+            mIsComplete = false;
+            return NO_MEMORY;
+        }
+
+        mipmap.version = sizeof(GGLSurface);
+        mipmap.width  = w;
+        mipmap.height = h;
+        mipmap.stride = s;
+        mipmap.format = format;
+        mipmap.compressedFormat = compressedFormat;
+
+        // check if the texture is complete
+        mIsComplete = true;
+        const GGLSurface* prev = &surface;
+        for (int i=0 ; i<mNumExtraLod ; i++) {
+            const GGLSurface* curr = mMipmaps + i;
+            if (curr->format != surface.format) {
+                mIsComplete = false;
+                break;
+            }
+
+            uint32_t w = (prev->width  >> 1) ? : 1;
+            uint32_t h = (prev->height >> 1) ? : 1;
+            if (w != curr->width || h != curr->height) {
+                mIsComplete = false;
+                break;
+            }
+            prev = curr;
+        }
+    }
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+EGLSurfaceManager::EGLSurfaceManager()
+    : TokenManager(), mCount(0)
+{
+}
+
+EGLSurfaceManager::~EGLSurfaceManager()
+{
+    // everything gets freed automatically here...
+}
+
+sp<EGLTextureObject> EGLSurfaceManager::createTexture(GLuint name)
+{
+    sp<EGLTextureObject> result;
+
+    Mutex::Autolock _l(mLock);
+    if (mTextures.indexOfKey(name) >= 0)
+        return result; // already exists!
+
+    result = new EGLTextureObject();
+
+    status_t err = mTextures.add(name, result);
+    if (err < 0)
+        result.clear();
+
+    return result;
+}
+
+sp<EGLTextureObject> EGLSurfaceManager::removeTexture(GLuint name)
+{
+    Mutex::Autolock _l(mLock);
+    const ssize_t index = mTextures.indexOfKey(name);
+    if (index >= 0) {
+        sp<EGLTextureObject> result(mTextures.valueAt(index));
+        mTextures.removeItemsAt(index);
+        return result;
+    }
+    return 0;
+}
+
+sp<EGLTextureObject> EGLSurfaceManager::replaceTexture(GLuint name)
+{
+    sp<EGLTextureObject> tex;
+    Mutex::Autolock _l(mLock);
+    const ssize_t index = mTextures.indexOfKey(name);
+    if (index >= 0) {
+        const sp<EGLTextureObject>& old = mTextures.valueAt(index);
+        const uint32_t refs = old->getStrongCount();
+        if (ggl_likely(refs == 1)) {
+            // we're the only owner
+            tex = old;
+        } else {
+            // keep the texture's parameters
+            tex = new EGLTextureObject();
+            tex->copyParameters(old);
+            mTextures.removeItemsAt(index);
+            mTextures.add(name, tex);
+        }
+    }
+    return tex;
+}
+
+void EGLSurfaceManager::deleteTextures(GLsizei n, const GLuint *tokens)
+{
+    // free all textures
+    Mutex::Autolock _l(mLock);
+    for (GLsizei i=0 ; i<n ; i++) {
+        const GLuint t(*tokens++);
+        if (t) {
+            mTextures.removeItem(t);
+        }
+    }
+}
+
+sp<EGLTextureObject> EGLSurfaceManager::texture(GLuint name)
+{
+    Mutex::Autolock _l(mLock);
+    const ssize_t index = mTextures.indexOfKey(name);
+    if (index >= 0)
+        return mTextures.valueAt(index);
+    return 0;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h
new file mode 100644
index 0000000..74ed1a4
--- /dev/null
+++ b/opengl/libagl/TextureObjectManager.h
@@ -0,0 +1,140 @@
+/*
+** Copyright 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.
+*/
+
+#ifndef ANDROID_OPENGLES_SURFACE_H
+#define ANDROID_OPENGLES_SURFACE_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <utils/threads.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Errors.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+#include "Tokenizer.h"
+#include "TokenManager.h"
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class EGLTextureObject
+{
+public:
+                    EGLTextureObject();
+                   ~EGLTextureObject();
+
+    // protocol for sp<>
+    inline  void        incStrong(const void* id) const;
+    inline  void        decStrong(const void* id) const;
+    inline  uint32_t    getStrongCount() const;
+
+    status_t            setSurface(GGLSurface const* s);
+    status_t            reallocate(GLint level,
+                            int w, int h, int s,
+                            int format, int compressedFormat, int bpr);
+    inline  size_t      size() const;
+    const GGLSurface&   mip(int lod) const;
+    GGLSurface&         editMip(int lod);
+    bool                hasMipmaps() const { return mMipmaps!=0; }
+    bool                isComplete() const { return mIsComplete; }
+    void                copyParameters(const sp<EGLTextureObject>& old);
+
+private:
+        status_t        allocateMipmaps();
+            void        freeMipmaps();
+            void        init();
+    mutable int32_t     mCount;
+    size_t              mSize;
+    GGLSurface          *mMipmaps;
+    int                 mNumExtraLod;
+    bool                mIsComplete;
+
+public:
+    GGLSurface          surface;
+    GLenum              wraps;
+    GLenum              wrapt;
+    GLenum              min_filter;
+    GLenum              mag_filter;
+    GLenum              internalformat;
+    GLint               crop_rect[4];
+    GLint               generate_mipmap;
+    GLint               direct;
+};
+
+void EGLTextureObject::incStrong(const void* id) const {
+    android_atomic_inc(&mCount);
+}
+void EGLTextureObject::decStrong(const void* id) const {
+    if (android_atomic_dec(&mCount) == 1) {
+        delete this;
+    }
+}
+uint32_t EGLTextureObject::getStrongCount() const {
+    return mCount;
+}
+size_t EGLTextureObject::size() const {
+    return mSize;
+}
+
+// ----------------------------------------------------------------------------
+
+class EGLSurfaceManager : public TokenManager
+{
+public:
+                EGLSurfaceManager();
+                ~EGLSurfaceManager();
+
+    // protocol for sp<>
+    inline  void    incStrong(const void* id) const;
+    inline  void    decStrong(const void* id) const;
+    typedef void    weakref_type;
+
+    sp<EGLTextureObject>    createTexture(GLuint name);
+    sp<EGLTextureObject>    removeTexture(GLuint name);
+    sp<EGLTextureObject>    replaceTexture(GLuint name);
+    void                    deleteTextures(GLsizei n, const GLuint *tokens);
+    sp<EGLTextureObject>    texture(GLuint name);
+
+private:
+    mutable int32_t                             mCount;
+    mutable Mutex                               mLock;
+    KeyedVector< GLuint, sp<EGLTextureObject> > mTextures;
+};
+
+void EGLSurfaceManager::incStrong(const void* id) const {
+    android_atomic_inc(&mCount);
+}
+void EGLSurfaceManager::decStrong(const void* id) const {
+    if (android_atomic_dec(&mCount) == 1) {
+        delete this;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_SURFACE_H
+
diff --git a/opengl/libagl/TokenManager.cpp b/opengl/libagl/TokenManager.cpp
new file mode 100644
index 0000000..eea6025
--- /dev/null
+++ b/opengl/libagl/TokenManager.cpp
@@ -0,0 +1,62 @@
+/* libs/opengles/surface.cpp
+**
+** Copyright 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 <stdlib.h>
+#include "TokenManager.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+TokenManager::TokenManager()
+{
+    // token 0 is always reserved
+    mTokenizer.reserve(0);
+}
+
+TokenManager::~TokenManager()
+{
+}
+
+status_t TokenManager::getToken(GLsizei n, GLuint *tokens)
+{
+    Mutex::Autolock _l(mLock);
+    for (GLsizei i=0 ; i<n ; i++)
+        *tokens++ = mTokenizer.acquire();
+    return NO_ERROR;
+}
+
+void TokenManager::recycleTokens(GLsizei n, const GLuint *tokens)
+{
+    Mutex::Autolock _l(mLock);
+    for (int i=0 ; i<n ; i++) {
+        const GLuint token = *tokens++;
+        if (token) {
+            mTokenizer.release(token);
+        }
+    }
+}
+
+bool TokenManager::isTokenValid(GLuint token) const
+{
+    Mutex::Autolock _l(mLock);
+    return mTokenizer.isAcquired(token);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/opengl/libagl/TokenManager.h b/opengl/libagl/TokenManager.h
new file mode 100644
index 0000000..49c1469
--- /dev/null
+++ b/opengl/libagl/TokenManager.h
@@ -0,0 +1,53 @@
+/*
+** Copyright 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.
+*/
+
+#ifndef ANDROID_OPENGLES_TOKEN_MANAGER_H
+#define ANDROID_OPENGLES_TOKEN_MANAGER_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <GLES/gl.h>
+
+#include "Tokenizer.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class TokenManager
+{
+public:
+                TokenManager();
+                ~TokenManager();
+
+    status_t    getToken(GLsizei n, GLuint *tokens);
+    void        recycleTokens(GLsizei n, const GLuint *tokens);
+    bool        isTokenValid(GLuint token) const;
+
+private:
+    mutable Mutex   mLock;
+    Tokenizer       mTokenizer;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_TOKEN_MANAGER_H
+
diff --git a/opengl/libagl/Tokenizer.cpp b/opengl/libagl/Tokenizer.cpp
new file mode 100644
index 0000000..9b3ea1a
--- /dev/null
+++ b/opengl/libagl/Tokenizer.cpp
@@ -0,0 +1,173 @@
+/* libs/opengles/Tokenizer.cpp
+**
+** Copyright 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 "Tokenizer.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+ANDROID_BASIC_TYPES_TRAITS(Tokenizer::run_t)
+
+Tokenizer::Tokenizer()
+{
+}
+
+Tokenizer::Tokenizer(const Tokenizer& other)
+    : mRanges(other.mRanges)
+{
+}
+
+Tokenizer::~Tokenizer()
+{
+}
+
+uint32_t Tokenizer::acquire()
+{
+    if (!mRanges.size() || mRanges[0].first) {
+        _insertTokenAt(0,0);
+        return 0;
+    }
+    
+    // just extend the first run
+    const run_t& run = mRanges[0];
+    uint32_t token = run.first + run.length;
+    _insertTokenAt(token, 1);
+    return token;
+}
+
+bool Tokenizer::isAcquired(uint32_t token) const
+{
+    return (_indexOrderOf(token) >= 0);
+}
+
+status_t Tokenizer::reserve(uint32_t token)
+{
+    size_t o;
+    const ssize_t i = _indexOrderOf(token, &o);
+    if (i >= 0) {
+        return BAD_VALUE; // this token is already taken
+    }
+    ssize_t err = _insertTokenAt(token, o);
+    return (err<0) ? err : status_t(NO_ERROR);
+}
+
+status_t Tokenizer::release(uint32_t token)
+{
+    const ssize_t i = _indexOrderOf(token);
+    if (i >= 0) {
+        const run_t& run = mRanges[i];
+        if ((token >= run.first) && (token < run.first+run.length)) {
+            // token in this range, we need to split
+            run_t& run = mRanges.editItemAt(i);
+            if ((token == run.first) || (token == run.first+run.length-1)) {
+                if (token == run.first) {
+                    run.first += 1;
+                }
+                run.length -= 1;
+                if (run.length == 0) {
+                    // XXX: should we systematically remove a run that's empty?
+                    mRanges.removeItemsAt(i);
+                }
+            } else {
+                // split the run
+                run_t new_run;
+                new_run.first = token+1;
+                new_run.length = run.first+run.length - new_run.first;
+                run.length = token - run.first;
+                mRanges.insertAt(new_run, i+1);
+            }
+            return NO_ERROR;
+        }
+    }
+    return NAME_NOT_FOUND;
+}
+
+ssize_t Tokenizer::_indexOrderOf(uint32_t token, size_t* order) const
+{
+    // binary search
+    ssize_t err = NAME_NOT_FOUND;
+    ssize_t l = 0;
+    ssize_t h = mRanges.size()-1;
+    ssize_t mid;
+    const run_t* a = mRanges.array();
+    while (l <= h) {
+        mid = l + (h - l)/2;
+        const run_t* const curr = a + mid;
+        int c = 0;
+        if (token < curr->first)                        c = 1;
+        else if (token >= curr->first+curr->length)     c = -1;
+        if (c == 0) {
+            err = l = mid;
+            break;
+        } else if (c < 0) {
+            l = mid + 1;
+        } else {
+            h = mid - 1;
+        }
+    }
+    if (order) *order = l;
+    return err;
+}
+
+ssize_t Tokenizer::_insertTokenAt(uint32_t token, size_t index)
+{
+    const size_t c = mRanges.size();
+
+    if (index >= 1) {
+        // do we need to merge with the previous run?
+        run_t& p = mRanges.editItemAt(index-1);
+        if (p.first+p.length == token) {
+            p.length += 1;
+            if (index < c) {
+                const run_t& n = mRanges[index];
+                if (token+1 == n.first) {
+                    p.length += n.length;
+                    mRanges.removeItemsAt(index);
+                }
+            }
+            return index;
+        }
+    }
+    
+    if (index < c) {
+        // do we need to merge with the next run?
+        run_t& n = mRanges.editItemAt(index);
+        if (token+1 == n.first) {
+            n.first -= 1;
+            n.length += 1;
+            return index;
+        }
+    }
+
+    return mRanges.insertAt(run_t(token,1), index);
+}
+
+void Tokenizer::dump() const
+{
+    const run_t* ranges = mRanges.array();
+    const size_t c = mRanges.size();
+    LOGD("Tokenizer (%p, size = %u)\n", this, c);
+    for (size_t i=0 ; i<c ; i++) {
+        LOGD("%u: (%u, %u)\n", i, ranges[i].first, ranges[i].length);
+    }
+}
+
+}; // namespace android
+
diff --git a/opengl/libagl/Tokenizer.h b/opengl/libagl/Tokenizer.h
new file mode 100644
index 0000000..ac555cb
--- /dev/null
+++ b/opengl/libagl/Tokenizer.h
@@ -0,0 +1,59 @@
+/* libs/opengles/Tokenizer.h
+**
+** Copyright 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.
+*/
+
+
+#ifndef ANDROID_OPENGLES_TOKENIZER_H
+#define ANDROID_OPENGLES_TOKENIZER_H
+
+#include <utils/Vector.h>
+#include <utils/Errors.h>
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+class Tokenizer
+{
+public:
+                Tokenizer();
+                Tokenizer(const Tokenizer& other);
+                ~Tokenizer();
+
+    uint32_t    acquire();
+    status_t    reserve(uint32_t token);
+    status_t    release(uint32_t token);
+    bool        isAcquired(uint32_t token) const;
+
+    void dump() const;
+
+    struct run_t {
+        run_t() {};
+        run_t(uint32_t f, uint32_t l) : first(f), length(l) {}
+        uint32_t    first;
+        uint32_t    length;
+    };
+private:
+    ssize_t _indexOrderOf(uint32_t token, size_t* order=0) const;
+    ssize_t _insertTokenAt(uint32_t token, size_t index);
+    Vector<run_t>   mRanges;
+};
+
+}; // namespace android
+
+// ----------------------------------------------------------------------------
+
+#endif // ANDROID_OPENGLES_TOKENIZER_H
diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp
new file mode 100644
index 0000000..8fa7566
--- /dev/null
+++ b/opengl/libagl/array.cpp
@@ -0,0 +1,1557 @@
+/* 
+** Copyright 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 <stdlib.h>
+#include <stdio.h>
+
+#include "context.h"
+#include "fp.h"
+#include "state.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "light.h"
+#include "primitives.h"
+#include "texture.h"
+#include "BufferObjectManager.h"
+
+// ----------------------------------------------------------------------------
+
+#define VC_CACHE_STATISTICS     0
+#define VC_CACHE_TYPE_NONE      0
+#define VC_CACHE_TYPE_INDEXED   1
+#define VC_CACHE_TYPE_LRU       2
+#define VC_CACHE_TYPE           VC_CACHE_TYPE_INDEXED
+
+#if VC_CACHE_STATISTICS
+#include <utils/Timers.h>
+#endif
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static void validate_arrays(ogles_context_t* c, GLenum mode);
+
+static void compileElements__generic(ogles_context_t*,
+        vertex_t*, GLint, GLsizei);
+static void compileElement__generic(ogles_context_t*,
+        vertex_t*, GLint);
+
+static void drawPrimitivesPoints(ogles_context_t*, GLint, GLsizei);
+static void drawPrimitivesLineStrip(ogles_context_t*, GLint, GLsizei);
+static void drawPrimitivesLineLoop(ogles_context_t*, GLint, GLsizei);
+static void drawPrimitivesLines(ogles_context_t*, GLint, GLsizei);
+static void drawPrimitivesTriangleStrip(ogles_context_t*, GLint, GLsizei);
+static void drawPrimitivesTriangleFan(ogles_context_t*, GLint, GLsizei);
+static void drawPrimitivesTriangles(ogles_context_t*, GLint, GLsizei);
+
+static void drawIndexedPrimitivesPoints(ogles_context_t*,
+        GLsizei, const GLvoid*);
+static void drawIndexedPrimitivesLineStrip(ogles_context_t*,
+        GLsizei, const GLvoid*);
+static void drawIndexedPrimitivesLineLoop(ogles_context_t*,
+        GLsizei, const GLvoid*);
+static void drawIndexedPrimitivesLines(ogles_context_t*,
+        GLsizei, const GLvoid*);
+static void drawIndexedPrimitivesTriangleStrip(ogles_context_t*,
+        GLsizei, const GLvoid*);
+static void drawIndexedPrimitivesTriangleFan(ogles_context_t*,
+        GLsizei, const GLvoid*);
+static void drawIndexedPrimitivesTriangles(ogles_context_t*,
+        GLsizei, const GLvoid*);
+
+// ----------------------------------------------------------------------------
+
+typedef void (*arrays_prims_fct_t)(ogles_context_t*, GLint, GLsizei);
+static const arrays_prims_fct_t drawArraysPrims[] = {
+    drawPrimitivesPoints,
+    drawPrimitivesLines,
+    drawPrimitivesLineLoop,
+    drawPrimitivesLineStrip,
+    drawPrimitivesTriangles,
+    drawPrimitivesTriangleStrip,
+    drawPrimitivesTriangleFan
+};
+
+typedef void (*elements_prims_fct_t)(ogles_context_t*, GLsizei, const GLvoid*);
+static const elements_prims_fct_t drawElementsPrims[] = {
+    drawIndexedPrimitivesPoints,
+    drawIndexedPrimitivesLines,
+    drawIndexedPrimitivesLineLoop,
+    drawIndexedPrimitivesLineStrip,
+    drawIndexedPrimitivesTriangles,
+    drawIndexedPrimitivesTriangleStrip,
+    drawIndexedPrimitivesTriangleFan
+};
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void ogles_init_array(ogles_context_t* c)
+{
+    c->arrays.vertex.size = 4;
+    c->arrays.vertex.type = GL_FLOAT;
+    c->arrays.color.size = 4;
+    c->arrays.color.type = GL_FLOAT;
+    c->arrays.normal.size = 4;
+    c->arrays.normal.type = GL_FLOAT;
+    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+        c->arrays.texture[i].size = 4;
+        c->arrays.texture[i].type = GL_FLOAT;
+    }
+    c->vc.init();
+
+    if (!c->vc.vBuffer) {
+        // this could have failed
+        ogles_error(c, GL_OUT_OF_MEMORY);
+    }
+}
+
+void ogles_uninit_array(ogles_context_t* c)
+{
+    c->vc.uninit();
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Array fetchers
+#endif
+
+static void currentColor(ogles_context_t* c, GLfixed* v, const GLvoid*) {
+    memcpy(v, c->current.color.v, sizeof(vec4_t));
+}
+static void currentColor_clamp(ogles_context_t* c, GLfixed* v, const GLvoid*) {
+    memcpy(v, c->currentColorClamped.v, sizeof(vec4_t));
+}
+static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) {
+    memcpy(v, c->currentNormal.v, sizeof(vec3_t));
+}
+static void currentTexCoord(ogles_context_t* c, GLfixed* v, const GLvoid*) {
+    memcpy(v, c->current.texture[c->arrays.tmu].v, sizeof(vec4_t));
+}
+
+
+static void fetchNop(ogles_context_t*, GLfixed*, const GLvoid*) {
+}
+static void fetch2b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
+    v[0] = gglIntToFixed(p[0]);
+    v[1] = gglIntToFixed(p[1]);
+}
+static void fetch2s(ogles_context_t*, GLfixed* v, const GLshort* p) {
+    v[0] = gglIntToFixed(p[0]);
+    v[1] = gglIntToFixed(p[1]);
+}
+static void fetch2x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
+    memcpy(v, p, 2*sizeof(GLfixed));
+}
+static void fetch2f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
+    v[0] = gglFloatToFixed(p[0]);
+    v[1] = gglFloatToFixed(p[1]);
+}
+static void fetch3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
+    v[0] = gglIntToFixed(p[0]);
+    v[1] = gglIntToFixed(p[1]);
+    v[2] = gglIntToFixed(p[2]);
+}
+static void fetch3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
+    v[0] = gglIntToFixed(p[0]);
+    v[1] = gglIntToFixed(p[1]);
+    v[2] = gglIntToFixed(p[2]);
+}
+static void fetch3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
+    memcpy(v, p, 3*sizeof(GLfixed));
+}
+static void fetch3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
+    v[0] = gglFloatToFixed(p[0]);
+    v[1] = gglFloatToFixed(p[1]);
+    v[2] = gglFloatToFixed(p[2]);
+}
+static void fetch4b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
+    v[0] = gglIntToFixed(p[0]);
+    v[1] = gglIntToFixed(p[1]);
+    v[2] = gglIntToFixed(p[2]);
+    v[3] = gglIntToFixed(p[3]);
+}
+static void fetch4s(ogles_context_t*, GLfixed* v, const GLshort* p) {
+    v[0] = gglIntToFixed(p[0]);
+    v[1] = gglIntToFixed(p[1]);
+    v[2] = gglIntToFixed(p[2]);
+    v[3] = gglIntToFixed(p[3]);
+}
+static void fetch4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
+    memcpy(v, p, 4*sizeof(GLfixed));
+}
+static void fetch4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
+    v[0] = gglFloatToFixed(p[0]);
+    v[1] = gglFloatToFixed(p[1]);
+    v[2] = gglFloatToFixed(p[2]);
+    v[3] = gglFloatToFixed(p[3]);
+}
+static void fetchExpand4ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
+    v[0] = GGL_UB_TO_X(p[0]);
+    v[1] = GGL_UB_TO_X(p[1]);
+    v[2] = GGL_UB_TO_X(p[2]);
+    v[3] = GGL_UB_TO_X(p[3]);
+}
+static void fetchClamp4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
+    v[0] = gglClampx(p[0]);
+    v[1] = gglClampx(p[1]);
+    v[2] = gglClampx(p[2]);
+    v[3] = gglClampx(p[3]);
+}
+static void fetchClamp4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
+    v[0] = gglClampx(gglFloatToFixed(p[0]));
+    v[1] = gglClampx(gglFloatToFixed(p[1]));
+    v[2] = gglClampx(gglFloatToFixed(p[2]));
+    v[3] = gglClampx(gglFloatToFixed(p[3]));
+}
+static void fetchExpand3ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
+    v[0] = GGL_UB_TO_X(p[0]);
+    v[1] = GGL_UB_TO_X(p[1]);
+    v[2] = GGL_UB_TO_X(p[2]);
+    v[3] = 0x10000;
+}
+static void fetchClamp3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
+    v[0] = gglClampx(p[0]);
+    v[1] = gglClampx(p[1]);
+    v[2] = gglClampx(p[2]);
+    v[3] = 0x10000;
+}
+static void fetchClamp3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
+    v[0] = gglClampx(gglFloatToFixed(p[0]));
+    v[1] = gglClampx(gglFloatToFixed(p[1]));
+    v[2] = gglClampx(gglFloatToFixed(p[2]));
+    v[3] = 0x10000;
+}
+static void fetchExpand3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
+    v[0] = GGL_B_TO_X(p[0]);
+    v[1] = GGL_B_TO_X(p[1]);
+    v[2] = GGL_B_TO_X(p[2]);
+}
+static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
+    v[0] = GGL_S_TO_X(p[0]);
+    v[1] = GGL_S_TO_X(p[1]);
+    v[2] = GGL_S_TO_X(p[2]);
+}
+
+typedef array_t::fetcher_t fn_t; 
+
+static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x}
+    { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
+         (fn_t)fetch3f, 0, 0, 0, 0, 0,
+         (fn_t)fetch3x },
+    { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
+         (fn_t)fetch4f, 0, 0, 0, 0, 0,
+         (fn_t)fetch4x },
+};
+static const fn_t color_clamp_fct[2][16] = { // size={3,4}, type={ub,f,x}
+    { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
+         (fn_t)fetchClamp3f, 0, 0, 0, 0, 0,
+         (fn_t)fetchClamp3x },
+    { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
+         (fn_t)fetchClamp4f, 0, 0, 0, 0, 0,
+         (fn_t)fetchClamp4x },
+};
+static const fn_t normal_fct[1][16] = { // size={3}, type={b,s,f,x}
+    { (fn_t)fetchExpand3b, 0,
+      (fn_t)fetchExpand3s, 0, 0, 0,
+      (fn_t)fetch3f, 0, 0, 0, 0, 0,
+      (fn_t)fetch3x },
+};
+static const fn_t vertex_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
+    { (fn_t)fetch2b, 0,
+      (fn_t)fetch2s, 0, 0, 0,
+      (fn_t)fetch2f, 0, 0, 0, 0, 0,
+      (fn_t)fetch3x },
+    { (fn_t)fetch3b, 0,
+      (fn_t)fetch3s, 0, 0, 0,
+      (fn_t)fetch3f, 0, 0, 0, 0, 0,
+      (fn_t)fetch3x },
+    { (fn_t)fetch4b, 0,
+      (fn_t)fetch4s, 0, 0, 0,
+      (fn_t)fetch4f, 0, 0, 0, 0, 0,
+      (fn_t)fetch4x }
+};
+static const fn_t texture_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
+    { (fn_t)fetch2b, 0,
+      (fn_t)fetch2s, 0, 0, 0,
+      (fn_t)fetch2f, 0, 0, 0, 0, 0,
+      (fn_t)fetch2x },
+    { (fn_t)fetch3b, 0,
+      (fn_t)fetch3s, 0, 0, 0,
+      (fn_t)fetch3f, 0, 0, 0, 0, 0,
+      (fn_t)fetch3x },
+    { (fn_t)fetch4b, 0,
+      (fn_t)fetch4s, 0, 0, 0,
+      (fn_t)fetch4f, 0, 0, 0, 0, 0,
+      (fn_t)fetch4x }
+};
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark array_t
+#endif
+
+void array_t::init(
+        GLint size, GLenum type, GLsizei stride,
+        const GLvoid *pointer, const buffer_t* bo, GLsizei count)
+{
+    if (!stride) {
+        stride = size;
+        switch (type) {
+        case GL_SHORT:
+        case GL_UNSIGNED_SHORT:
+            stride *= 2;
+            break;
+        case GL_FLOAT:
+        case GL_FIXED:
+            stride *= 4;
+            break;
+        }
+    }
+    this->size = size;
+    this->type = type;
+    this->stride = stride;
+    this->pointer = pointer;
+    this->bo = bo;
+    this->bounds = count;
+}
+
+inline void array_t::resolve() 
+{
+    physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark vertex_cache_t
+#endif
+
+void vertex_cache_t::init()
+{
+    // make sure the size of vertex_t allows cache-line alignment
+    CTA<(sizeof(vertex_t) & 0x1F) == 0> assertAlignedSize;
+
+    const int align = 32;
+    const size_t s = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
+    const size_t size = s*sizeof(vertex_t) + align;
+    base = malloc(size);
+    if (base) {
+        memset(base, 0, size);
+        vBuffer = (vertex_t*)((size_t(base) + align - 1) & ~(align-1));
+        vCache = vBuffer + VERTEX_BUFFER_SIZE;
+        sequence = 0;
+    }
+}
+
+void vertex_cache_t::uninit()
+{
+    free(base);
+    base = vBuffer = vCache = 0;
+}
+
+void vertex_cache_t::clear()
+{
+#if VC_CACHE_STATISTICS
+    startTime = systemTime(SYSTEM_TIME_THREAD);
+    total = 0;
+    misses = 0;
+#endif
+
+#if VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
+    vertex_t* v = vBuffer;
+    size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
+    do {
+        v->mru = 0;
+        v++;
+    } while (--count);
+#endif
+
+    sequence += INDEX_SEQ;
+    if (sequence >= 0x80000000LU) {
+        sequence = INDEX_SEQ;
+        vertex_t* v = vBuffer;
+        size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
+        do {
+            v->index = 0;
+            v++;
+        } while (--count);
+    }
+}
+
+void vertex_cache_t::dump_stats(GLenum mode)
+{
+#if VC_CACHE_STATISTICS
+    nsecs_t time = systemTime(SYSTEM_TIME_THREAD) - startTime;
+    uint32_t hits = total - misses;
+    uint32_t prim_count;
+    switch (mode) {
+    case GL_POINTS:             prim_count = total;         break;
+    case GL_LINE_STRIP:         prim_count = total - 1;     break;
+    case GL_LINE_LOOP:          prim_count = total - 1;     break;
+    case GL_LINES:              prim_count = total / 2;     break;
+    case GL_TRIANGLE_STRIP:     prim_count = total - 2;     break;
+    case GL_TRIANGLE_FAN:       prim_count = total - 2;     break;
+    case GL_TRIANGLES:          prim_count = total / 3;     break;
+    default:    return;
+    }
+    printf( "total=%5u, hits=%5u, miss=%5u, hitrate=%3u%%,"
+            " prims=%5u, time=%6u us, prims/s=%d, v/t=%f\n",
+            total, hits, misses, (hits*100)/total,
+            prim_count, int(ns2us(time)), int(prim_count*float(seconds(1))/time),
+            float(misses) / prim_count);
+#endif
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+static __attribute__((noinline))
+void enableDisableClientState(ogles_context_t* c, GLenum array, bool enable)
+{
+    const int tmu = c->arrays.activeTexture;
+    array_t* a;
+    switch (array) {
+    case GL_COLOR_ARRAY:            a = &c->arrays.color;           break;
+    case GL_NORMAL_ARRAY:           a = &c->arrays.normal;          break;
+    case GL_TEXTURE_COORD_ARRAY:    a = &c->arrays.texture[tmu];    break;
+    case GL_VERTEX_ARRAY:           a = &c->arrays.vertex;          break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    a->enable = enable ? GL_TRUE : GL_FALSE;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Vertex Cache
+#endif
+
+static __attribute__((noinline))
+vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index)
+{
+    #if VC_CACHE_STATISTICS
+        c->vc.misses++;
+    #endif
+    if (ggl_unlikely(v->locked)) {
+        // we're just looking for an entry in the cache that is not locked.
+        // and we know that there cannot be more than 2 locked entries
+        // because a triangle needs at most 3 vertices.
+        // We never use the first and second entries because they might be in
+        // use by the striper or faner. Any other entry will do as long as
+        // it's not locked.
+        // We compute directly the index of a "free" entry from the locked
+        // state of v[2] and v[3].
+        v = c->vc.vBuffer + 2;
+        v += v[0].locked | (v[1].locked<<1);       
+    }
+    // note: compileElement clears v->flags
+    c->arrays.compileElement(c, v, index);
+    v->locked = 1;
+    return v;
+}
+
+static __attribute__((noinline))
+vertex_t* fetch_vertex(ogles_context_t* c, size_t index)
+{
+    index |= c->vc.sequence;
+
+#if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED
+
+    vertex_t* const v = c->vc.vCache + 
+            (index & (vertex_cache_t::VERTEX_CACHE_SIZE-1));
+
+    if (ggl_likely(v->index == index)) {
+        v->locked = 1;
+        return v;
+    }
+    return cache_vertex(c, v, index);
+
+#elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
+
+    vertex_t* v = c->vc.vCache + 
+            (index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2;
+
+    // always record LRU in v[0]
+    if (ggl_likely(v[0].index == index)) {
+        v[0].locked = 1;
+        v[0].mru = 0;
+        return &v[0];
+    }
+
+    if (ggl_likely(v[1].index == index)) {
+        v[1].locked = 1;
+        v[0].mru = 1;
+        return &v[1];
+    }
+
+    const int lru = 1 - v[0].mru;
+    v[0].mru = lru;
+    return cache_vertex(c, &v[lru], index);
+
+#elif VC_CACHE_TYPE == VC_CACHE_TYPE_NONE
+
+    // just for debugging...
+    vertex_t* v = c->vc.vBuffer + 2;
+    return cache_vertex(c, v, index);
+
+#endif
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Primitive Assembly
+#endif
+
+void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count)
+{
+    if (ggl_unlikely(count < 1))
+        return;
+
+    // vertex cache size must be multiple of 1
+    const GLsizei vcs = 
+            (vertex_cache_t::VERTEX_BUFFER_SIZE +
+             vertex_cache_t::VERTEX_CACHE_SIZE);
+    do {
+        vertex_t* v = c->vc.vBuffer;
+        GLsizei num = count > vcs ? vcs : count; 
+        c->arrays.cull = vertex_t::CLIP_ALL;
+        c->arrays.compileElements(c, v, first, num);
+        first += num;
+        count -= num;
+        if (!c->arrays.cull) {
+            // quick/trivial reject of the whole batch
+            do {
+                const uint32_t cc = v[0].flags;
+                if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+                    c->prims.renderPoint(c, v);
+                v++;
+                num--;
+            } while (num);
+        }
+    } while (count);
+}
+
+// ----------------------------------------------------------------------------
+
+void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count)
+{
+    if (ggl_unlikely(count < 2))
+        return;
+
+    vertex_t *v, *v0, *v1;
+    c->arrays.cull = vertex_t::CLIP_ALL;
+    c->arrays.compileElement(c, c->vc.vBuffer, first);
+    first += 1;
+    count -= 1;
+
+    // vertex cache size must be multiple of 1
+    const GLsizei vcs = 
+        (vertex_cache_t::VERTEX_BUFFER_SIZE +
+         vertex_cache_t::VERTEX_CACHE_SIZE - 1);
+    do {
+        v0 = c->vc.vBuffer + 0; 
+        v  = c->vc.vBuffer + 1;
+        GLsizei num = count > vcs ? vcs : count; 
+        c->arrays.compileElements(c, v, first, num);
+        first += num;
+        count -= num;
+        if (!c->arrays.cull) {
+            // quick/trivial reject of the whole batch
+            do {
+                v1 = v++;
+                const uint32_t cc = v0->flags & v1->flags;
+                if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+                    c->prims.renderLine(c, v0, v1);
+                v0 = v1;
+                num--;
+            } while (num);
+        }
+        // copy back the last processed vertex
+        c->vc.vBuffer[0] = *v0;
+        c->arrays.cull = v0->flags & vertex_t::CLIP_ALL;
+    } while (count);
+}
+
+void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count)
+{
+    if (ggl_unlikely(count < 2))
+        return;
+    drawPrimitivesLineStrip(c, first, count);
+    if (ggl_likely(count >= 3)) {
+        vertex_t* v0 = c->vc.vBuffer; 
+        vertex_t* v1 = c->vc.vBuffer + 1;
+        c->arrays.compileElement(c, v1, first);
+        const uint32_t cc = v0->flags & v1->flags;
+        if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+            c->prims.renderLine(c, v0, v1);
+    }
+}
+
+void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count)
+{
+    if (ggl_unlikely(count < 2))
+        return;
+
+    // vertex cache size must be multiple of 2
+    const GLsizei vcs = 
+        ((vertex_cache_t::VERTEX_BUFFER_SIZE +
+        vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2;
+    do {
+        vertex_t* v = c->vc.vBuffer;
+        GLsizei num = count > vcs ? vcs : count; 
+        c->arrays.cull = vertex_t::CLIP_ALL;
+        c->arrays.compileElements(c, v, first, num);
+        first += num;
+        count -= num;
+        if (!c->arrays.cull) {
+            // quick/trivial reject of the whole batch
+            num -= 2;
+            do {
+                const uint32_t cc = v[0].flags & v[1].flags;
+                if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+                    c->prims.renderLine(c, v, v+1);
+                v += 2;
+                num -= 2;
+            } while (num >= 0);
+        }
+    } while (count >= 2);
+}
+
+// ----------------------------------------------------------------------------
+
+static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c,
+        GLint first, GLsizei count, int winding)
+{
+    // winding == 2 : fan
+    // winding == 1 : strip
+
+    if (ggl_unlikely(count < 3))
+        return;
+
+    vertex_t *v, *v0, *v1, *v2;
+    c->arrays.cull = vertex_t::CLIP_ALL;
+    c->arrays.compileElements(c, c->vc.vBuffer, first, 2);
+    first += 2;
+    count -= 2;
+
+    // vertex cache size must be multiple of 2. This is extremely important
+    // because it allows us to preserve the same winding when the whole
+    // batch is culled. We also need 2 extra vertices in the array, because
+    // we always keep the two first ones.
+    const GLsizei vcs = 
+        ((vertex_cache_t::VERTEX_BUFFER_SIZE +
+          vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2;
+    do {
+        v0 = c->vc.vBuffer + 0; 
+        v1 = c->vc.vBuffer + 1; 
+        v  = c->vc.vBuffer + 2;
+        GLsizei num = count > vcs ? vcs : count; 
+        c->arrays.compileElements(c, v, first, num);
+        first += num;
+        count -= num;
+        if (!c->arrays.cull) {
+            // quick/trivial reject of the whole batch
+            do {
+                v2 = v++;
+                const uint32_t cc = v0->flags & v1->flags & v2->flags;
+                if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+                    c->prims.renderTriangle(c, v0, v1, v2);
+                swap(((winding^=1) ? v1 : v0), v2);
+                num--;
+            } while (num);
+        }
+        if (count) {
+            v0 = c->vc.vBuffer + 2 + num - 2;
+            v1 = c->vc.vBuffer + 2 + num - 1;
+            if ((winding&2) == 0) {
+                // for strips copy back the two last compiled vertices
+                c->vc.vBuffer[0] = *v0;
+            }
+            c->vc.vBuffer[1] = *v1;
+            c->arrays.cull = v0->flags & v1->flags & vertex_t::CLIP_ALL;
+        }
+    } while (count > 0);
+}
+
+void drawPrimitivesTriangleStrip(ogles_context_t* c, 
+        GLint first, GLsizei count) {
+    drawPrimitivesTriangleFanOrStrip(c, first, count, 1);
+}
+
+void drawPrimitivesTriangleFan(ogles_context_t* c,
+        GLint first, GLsizei count) {
+    drawPrimitivesTriangleFanOrStrip(c, first, count, 2);
+}
+
+void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count)
+{
+    if (ggl_unlikely(count < 3))
+        return;
+
+    // vertex cache size must be multiple of 3
+    const GLsizei vcs = 
+        ((vertex_cache_t::VERTEX_BUFFER_SIZE +
+        vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3;
+    do {
+        vertex_t* v = c->vc.vBuffer;
+        GLsizei num = count > vcs ? vcs : count; 
+        c->arrays.cull = vertex_t::CLIP_ALL;
+        c->arrays.compileElements(c, v, first, num);
+        first += num;
+        count -= num;
+        if (!c->arrays.cull) {
+            // quick/trivial reject of the whole batch
+            num -= 3;
+            do {
+                const uint32_t cc = v[0].flags & v[1].flags & v[2].flags;
+                if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+                    c->prims.renderTriangle(c, v, v+1, v+2);
+                v += 3;
+                num -= 3;
+            } while (num >= 0);
+        }
+    } while (count >= 3);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+// this looks goofy, but gcc does a great job with this...
+static inline unsigned int read_index(int type, const GLvoid*& p) {
+    unsigned int r;
+    if (type) {
+        r = *(const GLubyte*)p;
+        p = (const GLubyte*)p + 1;
+    } else {
+        r = *(const GLushort*)p;
+        p = (const GLushort*)p + 1;
+    }
+    return r;
+}
+
+// ----------------------------------------------------------------------------
+
+void drawIndexedPrimitivesPoints(ogles_context_t* c,
+        GLsizei count, const GLvoid *indices)
+{
+    if (ggl_unlikely(count < 1))
+        return;
+    const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
+    do {
+        vertex_t * v = fetch_vertex(c, read_index(type, indices));
+        if (ggl_likely(!(v->flags & vertex_t::CLIP_ALL)))
+            c->prims.renderPoint(c, v);
+        v->locked = 0;
+        count--;
+    } while(count);
+}
+
+// ----------------------------------------------------------------------------
+
+void drawIndexedPrimitivesLineStrip(ogles_context_t* c,
+        GLsizei count, const GLvoid *indices)
+{
+    if (ggl_unlikely(count < 2))
+        return;
+    
+    vertex_t * const v = c->vc.vBuffer;
+    vertex_t* v0 = v;
+    vertex_t* v1;
+    
+    const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
+    c->arrays.compileElement(c, v0, read_index(type, indices));
+    count -= 1;
+    do {
+        v1 = fetch_vertex(c, read_index(type, indices));
+        const uint32_t cc = v0->flags & v1->flags;
+        if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+            c->prims.renderLine(c, v0, v1);
+        v0->locked = 0;
+        v0 = v1;
+        count--;
+    } while (count);
+    v1->locked = 0;
+}
+
+void drawIndexedPrimitivesLineLoop(ogles_context_t* c,
+        GLsizei count, const GLvoid *indices)
+{
+    if (ggl_unlikely(count <= 2)) {
+        drawIndexedPrimitivesLines(c, count, indices);
+        return;
+    }
+ 
+    vertex_t * const v = c->vc.vBuffer;
+    vertex_t* v0 = v;
+    vertex_t* v1;
+    
+    const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
+    c->arrays.compileElement(c, v0, read_index(type, indices));
+    count -= 1;
+    do {
+        v1 = fetch_vertex(c, read_index(type, indices));
+        const uint32_t cc = v0->flags & v1->flags;
+        if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+            c->prims.renderLine(c, v0, v1);
+        v0->locked = 0;
+        v0 = v1;
+        count--;
+    } while (count);
+    v1->locked = 0;
+
+    v1 = c->vc.vBuffer; 
+    const uint32_t cc = v0->flags & v1->flags;
+    if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+        c->prims.renderLine(c, v0, v1);
+}
+
+void drawIndexedPrimitivesLines(ogles_context_t* c,
+        GLsizei count, const GLvoid *indices)
+{
+    if (ggl_unlikely(count < 2))
+        return;
+
+    count -= 2;
+    const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
+    do {
+        vertex_t* const v0 = fetch_vertex(c, read_index(type, indices));
+        vertex_t* const v1 = fetch_vertex(c, read_index(type, indices));
+        const uint32_t cc = v0->flags & v1->flags;
+        if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+            c->prims.renderLine(c, v0, v1);
+        v0->locked = 0;
+        v1->locked = 0;
+        count -= 2;
+    } while (count >= 0);
+}
+
+// ----------------------------------------------------------------------------
+
+static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c,
+        GLsizei count, const GLvoid *indices, int winding)
+{
+    // winding == 2 : fan
+    // winding == 1 : strip
+
+    if (ggl_unlikely(count < 3))
+        return;
+    
+    vertex_t * const v = c->vc.vBuffer;
+    vertex_t* v0 = v;
+    vertex_t* v1 = v+1;
+    vertex_t* v2;
+
+    const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
+    c->arrays.compileElement(c, v0, read_index(type, indices));
+    c->arrays.compileElement(c, v1, read_index(type, indices));
+    count -= 2;
+
+    // note: GCC 4.1.1 here makes a prety interesting optimization
+    // where it duplicates the loop below based on c->arrays.indicesType
+
+    do {
+        v2 = fetch_vertex(c, read_index(type, indices));
+        const uint32_t cc = v0->flags & v1->flags & v2->flags;
+        if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+            c->prims.renderTriangle(c, v0, v1, v2);
+        vertex_t* & consumed = ((winding^=1) ? v1 : v0);
+        consumed->locked = 0;
+        consumed = v2;
+        count--;
+    } while (count);
+    v0->locked = v1->locked = 0;
+    v2->locked = 0;
+}
+
+void drawIndexedPrimitivesTriangleStrip(ogles_context_t* c,
+        GLsizei count, const GLvoid *indices) {
+    drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 1);
+}
+
+void drawIndexedPrimitivesTriangleFan(ogles_context_t* c,
+        GLsizei count, const GLvoid *indices) {
+    drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 2);
+}
+
+void drawIndexedPrimitivesTriangles(ogles_context_t* c,
+        GLsizei count, const GLvoid *indices)
+{
+    if (ggl_unlikely(count < 3))
+        return;
+
+    count -= 3;
+    if (ggl_likely(c->arrays.indicesType == GL_UNSIGNED_SHORT)) {
+        // This case is probably our most common case...
+        uint16_t const * p = (uint16_t const *)indices;
+        do {
+            vertex_t* const v0 = fetch_vertex(c, *p++);
+            vertex_t* const v1 = fetch_vertex(c, *p++);
+            vertex_t* const v2 = fetch_vertex(c, *p++);
+            const uint32_t cc = v0->flags & v1->flags & v2->flags;
+            if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+                c->prims.renderTriangle(c, v0, v1, v2);
+            v0->locked = 0;
+            v1->locked = 0;
+            v2->locked = 0;
+            count -= 3;
+        } while (count >= 0);
+    } else {
+        uint8_t const * p = (uint8_t const *)indices;
+        do {
+            vertex_t* const v0 = fetch_vertex(c, *p++);
+            vertex_t* const v1 = fetch_vertex(c, *p++);
+            vertex_t* const v2 = fetch_vertex(c, *p++);
+            const uint32_t cc = v0->flags & v1->flags & v2->flags;
+            if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+                c->prims.renderTriangle(c, v0, v1, v2);
+            v0->locked = 0;
+            v1->locked = 0;
+            v2->locked = 0;
+            count -= 3;
+        } while (count >= 0);
+    }
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Array compilers
+#endif
+
+void compileElement__generic(ogles_context_t* c,
+        vertex_t* v, GLint first)
+{
+    v->flags = 0;
+    v->index = first;
+    first &= vertex_cache_t::INDEX_MASK;
+    const GLubyte* vp = c->arrays.vertex.element(first);
+    c->arrays.vertex.fetch(c, v->obj.v, vp);
+    c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj);
+    c->arrays.perspective(c, v);
+}
+
+void compileElements__generic(ogles_context_t* c,
+        vertex_t* v, GLint first, GLsizei count)
+{
+    const GLubyte* vp = c->arrays.vertex.element(
+            first & vertex_cache_t::INDEX_MASK);
+    const size_t stride = c->arrays.vertex.stride;
+    transform_t const* const mvp = &c->transforms.mvp;
+    do {
+        v->flags = 0;
+        v->index = first++;
+        c->arrays.vertex.fetch(c, v->obj.v, vp);
+        c->arrays.mvp_transform(mvp, &v->clip, &v->obj);
+        c->arrays.perspective(c, v);
+        vp += stride;
+        v++;
+    } while (--count);
+}
+
+/*
+void compileElements__3x_full(ogles_context_t* c,
+        vertex_t* v, GLint first, GLsizei count)
+{
+    const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first);
+    const size_t stride = c->arrays.vertex.stride / 4;
+//    const GLfixed* const& m = c->transforms.mvp.matrix.m;
+    
+    GLfixed m[16];
+    memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m));
+    
+    do {
+        const GLfixed rx = vp[0];
+        const GLfixed ry = vp[1];
+        const GLfixed rz = vp[2];
+        vp += stride;
+        v->index = first++;
+        v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]); 
+        v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
+        v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
+        v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
+
+        const GLfixed w = v->clip.w;
+        uint32_t clip = 0;
+        if (v->clip.x < -w)   clip |= vertex_t::CLIP_L;
+        if (v->clip.x >  w)   clip |= vertex_t::CLIP_R;
+        if (v->clip.y < -w)   clip |= vertex_t::CLIP_B;
+        if (v->clip.y >  w)   clip |= vertex_t::CLIP_T;
+        if (v->clip.z < -w)   clip |= vertex_t::CLIP_N;
+        if (v->clip.z >  w)   clip |= vertex_t::CLIP_F;
+        v->flags = clip;
+        c->arrays.cull &= clip;
+
+        //c->arrays.perspective(c, v);
+        v++;
+    } while (--count);
+}
+*/
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark clippers
+#endif
+
+static void clipVec4(vec4_t& nv, 
+        GLfixed t, const vec4_t& s, const vec4_t& p)
+{
+    for (int i=0; i<4 ; i++)
+        nv.v[i] = gglMulAddx(t, s.v[i] - p.v[i], p.v[i], 28);
+}
+
+static void clipVertex(ogles_context_t* c, vertex_t* nv,
+        GLfixed t, const vertex_t* s, const vertex_t* p)
+{
+    clipVec4(nv->clip, t, s->clip, p->clip);
+    nv->fog = gglMulAddx(t, s->fog - p->fog, p->fog, 28);
+    ogles_vertex_project(c, nv);
+    nv->flags |=  vertex_t::LIT | vertex_t::EYE | vertex_t::TT;
+    nv->flags &= ~vertex_t::CLIP_ALL;
+}
+
+static void clipVertexC(ogles_context_t* c, vertex_t* nv,
+        GLfixed t, const vertex_t* s, const vertex_t* p)
+{
+    clipVec4(nv->color, t, s->color, p->color);
+    clipVertex(c, nv, t, s, p);
+}
+
+static void clipVertexT(ogles_context_t* c, vertex_t* nv,
+        GLfixed t, const vertex_t* s, const vertex_t* p)
+{
+    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+        if (c->rasterizer.state.texture[i].enable)
+            clipVec4(nv->texture[i], t, s->texture[i], p->texture[i]);
+    }
+    clipVertex(c, nv, t, s, p);
+}
+
+static void clipVertexAll(ogles_context_t* c, vertex_t* nv,
+        GLfixed t, const vertex_t* s, const vertex_t* p)
+{
+    clipVec4(nv->color, t, s->color, p->color);
+    clipVertexT(c, nv, t, s, p);
+}
+
+static void clipEye(ogles_context_t* c, vertex_t* nv,
+        GLfixed t, const vertex_t* s, const vertex_t* p)
+{
+    nv->clear();
+    c->arrays.clipVertex(c, nv, t, p, s);
+    clipVec4(nv->eye, t, s->eye, p->eye);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void validate_arrays(ogles_context_t* c, GLenum mode)
+{
+    uint32_t enables = c->rasterizer.state.enables;
+
+    // Perspective correction is not need if Ortho transform, but
+    // the user can still provide the w coordinate manually, so we can't
+    // automatically turn it off (in fact we could when the 4th coordinate
+    // is not spcified in the vertex array).
+    // W interpolation is never needed for points.
+    GLboolean perspective = 
+        c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS);
+    c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective);
+    
+    // set anti-aliasing
+    GLboolean smooth = GL_FALSE;
+    switch (mode) {
+    case GL_POINTS:
+        smooth = c->point.smooth;
+        break;
+    case GL_LINES:
+    case GL_LINE_LOOP:
+    case GL_LINE_STRIP:
+        smooth = c->line.smooth;
+        break;
+    }
+    if (((enables & GGL_ENABLE_AA)?1:0) != smooth)
+        c->rasterizer.procs.enableDisable(c, GGL_AA, smooth);
+
+    // set the shade model for this primitive
+    c->rasterizer.procs.shadeModel(c,
+            (mode == GL_POINTS) ? GL_FLAT : c->lighting.shadeModel);
+
+    // compute all the matrices we'll need...
+    uint32_t want =
+            transform_state_t::MVP |
+            transform_state_t::VIEWPORT;
+    if (c->lighting.enable) { // needs normal transforms and eye coords
+        want |= transform_state_t::MVUI;
+        want |= transform_state_t::MODELVIEW;
+    }
+    if (enables & GGL_ENABLE_TMUS) { // needs texture transforms
+        want |= transform_state_t::TEXTURE;
+    }
+    if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) { 
+        want |= transform_state_t::MODELVIEW; // needs eye coords
+    }
+    ogles_validate_transform(c, want);
+
+    // textures...
+    if (enables & GGL_ENABLE_TMUS)
+        ogles_validate_texture(c);
+
+    // vertex compilers
+    c->arrays.compileElement = compileElement__generic;
+    c->arrays.compileElements = compileElements__generic;
+
+    // vertex transform
+    c->arrays.mvp_transform =
+        c->transforms.mvp.pointv[c->arrays.vertex.size - 2];
+
+    c->arrays.mv_transform =
+        c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2];
+    
+    /*
+     * ***********************************************************************
+     *  pick fetchers
+     * ***********************************************************************
+     */
+    
+    array_machine_t& am = c->arrays;
+    am.vertex.fetch = fetchNop;
+    am.normal.fetch = currentNormal;
+    am.color.fetch = currentColor;
+    
+    if (am.vertex.enable) {
+        am.vertex.resolve();
+        if (am.vertex.bo || am.vertex.pointer) {
+            am.vertex.fetch = vertex_fct[am.vertex.size-2][am.vertex.type & 0xF];
+        }
+    }
+
+    if (am.normal.enable) {
+        am.normal.resolve();
+        if (am.normal.bo || am.normal.pointer) {
+            am.normal.fetch = normal_fct[am.normal.size-3][am.normal.type & 0xF];
+        }
+    }
+
+    if (am.color.enable) {
+        am.color.resolve();
+        if (c->lighting.enable) {
+            if (am.color.bo || am.color.pointer) {
+                am.color.fetch = color_fct[am.color.size-3][am.color.type & 0xF];
+            }
+        } else {
+            if (am.color.bo || am.color.pointer) {
+                am.color.fetch = color_clamp_fct[am.color.size-3][am.color.type & 0xF];
+            }
+        }
+    }
+
+    int activeTmuCount = 0;
+    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+        am.texture[i].fetch = currentTexCoord;
+        if (c->rasterizer.state.texture[i].enable) {
+
+            // texture fetchers...
+            if (am.texture[i].enable) {
+                am.texture[i].resolve();
+                if (am.texture[i].bo || am.texture[i].pointer) {
+                    am.texture[i].fetch = texture_fct[am.texture[i].size-2][am.texture[i].type & 0xF];
+                }
+            }
+
+            // texture transform...
+            const int index = c->arrays.texture[i].size - 2;
+            c->arrays.tex_transform[i] =
+                c->transforms.texture[i].transform.pointv[index];
+
+            am.tmu = i;
+            activeTmuCount++;
+        }
+    }
+
+    // pick the vertex-clipper
+    uint32_t clipper = 0;
+    // we must reload 'enables' here
+    enables = c->rasterizer.state.enables;
+    if (enables & GGL_ENABLE_SMOOTH)
+        clipper |= 1;   // we need to interpolate colors
+    if (enables & GGL_ENABLE_TMUS)
+        clipper |= 2;   // we need to interpolate textures
+    switch (clipper) {
+    case 0: c->arrays.clipVertex = clipVertex;      break;
+    case 1: c->arrays.clipVertex = clipVertexC;     break;
+    case 2: c->arrays.clipVertex = clipVertexT;     break;
+    case 3: c->arrays.clipVertex = clipVertexAll;   break;
+    }
+    c->arrays.clipEye = clipEye;
+
+    // pick the primitive rasterizer
+    ogles_validate_primitives(c);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+#if 0
+#pragma mark -
+#pragma mark array API
+#endif
+
+void glVertexPointer(
+    GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (size<2 || size>4 || stride<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    switch (type) {
+    case GL_BYTE:
+    case GL_SHORT:
+    case GL_FIXED:
+    case GL_FLOAT:
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->arrays.vertex.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
+}
+
+void glColorPointer(
+    GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    // in theory ogles doesn't allow color arrays of size 3
+    // but it is very useful to 'visualize' the normal array.
+    if (size<3 || size>4 || stride<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    switch (type) {
+    case GL_UNSIGNED_BYTE:
+    case GL_FIXED:
+    case GL_FLOAT:
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->arrays.color.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
+}
+
+void glNormalPointer(
+    GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (stride<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    switch (type) {
+    case GL_BYTE:
+    case GL_SHORT:
+    case GL_FIXED:
+    case GL_FLOAT:
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->arrays.normal.init(3, type, stride, pointer, c->arrays.array_buffer, 0);
+}
+
+void glTexCoordPointer(
+    GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (size<2 || size>4 || stride<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    switch (type) {
+    case GL_BYTE:
+    case GL_SHORT:
+    case GL_FIXED:
+    case GL_FLOAT:
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    const int tmu = c->arrays.activeTexture;
+    c->arrays.texture[tmu].init(size, type, stride, pointer,
+            c->arrays.array_buffer, 0);
+}
+
+
+void glEnableClientState(GLenum array) {
+    ogles_context_t* c = ogles_context_t::get();
+    enableDisableClientState(c, array, true);
+}
+
+void glDisableClientState(GLenum array) {
+    ogles_context_t* c = ogles_context_t::get();
+    enableDisableClientState(c, array, false);
+}
+
+void glClientActiveTexture(GLenum texture)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (texture<GL_TEXTURE0 || texture>=GL_TEXTURE0+GGL_TEXTURE_UNIT_COUNT) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->arrays.activeTexture = texture - GL_TEXTURE0;
+}
+
+void glDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (count<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    switch (mode) {
+    case GL_POINTS:
+    case GL_LINE_STRIP:
+    case GL_LINE_LOOP:
+    case GL_LINES:
+    case GL_TRIANGLE_STRIP:
+    case GL_TRIANGLE_FAN:
+    case GL_TRIANGLES:
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+
+    if (count == 0 || !c->arrays.vertex.enable)
+        return;
+    if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
+        return; // all triangles are culled
+
+    validate_arrays(c, mode);
+    drawArraysPrims[mode](c, first, count);
+
+#if VC_CACHE_STATISTICS
+    c->vc.total = count;
+    c->vc.dump_stats(mode);
+#endif
+}
+
+void glDrawElements(
+    GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (count<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    switch (mode) {
+    case GL_POINTS:
+    case GL_LINE_STRIP:
+    case GL_LINE_LOOP:
+    case GL_LINES:
+    case GL_TRIANGLE_STRIP:
+    case GL_TRIANGLE_FAN:
+    case GL_TRIANGLES:
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    switch (type) {
+    case GL_UNSIGNED_BYTE:
+    case GL_UNSIGNED_SHORT:
+        c->arrays.indicesType = type;
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if (count == 0 || !c->arrays.vertex.enable)
+        return;
+    if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
+        return; // all triangles are culled
+
+    // clear the vertex-cache
+    c->vc.clear();
+    validate_arrays(c, mode);
+    
+    // if indices are in a buffer object, the pointer is treated as an
+    // offset in that buffer.
+    if (c->arrays.element_array_buffer) {
+        indices = c->arrays.element_array_buffer->data + uintptr_t(indices);
+    }
+
+    drawElementsPrims[mode](c, count, indices);
+
+#if VC_CACHE_STATISTICS
+    c->vc.total = count;
+    c->vc.dump_stats(mode);
+#endif
+}
+
+// ----------------------------------------------------------------------------
+// buffers
+// ----------------------------------------------------------------------------
+
+void glBindBuffer(GLenum target, GLuint buffer)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    // create a buffer object, or bind an existing one
+    buffer_t const* bo = 0;
+    if (buffer) {
+        bo = c->bufferObjectManager->bind(buffer);
+        if (!bo) {
+            ogles_error(c, GL_OUT_OF_MEMORY);
+            return;
+        }
+    }
+    ((target == GL_ARRAY_BUFFER) ? 
+            c->arrays.array_buffer : c->arrays.element_array_buffer) = bo;
+}
+
+void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if (size<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    if ((usage!=GL_STATIC_DRAW) && (usage!=GL_DYNAMIC_DRAW)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ? 
+            c->arrays.array_buffer : c->arrays.element_array_buffer);
+
+    if (bo == 0) {
+        // can't modify buffer 0
+        ogles_error(c, GL_INVALID_OPERATION);
+        return;
+    }
+
+    buffer_t* edit_bo = const_cast<buffer_t*>(bo);
+    if (c->bufferObjectManager->allocateStore(edit_bo, size, usage) != 0) {
+        ogles_error(c, GL_OUT_OF_MEMORY);
+        return;
+    }
+    if (data) {
+        memcpy(bo->data, data, size);
+    }
+}
+
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if (offset<0 || size<0 || data==0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ? 
+            c->arrays.array_buffer : c->arrays.element_array_buffer);
+
+    if (bo == 0) {
+        // can't modify buffer 0
+        ogles_error(c, GL_INVALID_OPERATION);
+        return;
+    }
+    if (offset+size > bo->size) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    memcpy(bo->data + offset, data, size);
+}
+
+void glDeleteBuffers(GLsizei n, const GLuint* buffers)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (n<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+
+    for (int i=0 ; i<n ; i++) {
+        GLuint name = buffers[i];
+        if (name) {
+            // unbind bound deleted buffers...
+            if (c->arrays.element_array_buffer->name == name) {
+                c->arrays.element_array_buffer = 0;
+            }
+            if (c->arrays.array_buffer->name == name) {
+                c->arrays.array_buffer = 0;
+            }
+            if (c->arrays.vertex.bo->name == name) {
+                c->arrays.vertex.bo = 0;
+            }
+            if (c->arrays.normal.bo->name == name) {
+                c->arrays.normal.bo = 0;
+            }
+            if (c->arrays.color.bo->name == name) {
+                c->arrays.color.bo = 0;
+            }
+            for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
+                if (c->arrays.texture[t].bo->name == name) {
+                    c->arrays.texture[t].bo = 0;
+                }
+            }
+        }
+    }    
+    c->bufferObjectManager->deleteBuffers(n, buffers);
+    c->bufferObjectManager->recycleTokens(n, buffers);
+}
+
+void glGenBuffers(GLsizei n, GLuint* buffers)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (n<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    c->bufferObjectManager->getToken(n, buffers);
+}
diff --git a/opengl/libagl/array.h b/opengl/libagl/array.h
new file mode 100644
index 0000000..e156978
--- /dev/null
+++ b/opengl/libagl/array.h
@@ -0,0 +1,37 @@
+/* libs/opengles/array.h
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_OPENGLES_ARRAY_H
+#define ANDROID_OPENGLES_ARRAY_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+namespace android {
+
+namespace gl {
+struct ogles_context_t;
+};
+
+void ogles_init_array(ogles_context_t* c);
+void ogles_uninit_array(ogles_context_t* c);
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_ARRAY_H
+
diff --git a/opengl/libagl/context.h b/opengl/libagl/context.h
new file mode 100644
index 0000000..ef36b56
--- /dev/null
+++ b/opengl/libagl/context.h
@@ -0,0 +1,20 @@
+/* libs/opengles/context.h
+**
+** Copyright 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 <private/opengles/gl_context.h>
+
+using namespace android::gl;
diff --git a/opengl/libagl/dxt.cpp b/opengl/libagl/dxt.cpp
new file mode 100644
index 0000000..238c81f
--- /dev/null
+++ b/opengl/libagl/dxt.cpp
@@ -0,0 +1,636 @@
+/* libs/opengles/dxt.cpp
+**
+** Copyright 2007, 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.
+*/
+
+#define TIMING 0
+
+#if TIMING
+#include <sys/time.h> // for optimization timing
+#include <stdio.h>
+#include <stdlib.h>
+#endif
+
+#include <GLES/gl.h>
+#include <utils/Endian.h>
+
+#include "context.h"
+
+#define TIMING 0
+
+namespace android {
+
+static uint8_t avg23tab[64*64];
+static volatile int tables_initialized = 0;
+
+// Definitions below are equivalent to these over the valid range of arguments
+//  #define div5(x) ((x)/5)
+//  #define div7(x) ((x)/7)
+
+// Use fixed-point to divide by 5 and 7
+// 3277 = 2^14/5 + 1
+// 2341 = 2^14/7 + 1
+#define div5(x) (((x)*3277) >> 14)
+#define div7(x) (((x)*2341) >> 14)
+
+// Table with entry [a << 6 | b] = (2*a + b)/3 for 0 <= a,b < 64
+#define avg23(x0,x1) avg23tab[((x0) << 6) | (x1)]
+
+// Extract 5/6/5 RGB
+#define red(x)   (((x) >> 11) & 0x1f)
+#define green(x) (((x) >>  5) & 0x3f)
+#define blue(x)  ( (x)        & 0x1f)
+
+/*
+ * Convert 5/6/5 RGB (as 3 ints) to 8/8/8
+ *
+ * Operation count: 8 <<, 0 &, 5 |
+ */
+inline static int rgb565SepTo888(int r, int g, int b)
+
+{
+    return ((((r << 3) | (r >> 2)) << 16) |
+            (((g << 2) | (g >> 4)) <<  8) |
+             ((b << 3) | (b >> 2)));
+}
+
+/*
+ * Convert 5/6/5 RGB (as a single 16-bit word) to 8/8/8
+ *
+ *                   r4r3r2r1 r0g5g4g3 g2g1g0b4 b3b2b1b0   rgb
+ *            r4r3r2 r1r0g5g4 g3g2g1g0 b4b3b2b1 b0 0 0 0   rgb << 3
+ * r4r3r2r1 r0r4r3r2 g5g4g3g2 g1g0g5g4 b4b3b2b1 b0b4b3b2   desired result
+ *
+ * Construct the 24-bit RGB word as:
+ *
+ * r4r3r2r1 r0------ -------- -------- -------- --------  (rgb << 8) & 0xf80000
+ *            r4r3r2 -------- -------- -------- --------  (rgb << 3) & 0x070000
+ *                   g5g4g3g2 g1g0---- -------- --------  (rgb << 5) & 0x00fc00
+ *                                g5g4 -------- --------  (rgb >> 1) & 0x000300
+ *                                     b4b3b2b1 b0------  (rgb << 3) & 0x0000f8
+ *                                                b4b3b2  (rgb >> 2) & 0x000007
+ *
+ * Operation count: 5 <<, 6 &, 5 | (n.b. rgb >> 3 is used twice)
+ */
+inline static int rgb565To888(int rgb)
+
+{
+    int rgb3 = rgb >> 3;
+    return (((rgb << 8) & 0xf80000) |
+            ( rgb3      & 0x070000) |
+            ((rgb << 5) & 0x00fc00) |
+            ((rgb >> 1) & 0x000300) |
+            ( rgb3      & 0x0000f8) |
+            ((rgb >> 2) & 0x000007));
+}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+static uint32_t swap(uint32_t x) {
+    int b0 = (x >> 24) & 0xff;
+    int b1 = (x >> 16) & 0xff;
+    int b2 = (x >>  8) & 0xff;
+    int b3 = (x      ) & 0xff;
+    
+    return (uint32_t)((b3 << 24) | (b2 << 16) | (b1 << 8) | b0);
+}
+#endif
+
+static void
+init_tables()
+{
+    if (tables_initialized) {
+        return;
+    }
+
+    for (int i = 0; i < 64; i++) {
+        for (int j = 0; j < 64; j++) {
+            int avg = (2*i + j)/3;
+            avg23tab[(i << 6) | j] = avg;
+        }
+    }
+
+    asm volatile ("" : : : "memory");
+    tables_initialized = 1;
+}
+
+/*
+ * Utility to scan a DXT1 compressed texture to determine whether it
+ * contains a transparent pixel (color0 < color1, code == 3).  This
+ * may be useful if the application lacks information as to whether
+ * the true format is GL_COMPRESSED_RGB_S3TC_DXT1_EXT or
+ * GL_COMPRESSED_RGBA_S3TC_DXT1_EXT.
+ */
+bool
+DXT1HasAlpha(const GLvoid *data, int width, int height) {    
+#if TIMING
+    struct timeval start_t, end_t;
+    struct timezone tz;
+    
+    gettimeofday(&start_t, &tz);
+#endif
+
+    bool hasAlpha = false;
+
+    int xblocks = (width + 3)/4;
+    int yblocks = (height + 3)/4;
+    int numblocks = xblocks*yblocks;
+
+    uint32_t const *d32 = (uint32_t *)data;
+    for (int b = 0; b < numblocks; b++) {
+        uint32_t colors = *d32++;
+        
+#if __BYTE_ORDER == __BIG_ENDIAN
+        colors = swap(colors);
+#endif
+        
+        uint16_t color0 = colors & 0xffff;
+        uint16_t color1 = colors >> 16;
+        
+        if (color0 < color1) {
+            // There's no need to endian-swap within 'bits'
+            // since we don't care which pixel is the transparent one
+            uint32_t bits = *d32++;
+            
+            // Detect if any (odd, even) pair of bits are '11'
+            //      bits: b31 b30 b29 ... b3 b2 b1 b0
+            // bits >> 1: b31 b31 b30 ... b4 b3 b2 b1
+            //         &: b31 (b31 & b30) (b29 & b28) ... (b2 & b1) (b1 & b0)
+            //  & 0x55..:   0 (b31 & b30)       0     ...     0     (b1 & b0)
+            if (((bits & (bits >> 1)) & 0x55555555) != 0) {
+                hasAlpha = true;
+                goto done;
+            }
+        } else {
+            // Skip 4 bytes
+            ++d32;
+        }
+    }
+    
+ done:
+#if TIMING
+    gettimeofday(&end_t, &tz);
+    long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 +
+        (end_t.tv_usec - start_t.tv_usec);
+    
+    printf("Scanned w=%d h=%d in %ld usec\n", width, height, usec);
+#endif
+    
+    return hasAlpha;
+}
+
+static void
+decodeDXT1(const GLvoid *data, int width, int height,
+           void *surface, int stride,
+           bool hasAlpha)
+    
+{
+    init_tables();
+    
+    uint32_t const *d32 = (uint32_t *)data;
+    
+    // Color table for the current block
+    uint16_t c[4];
+    c[0] = c[1] = c[2] = c[3] = 0;
+    
+    // Specified colors from the previous block
+    uint16_t prev_color0 = 0x0000;
+    uint16_t prev_color1 = 0x0000;
+    
+    uint16_t* rowPtr = (uint16_t*)surface;
+    for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) {
+        uint16_t *blockPtr = rowPtr;
+        for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) {
+            uint32_t colors = *d32++;
+            uint32_t bits = *d32++;
+            
+#if __BYTE_ORDER == __BIG_ENDIAN
+            colors = swap(colors);
+            bits = swap(bits);
+#endif
+            
+            // Raw colors
+            uint16_t color0 = colors & 0xffff;
+            uint16_t color1 = colors >> 16;
+            
+            // If the new block has the same base colors as the
+            // previous one, we don't need to recompute the color
+            // table c[]
+            if (color0 != prev_color0 || color1 != prev_color1) {
+                // Store raw colors for comparison with next block
+                prev_color0 = color0;
+                prev_color1 = color1;
+                
+                int r0 =   red(color0);
+                int g0 = green(color0);
+                int b0 =  blue(color0);
+
+                int r1 =   red(color1);
+                int g1 = green(color1);
+                int b1 =  blue(color1);                
+                
+                if (hasAlpha) {
+                    c[0] = (r0 << 11) | ((g0 >> 1) << 6) | (b0 << 1) | 0x1;
+                    c[1] = (r1 << 11) | ((g1 >> 1) << 6) | (b1 << 1) | 0x1;
+                } else {
+                    c[0] = color0;
+                    c[1] = color1;
+                }
+                
+                int r2, g2, b2, r3, g3, b3, a3;
+                
+                int bbits = bits >> 1;
+                bool has2 = ((bbits & ~bits) & 0x55555555) != 0;
+                bool has3 = ((bbits &  bits) & 0x55555555) != 0;
+                
+                if (has2 || has3) {
+                    if (color0 > color1) {
+                        r2 = avg23(r0, r1);
+                        g2 = avg23(g0, g1);
+                        b2 = avg23(b0, b1);
+                        
+                        r3 = avg23(r1, r0);
+                        g3 = avg23(g1, g0);
+                        b3 = avg23(b1, b0);
+                        a3 = 1;
+                    } else {
+                        r2 = (r0 + r1) >> 1;
+                        g2 = (g0 + g1) >> 1;
+                        b2 = (b0 + b1) >> 1;
+                        
+                        r3 = g3 = b3 = a3 = 0;
+                    }
+                    if (hasAlpha) {
+                        c[2] = (r2 << 11) | ((g2 >> 1) << 6) |
+                            (b2 << 1) | 0x1;
+                        c[3] = (r3 << 11) | ((g3 >> 1) << 6) |
+                            (b3 << 1) | a3;
+                    } else {
+                        c[2] = (r2 << 11) | (g2 << 5) | b2;
+                        c[3] = (r3 << 11) | (g3 << 5) | b3;
+                    }
+                }
+            }
+            
+            uint16_t* blockRowPtr = blockPtr;
+            for (int y = 0; y < 4; y++, blockRowPtr += stride) {
+                // Don't process rows past the botom
+                if (base_y + y >= height) {
+                    break;
+                }
+                
+                int w = min(width - base_x, 4);
+                for (int x = 0; x < w; x++) {
+                    int code = bits & 0x3;
+                    bits >>= 2;
+                    
+                    blockRowPtr[x] = c[code];
+                }
+            }
+        }
+    }
+}
+    
+// Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE
+static void
+decodeDXT3(const GLvoid *data, int width, int height,
+           void *surface, int stride)
+
+{
+    init_tables();
+    
+    uint32_t const *d32 = (uint32_t *)data;
+    
+    // Specified colors from the previous block
+    uint16_t prev_color0 = 0x0000;
+    uint16_t prev_color1 = 0x0000;
+
+    // Color table for the current block
+    uint32_t c[4];
+    c[0] = c[1] = c[2] = c[3] = 0;
+
+    uint32_t* rowPtr = (uint32_t*)surface;
+    for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) {
+        uint32_t *blockPtr = rowPtr;
+        for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) {
+            
+#if __BYTE_ORDER == __BIG_ENDIAN
+            uint32_t alphahi = *d32++;
+            uint32_t alphalo = *d32++;
+            alphahi = swap(alphahi);
+            alphalo = swap(alphalo);
+#else
+            uint32_t alphalo = *d32++;
+            uint32_t alphahi = *d32++;
+#endif
+
+            uint32_t colors = *d32++;
+            uint32_t bits = *d32++;
+            
+#if __BYTE_ORDER == __BIG_ENDIAN
+            colors = swap(colors);
+            bits = swap(bits);
+#endif
+            
+            uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo;
+
+            // Raw colors
+            uint16_t color0 = colors & 0xffff;
+            uint16_t color1 = colors >> 16;
+
+            // If the new block has the same base colors as the
+            // previous one, we don't need to recompute the color
+            // table c[]
+            if (color0 != prev_color0 || color1 != prev_color1) {
+                // Store raw colors for comparison with next block
+                prev_color0 = color0;
+                prev_color1 = color1;
+                
+                int bbits = bits >> 1;
+                bool has2 = ((bbits & ~bits) & 0x55555555) != 0;
+                bool has3 = ((bbits &  bits) & 0x55555555) != 0;
+                
+                if (has2 || has3) {
+                    int r0 =   red(color0);
+                    int g0 = green(color0);
+                    int b0 =  blue(color0);
+                    
+                    int r1 =   red(color1);
+                    int g1 = green(color1);
+                    int b1 =  blue(color1);
+                    
+                    int r2 = avg23(r0, r1);
+                    int g2 = avg23(g0, g1);
+                    int b2 = avg23(b0, b1);
+                    
+                    int r3 = avg23(r1, r0);
+                    int g3 = avg23(g1, g0);
+                    int b3 = avg23(b1, b0);
+
+                    c[0] = rgb565SepTo888(r0, g0, b0);
+                    c[1] = rgb565SepTo888(r1, g1, b1);
+                    c[2] = rgb565SepTo888(r2, g2, b2);
+                    c[3] = rgb565SepTo888(r3, g3, b3);
+                } else {
+                    // Convert to 8 bits
+                    c[0] = rgb565To888(color0);
+                    c[1] = rgb565To888(color1);
+                }
+            }
+
+            uint32_t* blockRowPtr = blockPtr;
+            for (int y = 0; y < 4; y++, blockRowPtr += stride) {
+                // Don't process rows past the botom
+                if (base_y + y >= height) {
+                    break;
+                }
+                
+                int w = min(width - base_x, 4);
+                for (int x = 0; x < w; x++) {
+                    int a = alpha & 0xf;
+                    alpha >>= 4;
+
+                    int code = bits & 0x3;
+                    bits >>= 2;
+
+                    blockRowPtr[x] = c[code] | (a << 28) | (a << 24);
+                }
+            }
+        }
+    }
+}
+
+// Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE
+static void
+decodeDXT5(const GLvoid *data, int width, int height,
+           void *surface, int stride)
+
+{
+    init_tables();
+    
+    uint32_t const *d32 = (uint32_t *)data;
+    
+    // Specified alphas from the previous block
+    uint8_t prev_alpha0 = 0x00;
+    uint8_t prev_alpha1 = 0x00;
+
+    // Specified colors from the previous block
+    uint16_t prev_color0 = 0x0000;
+     uint16_t prev_color1 = 0x0000;
+
+    // Alpha table for the current block
+    uint8_t a[8];
+    a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = 0;
+
+    // Color table for the current block
+    uint32_t c[4];
+    c[0] = c[1] = c[2] = c[3] = 0;
+
+    int good_a5 = 0;
+    int bad_a5 = 0;
+    int good_a6 = 0;
+    int bad_a6 = 0;
+    int good_a7 = 0;
+    int bad_a7 = 0;
+
+    uint32_t* rowPtr = (uint32_t*)surface;
+    for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) {
+        uint32_t *blockPtr = rowPtr;
+        for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) {
+            
+#if __BYTE_ORDER == __BIG_ENDIAN
+            uint32_t alphahi = *d32++;
+            uint32_t alphalo = *d32++;
+            alphahi = swap(alphahi);
+            alphalo = swap(alphalo);
+#else
+             uint32_t alphalo = *d32++;
+             uint32_t alphahi = *d32++;
+#endif
+
+            uint32_t colors = *d32++;
+            uint32_t bits = *d32++;
+            
+#if __BYTE_ORDER == __BIG_ENDIANx
+            colors = swap(colors);
+            bits = swap(bits);
+#endif
+            
+            uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo;
+            uint64_t alpha0 = alpha & 0xff;
+            alpha >>= 8;
+            uint64_t alpha1 = alpha & 0xff;
+            alpha >>= 8;
+
+            if (alpha0 != prev_alpha0 || alpha1 != prev_alpha1) {
+                prev_alpha0 = alpha0;
+                prev_alpha1 = alpha1;
+                
+                a[0] = alpha0;
+                a[1] = alpha1;
+                int a01 = alpha0 + alpha1 - 1;
+                if (alpha0 > alpha1) {
+                    a[2] = div7(6*alpha0 +   alpha1);
+                    a[4] = div7(4*alpha0 + 3*alpha1);
+                    a[6] = div7(2*alpha0 + 5*alpha1);
+
+                    // Use symmetry to derive half of the values
+                    // A few values will be off by 1 (~.5%)
+                    // Alternate which values are computed directly
+                    // and which are derived to try to reduce bias
+                    a[3] = a01 - a[6];
+                    a[5] = a01 - a[4];
+                    a[7] = a01 - a[2];
+                } else {
+                    a[2] = div5(4*alpha0 +   alpha1);
+                    a[4] = div5(2*alpha0 + 3*alpha1);
+                    a[3] = a01 - a[4];
+                    a[5] = a01 - a[2];
+                    a[6] = 0x00;
+                    a[7] = 0xff;
+                }
+            }
+
+            // Raw colors
+            uint16_t color0 = colors & 0xffff;
+            uint16_t color1 = colors >> 16;
+
+            // If the new block has the same base colors as the
+            // previous one, we don't need to recompute the color
+            // table c[]
+            if (color0 != prev_color0 || color1 != prev_color1) {
+                // Store raw colors for comparison with next block
+                prev_color0 = color0;
+                prev_color1 = color1;
+                
+                int bbits = bits >> 1;
+                bool has2 = ((bbits & ~bits) & 0x55555555) != 0;
+                bool has3 = ((bbits &  bits) & 0x55555555) != 0;
+                
+                if (has2 || has3) {
+                    int r0 =   red(color0);
+                    int g0 = green(color0);
+                    int b0 =  blue(color0);
+                    
+                    int r1 =   red(color1);
+                    int g1 = green(color1);
+                    int b1 =  blue(color1);
+                
+                    int r2 = avg23(r0, r1);
+                    int g2 = avg23(g0, g1);
+                    int b2 = avg23(b0, b1);
+                    
+                    int r3 = avg23(r1, r0);
+                    int g3 = avg23(g1, g0);
+                    int b3 = avg23(b1, b0);
+
+                    c[0] = rgb565SepTo888(r0, g0, b0);
+                    c[1] = rgb565SepTo888(r1, g1, b1);
+                    c[2] = rgb565SepTo888(r2, g2, b2);
+                    c[3] = rgb565SepTo888(r3, g3, b3);
+                } else {
+                    // Convert to 8 bits
+                    c[0] = rgb565To888(color0);
+                    c[1] = rgb565To888(color1);
+                }                
+            }
+
+            uint32_t* blockRowPtr = blockPtr;
+            for (int y = 0; y < 4; y++, blockRowPtr += stride) {
+                // Don't process rows past the botom
+                if (base_y + y >= height) {
+                    break;
+                }
+                
+                int w = min(width - base_x, 4);
+                for (int x = 0; x < w; x++) {
+                    int acode = alpha & 0x7;
+                    alpha >>= 3;
+
+                    int code = bits & 0x3;
+                    bits >>= 2;
+
+                    blockRowPtr[x] = c[code] | (a[acode] << 24);
+                }
+            }
+        }
+    }
+}
+   
+/*
+ * Decode a DXT-compressed texture into memory.  DXT textures consist of
+ * a series of 4x4 pixel blocks in left-to-right, top-down order.
+ * The number of blocks is given by ceil(width/4)*ceil(height/4).
+ *
+ * 'data' points to the texture data. 'width' and 'height' indicate the
+ * dimensions of the texture.  We assume width and height are >= 0 but
+ * do not require them to be powers of 2 or divisible by any factor.
+ *
+ * The output is written to 'surface' with each scanline separated by
+ * 'stride' 2- or 4-byte words.
+ *
+ * 'format' indicates the type of compression and must be one of the following:
+ *
+ *   GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ *      The output is written as 5/6/5 opaque RGB (16 bit words).
+ *      8 bytes are read from 'data' for each block.
+ *
+ *   GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
+ *      The output is written as 5/5/5/1 RGBA (16 bit words)
+ *      8 bytes are read from 'data' for each block.
+ *
+ *   GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
+ *   GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
+ *      The output is written as 8/8/8/8 ARGB (32 bit words)
+ *      16 bytes are read from 'data' for each block.
+ */
+void
+decodeDXT(const GLvoid *data, int width, int height,
+          void *surface, int stride, int format)
+{
+#if TIMING
+    struct timeval start_t, end_t;
+    struct timezone tz;
+    
+    gettimeofday(&start_t, &tz);
+#endif
+
+    switch (format) {
+    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+        decodeDXT1(data, width, height, surface, stride, false);
+        break;
+        
+    case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+        decodeDXT1(data, width, height, surface, stride, true);
+        break;
+        
+    case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+        decodeDXT3(data, width, height, surface, stride);
+        break;
+        
+    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+        decodeDXT5(data, width, height, surface, stride);
+        break;
+    }
+    
+#if TIMING
+    gettimeofday(&end_t, &tz);
+    long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 +
+        (end_t.tv_usec - start_t.tv_usec);
+    
+    printf("Loaded w=%d h=%d in %ld usec\n", width, height, usec);
+#endif
+}
+
+} // namespace android
diff --git a/opengl/libagl/dxt.h b/opengl/libagl/dxt.h
new file mode 100644
index 0000000..d95a36c
--- /dev/null
+++ b/opengl/libagl/dxt.h
@@ -0,0 +1,33 @@
+/* libs/opengles/dxt.h
+**
+** Copyright 2007, 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.
+*/
+
+#ifndef ANDROID_OPENGLES_TEXTURE_H
+#define ANDROID_OPENGLES_TEXTURE_H
+
+#include <stdlib.h>
+
+#include <GLES/gl.h>
+
+namespace android {
+
+  bool DXT1HasAlpha(const GLvoid *data, int width, int height);
+  void decodeDXT(const GLvoid *data, int width, int height,
+                 void *surface, int stride, int format);
+
+} // namespace android
+
+#endif // ANDROID_OPENGLES_TEXTURE_H
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
new file mode 100644
index 0000000..5b90bf0
--- /dev/null
+++ b/opengl/libagl/egl.cpp
@@ -0,0 +1,1543 @@
+/* 
+**
+** Copyright 2007 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.
+*/
+
+#define LOG_TAG "EGL"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+
+#include <utils/threads.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <pixelflinger/format.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include "context.h"
+#include "state.h"
+#include "texture.h"
+#include "matrix.h"
+
+#undef NELEM
+#define NELEM(x) (sizeof(x)/sizeof(*(x)))
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+const unsigned int NUM_DISPLAYS = 1;
+
+static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_key_t gEGLErrorKey = -1;
+#ifndef HAVE_ANDROID_OS
+namespace gl {
+pthread_key_t gGLKey = -1;
+}; // namespace gl
+#endif
+
+template<typename T>
+static T setError(GLint error, T returnValue) {
+    if (ggl_unlikely(gEGLErrorKey == -1)) {
+        pthread_mutex_lock(&gErrorKeyMutex);
+        if (gEGLErrorKey == -1)
+            pthread_key_create(&gEGLErrorKey, NULL);
+        pthread_mutex_unlock(&gErrorKeyMutex);
+    }
+    pthread_setspecific(gEGLErrorKey, (void*)error);
+    return returnValue;
+}
+
+static GLint getError() {
+    if (ggl_unlikely(gEGLErrorKey == -1))
+        return EGL_SUCCESS;
+    GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
+    pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
+    return error;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_display_t
+{
+    egl_display_t() : type(0), initialized(0) { }
+    
+    static egl_display_t& get_display(EGLDisplay dpy);
+    
+    static EGLBoolean is_valid(EGLDisplay dpy) {
+        return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
+    }
+
+    NativeDisplayType   type;
+    volatile int32_t    initialized;
+};
+
+static egl_display_t gDisplays[NUM_DISPLAYS];
+
+egl_display_t& egl_display_t::get_display(EGLDisplay dpy) {
+    return gDisplays[uintptr_t(dpy)-1U];
+}
+
+struct egl_context_t {
+    enum {
+        IS_CURRENT      =   0x00010000,
+        NEVER_CURRENT   =   0x00020000
+    };
+    uint32_t            flags;
+    EGLDisplay          dpy;
+    EGLConfig           config;
+    EGLSurface          read;
+    EGLSurface          draw;
+
+    static inline egl_context_t* context(EGLContext ctx) {
+        ogles_context_t* const gl = static_cast<ogles_context_t*>(ctx);
+        return static_cast<egl_context_t*>(gl->rasterizer.base);
+    }
+};
+
+// ----------------------------------------------------------------------------
+
+struct egl_surface_t
+{
+    enum {
+        PAGE_FLIP = 0x00000001,
+        MAGIC     = 0x31415265
+    };
+
+    uint32_t            magic;
+    EGLDisplay          dpy;
+    EGLConfig           config;
+    EGLContext          ctx;
+
+                egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
+    virtual     ~egl_surface_t();
+    virtual     bool    isValid() const = 0;
+    
+    virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl) = 0;
+    virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl) = 0;
+    virtual     EGLint      getWidth() const = 0;
+    virtual     EGLint      getHeight() const = 0;
+    virtual     void*       getBits() const = 0;
+
+    virtual     EGLint      getHorizontalResolution() const;
+    virtual     EGLint      getVerticalResolution() const;
+    virtual     EGLint      getRefreshRate() const;
+    virtual     EGLint      getSwapBehavior() const;
+    virtual     EGLBoolean  swapBuffers();
+protected:
+    GGLSurface              depth;
+};
+
+egl_surface_t::egl_surface_t(EGLDisplay dpy,
+        EGLConfig config,
+        int32_t depthFormat)
+    : magic(MAGIC), dpy(dpy), config(config), ctx(0)
+{
+    depth.version = sizeof(GGLSurface);
+    depth.data = 0;
+    depth.format = depthFormat;
+}
+egl_surface_t::~egl_surface_t()
+{
+    magic = 0;
+    free(depth.data);
+}
+EGLBoolean egl_surface_t::swapBuffers() {
+    return EGL_FALSE;
+}
+EGLint egl_surface_t::getHorizontalResolution() const {
+    return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_surface_t::getVerticalResolution() const {
+    return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_surface_t::getRefreshRate() const {
+    return (60 * EGL_DISPLAY_SCALING);
+}
+EGLint egl_surface_t::getSwapBehavior() const {
+    return EGL_BUFFER_PRESERVED;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_window_surface_t : public egl_surface_t
+{
+    egl_window_surface_t(
+            EGLDisplay dpy, EGLConfig config,
+            int32_t depthFormat,
+            egl_native_window_t* window);
+
+     ~egl_window_surface_t();
+
+    virtual     bool        isValid() const { return nativeWindow->magic == 0x600913; }    
+    virtual     EGLBoolean  swapBuffers();
+    virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl);
+    virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl);
+    virtual     EGLint      getWidth() const    { return nativeWindow->width;  }
+    virtual     EGLint      getHeight() const   { return nativeWindow->height; }
+    virtual     void*       getBits() const;
+    virtual     EGLint      getHorizontalResolution() const;
+    virtual     EGLint      getVerticalResolution() const;
+    virtual     EGLint      getRefreshRate() const;
+    virtual     EGLint      getSwapBehavior() const;
+private:
+    egl_native_window_t*    nativeWindow;
+};
+
+egl_window_surface_t::egl_window_surface_t(EGLDisplay dpy,
+        EGLConfig config,
+        int32_t depthFormat,
+        egl_native_window_t* window)
+    : egl_surface_t(dpy, config, depthFormat), nativeWindow(window)
+{
+    if (depthFormat) {
+        depth.width   = window->width;
+        depth.height  = window->height;
+        depth.stride  = depth.width; // use the width here
+        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        if (depth.data == 0) {
+            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+            return;
+        }
+    }
+    nativeWindow->incRef(nativeWindow);
+}
+egl_window_surface_t::~egl_window_surface_t() {
+    nativeWindow->decRef(nativeWindow);
+}
+
+EGLBoolean egl_window_surface_t::swapBuffers()
+{
+    uint32_t flags = nativeWindow->swapBuffers(nativeWindow);
+    if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
+        // TODO: we probably should reset the swap rect here
+        // if the window size has changed
+        if (depth.data) {
+            free(depth.data);
+            depth.width   = nativeWindow->width;
+            depth.height  = nativeWindow->height;
+            depth.stride  = nativeWindow->stride;
+            depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+            if (depth.data == 0) {
+                setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+                return EGL_FALSE;
+            }
+        }
+    }
+    return EGL_TRUE;
+}
+
+EGLBoolean egl_window_surface_t::bindDrawSurface(ogles_context_t* gl)
+{
+    GGLSurface buffer;
+    buffer.version = sizeof(GGLSurface);
+    buffer.width   = nativeWindow->width;
+    buffer.height  = nativeWindow->height;
+    buffer.stride  = nativeWindow->stride;
+    buffer.data    = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
+    buffer.format  = nativeWindow->format;
+    gl->rasterizer.procs.colorBuffer(gl, &buffer);
+    if (depth.data != gl->rasterizer.state.buffers.depth.data)
+        gl->rasterizer.procs.depthBuffer(gl, &depth);
+    return EGL_TRUE;
+}
+EGLBoolean egl_window_surface_t::bindReadSurface(ogles_context_t* gl)
+{
+    GGLSurface buffer;
+    buffer.version = sizeof(GGLSurface);
+    buffer.width   = nativeWindow->width;
+    buffer.height  = nativeWindow->height;
+    buffer.stride  = nativeWindow->stride;
+    buffer.data    = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
+    buffer.format  = nativeWindow->format;
+    gl->rasterizer.procs.readBuffer(gl, &buffer);
+    return EGL_TRUE;
+}
+void* egl_window_surface_t::getBits() const {
+    return (GGLubyte*)nativeWindow->base + nativeWindow->offset;
+}
+EGLint egl_window_surface_t::getHorizontalResolution() const {
+    return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_window_surface_t::getVerticalResolution() const {
+    return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_window_surface_t::getRefreshRate() const {
+    return (nativeWindow->fps * EGL_DISPLAY_SCALING);
+}
+EGLint egl_window_surface_t::getSwapBehavior() const {
+    uint32_t flags = nativeWindow->flags;
+    if (flags & EGL_NATIVES_FLAG_DESTROY_BACKBUFFER)
+        return EGL_BUFFER_DESTROYED;
+    return EGL_BUFFER_PRESERVED;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_pixmap_surface_t : public egl_surface_t
+{
+    egl_pixmap_surface_t(
+            EGLDisplay dpy, EGLConfig config,
+            int32_t depthFormat,
+            egl_native_pixmap_t const * pixmap);
+
+    virtual ~egl_pixmap_surface_t() { }
+
+    virtual     bool        isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); }    
+    virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl);
+    virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl);
+    virtual     EGLint      getWidth() const    { return nativePixmap.width;  }
+    virtual     EGLint      getHeight() const   { return nativePixmap.height; }
+    virtual     void*       getBits() const     { return nativePixmap.data; }
+private:
+    egl_native_pixmap_t     nativePixmap;
+};
+
+egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
+        EGLConfig config,
+        int32_t depthFormat,
+        egl_native_pixmap_t const * pixmap)
+    : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
+{
+    if (depthFormat) {
+        depth.width   = pixmap->width;
+        depth.height  = pixmap->height;
+        depth.stride  = depth.width; // use the width here
+        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        if (depth.data == 0) {
+            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+            return;
+        }
+    }
+}
+EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl)
+{
+    GGLSurface buffer;
+    buffer.version = sizeof(GGLSurface);
+    buffer.width   = nativePixmap.width;
+    buffer.height  = nativePixmap.height;
+    buffer.stride  = nativePixmap.stride;
+    buffer.data    = nativePixmap.data;
+    buffer.format  = nativePixmap.format;
+    
+    gl->rasterizer.procs.colorBuffer(gl, &buffer);
+    if (depth.data != gl->rasterizer.state.buffers.depth.data)
+        gl->rasterizer.procs.depthBuffer(gl, &depth);
+    return EGL_TRUE;
+}
+EGLBoolean egl_pixmap_surface_t::bindReadSurface(ogles_context_t* gl)
+{
+    GGLSurface buffer;
+    buffer.version = sizeof(GGLSurface);
+    buffer.width   = nativePixmap.width;
+    buffer.height  = nativePixmap.height;
+    buffer.stride  = nativePixmap.stride;
+    buffer.data    = nativePixmap.data;
+    buffer.format  = nativePixmap.format;
+    gl->rasterizer.procs.readBuffer(gl, &buffer);
+    return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_pbuffer_surface_t : public egl_surface_t
+{
+    egl_pbuffer_surface_t(
+            EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
+            int32_t w, int32_t h, int32_t f);
+
+    virtual ~egl_pbuffer_surface_t();
+
+    virtual     bool        isValid() const { return pbuffer.data != 0; }    
+    virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl);
+    virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl);
+    virtual     EGLint      getWidth() const    { return pbuffer.width;  }
+    virtual     EGLint      getHeight() const   { return pbuffer.height; }
+    virtual     void*       getBits() const     { return pbuffer.data; }
+private:
+    GGLSurface  pbuffer;
+};
+
+egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
+        EGLConfig config, int32_t depthFormat,
+        int32_t w, int32_t h, int32_t f)
+    : egl_surface_t(dpy, config, depthFormat)
+{
+    size_t size = w*h;
+    switch (f) {
+        case GGL_PIXEL_FORMAT_A_8:          size *= 1; break;
+        case GGL_PIXEL_FORMAT_RGB_565:      size *= 2; break;
+        case GGL_PIXEL_FORMAT_RGBA_8888:    size *= 4; break;
+        default:
+            LOGE("incompatible pixel format for pbuffer (format=%d)", f);
+            pbuffer.data = 0;
+            break;
+    }
+    pbuffer.version = sizeof(GGLSurface);
+    pbuffer.width   = w;
+    pbuffer.height  = h;
+    pbuffer.stride  = w;
+    pbuffer.data    = (GGLubyte*)malloc(size);
+    pbuffer.format  = f;
+    
+    if (depthFormat) {
+        depth.width   = pbuffer.width;
+        depth.height  = pbuffer.height;
+        depth.stride  = depth.width; // use the width here
+        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        if (depth.data == 0) {
+            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+            return;
+        }
+    }
+}
+egl_pbuffer_surface_t::~egl_pbuffer_surface_t() {
+    free(pbuffer.data);
+}
+EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(ogles_context_t* gl)
+{
+    gl->rasterizer.procs.colorBuffer(gl, &pbuffer);
+    if (depth.data != gl->rasterizer.state.buffers.depth.data)
+        gl->rasterizer.procs.depthBuffer(gl, &depth);
+    return EGL_TRUE;
+}
+EGLBoolean egl_pbuffer_surface_t::bindReadSurface(ogles_context_t* gl)
+{
+    gl->rasterizer.procs.readBuffer(gl, &pbuffer);
+    return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+
+struct config_pair_t {
+    GLint key;
+    GLint value;
+};
+
+struct configs_t {
+    const config_pair_t* array;
+    int                  size;
+};
+
+struct config_management_t {
+    GLint key;
+    bool (*match)(GLint reqValue, GLint confValue);
+    static bool atLeast(GLint reqValue, GLint confValue) {
+        return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
+    }
+    static bool exact(GLint reqValue, GLint confValue) {
+        return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
+    }
+    static bool mask(GLint reqValue, GLint confValue) {
+        return (confValue & reqValue) == reqValue;
+    }
+};
+
+// ----------------------------------------------------------------------------
+
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 2
+static char const * const gVendorString     = "Google Inc.";
+static char const * const gVersionString    = "1.2 Android Driver";
+static char const * const gClientApiString  = "OpenGL ES";
+static char const * const gExtensionsString = "";
+
+// ----------------------------------------------------------------------------
+
+struct extention_map_t {
+    const char * const name;
+    __eglMustCastToProperFunctionPointerType address;
+};
+
+static const extention_map_t gExtentionMap[] = {
+    { "glDrawTexsOES",              (void(*)())&glDrawTexsOES },
+    { "glDrawTexiOES",              (void(*)())&glDrawTexiOES },
+    { "glDrawTexfOES",              (void(*)())&glDrawTexfOES },
+    { "glDrawTexxOES",              (void(*)())&glDrawTexxOES },
+    { "glDrawTexsvOES",             (void(*)())&glDrawTexsvOES },
+    { "glDrawTexivOES",             (void(*)())&glDrawTexivOES },
+    { "glDrawTexfvOES",             (void(*)())&glDrawTexfvOES },
+    { "glDrawTexxvOES",             (void(*)())&glDrawTexxvOES },
+    { "glQueryMatrixxOES",          (void(*)())&glQueryMatrixxOES },
+    { "glClipPlanef",               (void(*)())&glClipPlanef },
+    { "glClipPlanex",               (void(*)())&glClipPlanex },
+    { "glBindBuffer",               (void(*)())&glBindBuffer },
+    { "glBufferData",               (void(*)())&glBufferData },
+    { "glBufferSubData",            (void(*)())&glBufferSubData },
+    { "glDeleteBuffers",            (void(*)())&glDeleteBuffers },
+    { "glGenBuffers",               (void(*)())&glGenBuffers },
+};
+
+/* 
+ * In the lists below, attributes names MUST be sorted.
+ * Additionally, all configs must be sorted according to
+ * the EGL specification.
+ */
+
+static config_pair_t const config_base_attribute_list[] = {
+        { EGL_STENCIL_SIZE,               0                                 },
+        { EGL_CONFIG_CAVEAT,              EGL_SLOW_CONFIG                   },
+        { EGL_LEVEL,                      0                                 },
+        { EGL_MAX_PBUFFER_HEIGHT,         GGL_MAX_VIEWPORT_DIMS             },
+        { EGL_MAX_PBUFFER_PIXELS,         
+                GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS                 },
+        { EGL_MAX_PBUFFER_WIDTH,          GGL_MAX_VIEWPORT_DIMS             },
+        { EGL_NATIVE_RENDERABLE,          EGL_TRUE                          },
+        { EGL_NATIVE_VISUAL_ID,           0                                 },
+        { EGL_NATIVE_VISUAL_TYPE,         GGL_PIXEL_FORMAT_RGB_565          },
+        { EGL_SAMPLES,                    0                                 },
+        { EGL_SAMPLE_BUFFERS,             0                                 },
+        { EGL_TRANSPARENT_TYPE,           EGL_NONE                          },
+        { EGL_TRANSPARENT_BLUE_VALUE,     0                                 },
+        { EGL_TRANSPARENT_GREEN_VALUE,    0                                 },
+        { EGL_TRANSPARENT_RED_VALUE,      0                                 },
+        { EGL_BIND_TO_TEXTURE_RGBA,       EGL_FALSE                         },
+        { EGL_BIND_TO_TEXTURE_RGB,        EGL_FALSE                         },
+        { EGL_MIN_SWAP_INTERVAL,          1                                 },
+        { EGL_MAX_SWAP_INTERVAL,          4                                 },
+};
+
+// These configs can override the base attribute list
+// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
+
+static config_pair_t const config_0_attribute_list[] = {
+        { EGL_BUFFER_SIZE,     16 },
+        { EGL_ALPHA_SIZE,       0 },
+        { EGL_BLUE_SIZE,        5 },
+        { EGL_GREEN_SIZE,       6 },
+        { EGL_RED_SIZE,         5 },
+        { EGL_DEPTH_SIZE,       0 },
+        { EGL_CONFIG_ID,        0 },
+        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_1_attribute_list[] = {
+        { EGL_BUFFER_SIZE,     16 },
+        { EGL_ALPHA_SIZE,       0 },
+        { EGL_BLUE_SIZE,        5 },
+        { EGL_GREEN_SIZE,       6 },
+        { EGL_RED_SIZE,         5 },
+        { EGL_DEPTH_SIZE,      16 },
+        { EGL_CONFIG_ID,        1 },
+        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_2_attribute_list[] = {
+        { EGL_BUFFER_SIZE,     32 },
+        { EGL_ALPHA_SIZE,       8 },
+        { EGL_BLUE_SIZE,        8 },
+        { EGL_GREEN_SIZE,       8 },
+        { EGL_RED_SIZE,         8 },
+        { EGL_DEPTH_SIZE,       0 },
+        { EGL_CONFIG_ID,        2 },
+        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_3_attribute_list[] = {
+        { EGL_BUFFER_SIZE,     32 },
+        { EGL_ALPHA_SIZE,       8 },
+        { EGL_BLUE_SIZE,        8 },
+        { EGL_GREEN_SIZE,       8 },
+        { EGL_RED_SIZE,         8 },
+        { EGL_DEPTH_SIZE,      16 },
+        { EGL_CONFIG_ID,        3 },
+        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_4_attribute_list[] = {
+        { EGL_BUFFER_SIZE,      8 },
+        { EGL_ALPHA_SIZE,       8 },
+        { EGL_BLUE_SIZE,        0 },
+        { EGL_GREEN_SIZE,       0 },
+        { EGL_RED_SIZE,         0 },
+        { EGL_DEPTH_SIZE,       0 },
+        { EGL_CONFIG_ID,        4 },
+        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_5_attribute_list[] = {
+        { EGL_BUFFER_SIZE,      8 },
+        { EGL_ALPHA_SIZE,       8 },
+        { EGL_BLUE_SIZE,        0 },
+        { EGL_GREEN_SIZE,       0 },
+        { EGL_RED_SIZE,         0 },
+        { EGL_DEPTH_SIZE,      16 },
+        { EGL_CONFIG_ID,        5 },
+        { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
+static configs_t const gConfigs[] = {
+        { config_0_attribute_list, NELEM(config_0_attribute_list) },
+        { config_1_attribute_list, NELEM(config_1_attribute_list) },
+        { config_2_attribute_list, NELEM(config_2_attribute_list) },
+        { config_3_attribute_list, NELEM(config_3_attribute_list) },
+        { config_4_attribute_list, NELEM(config_4_attribute_list) },
+        { config_5_attribute_list, NELEM(config_5_attribute_list) },
+};
+
+static config_management_t const gConfigManagement[] = {
+        { EGL_BUFFER_SIZE,                config_management_t::atLeast },
+        { EGL_ALPHA_SIZE,                 config_management_t::atLeast },
+        { EGL_BLUE_SIZE,                  config_management_t::atLeast },
+        { EGL_GREEN_SIZE,                 config_management_t::atLeast },
+        { EGL_RED_SIZE,                   config_management_t::atLeast },
+        { EGL_DEPTH_SIZE,                 config_management_t::atLeast },
+        { EGL_STENCIL_SIZE,               config_management_t::atLeast },
+        { EGL_CONFIG_CAVEAT,              config_management_t::exact   },
+        { EGL_CONFIG_ID,                  config_management_t::exact   },
+        { EGL_LEVEL,                      config_management_t::exact   },
+        { EGL_MAX_PBUFFER_HEIGHT,         config_management_t::exact   },
+        { EGL_MAX_PBUFFER_PIXELS,         config_management_t::exact   },
+        { EGL_MAX_PBUFFER_WIDTH,          config_management_t::exact   },
+        { EGL_NATIVE_RENDERABLE,          config_management_t::exact   },
+        { EGL_NATIVE_VISUAL_ID,           config_management_t::exact   },
+        { EGL_NATIVE_VISUAL_TYPE,         config_management_t::exact   },
+        { EGL_SAMPLES,                    config_management_t::exact   },
+        { EGL_SAMPLE_BUFFERS,             config_management_t::exact   },
+        { EGL_SURFACE_TYPE,               config_management_t::mask    },
+        { EGL_TRANSPARENT_TYPE,           config_management_t::exact   },
+        { EGL_TRANSPARENT_BLUE_VALUE,     config_management_t::exact   },
+        { EGL_TRANSPARENT_GREEN_VALUE,    config_management_t::exact   },
+        { EGL_TRANSPARENT_RED_VALUE,      config_management_t::exact   },
+        { EGL_BIND_TO_TEXTURE_RGBA,       config_management_t::exact   },
+        { EGL_BIND_TO_TEXTURE_RGB,        config_management_t::exact   },
+        { EGL_MIN_SWAP_INTERVAL,          config_management_t::exact   },
+        { EGL_MAX_SWAP_INTERVAL,          config_management_t::exact   },
+};
+
+static config_pair_t const config_defaults[] = {
+        { EGL_SURFACE_TYPE,        EGL_WINDOW_BIT },
+};
+
+// ----------------------------------------------------------------------------
+
+template<typename T>
+static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
+{
+   while (first <= last) {
+       int mid = (first + last) / 2;
+       if (key > sortedArray[mid].key) { 
+           first = mid + 1;
+       } else if (key < sortedArray[mid].key) { 
+           last = mid - 1;
+       } else {
+           return mid;
+       }
+   }
+   return -1;
+}
+
+static int isAttributeMatching(int i, EGLint attr, EGLint val)
+{
+    // look for the attribute in all of our configs
+    config_pair_t const* configFound = gConfigs[i].array; 
+    int index = binarySearch<config_pair_t>(
+            gConfigs[i].array,
+            0, gConfigs[i].size-1,
+            attr);
+    if (index < 0) {
+        configFound = config_base_attribute_list; 
+        index = binarySearch<config_pair_t>(
+                config_base_attribute_list,
+                0, NELEM(config_base_attribute_list)-1,
+                attr);
+    }
+    if (index >= 0) {
+        // attribute found, check if this config could match
+        int cfgMgtIndex = binarySearch<config_management_t>(
+                gConfigManagement,
+                0, NELEM(gConfigManagement)-1,
+                attr);
+        if (index >= 0) {
+            bool match = gConfigManagement[cfgMgtIndex].match(
+                    val, configFound[index].value);
+            if (match) {
+                // this config matches
+                return 1;
+            }
+        } else {
+            // attribute not found. this should NEVER happen.
+        }
+    } else {
+        // error, this attribute doesn't exist
+    }
+    return 0;
+}
+
+static int makeCurrent(ogles_context_t* gl)
+{
+    ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();
+    if (gl) {
+        egl_context_t* c = egl_context_t::context(gl);
+        if (c->flags & egl_context_t::IS_CURRENT) {
+            if (current != gl) {
+                // it is an error to set a context current, if it's already
+                // current to another thread
+                return -1;
+            }
+        } else {
+            if (current) {
+                // mark the current context as not current, and flush
+                glFlush();
+                egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
+            }
+        }
+        if (!(c->flags & egl_context_t::IS_CURRENT)) {
+            // The context is not current, make it current!
+            setGlThreadSpecific(gl);
+            c->flags |= egl_context_t::IS_CURRENT;
+        }
+    } else {
+        if (current) {
+            // mark the current context as not current, and flush
+            glFlush();
+            egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
+        }
+        // this thread has no context attached to it
+        setGlThreadSpecific(0);
+    }
+    return 0;
+}
+
+static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
+        EGLint attribute, EGLint *value)
+{
+    size_t numConfigs =  NELEM(gConfigs);
+    int index = (int)config;
+    if (uint32_t(index) >= numConfigs)
+        return setError(EGL_BAD_CONFIG, EGL_FALSE);
+
+    int attrIndex;
+    attrIndex = binarySearch<config_pair_t>(
+            gConfigs[index].array,
+            0, gConfigs[index].size-1,
+            attribute);
+    if (attrIndex>=0) {
+        *value = gConfigs[index].array[attrIndex].value;
+        return EGL_TRUE;
+    }
+
+    attrIndex = binarySearch<config_pair_t>(
+            config_base_attribute_list,
+            0, NELEM(config_base_attribute_list)-1,
+            attribute);
+    if (attrIndex>=0) {
+        *value = config_base_attribute_list[attrIndex].value;
+        return EGL_TRUE;
+    }
+    return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+}
+
+static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
+        NativeWindowType window, const EGLint *attrib_list)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+    if (window == 0)
+        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+    EGLint surfaceType;
+    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+        return EGL_FALSE;
+
+    if (!(surfaceType & EGL_WINDOW_BIT))
+        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+    EGLint configID;
+    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+        return EGL_FALSE;
+
+    int32_t depthFormat;
+    int32_t pixelFormat;
+    switch(configID) {
+    case 0: 
+        pixelFormat = GGL_PIXEL_FORMAT_RGB_565; 
+        depthFormat = 0;
+        break;
+    case 1:
+        pixelFormat = GGL_PIXEL_FORMAT_RGB_565; 
+        depthFormat = GGL_PIXEL_FORMAT_Z_16;
+        break;
+    case 2:
+        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; 
+        depthFormat = 0;
+        break;
+    case 3:
+        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; 
+        depthFormat = GGL_PIXEL_FORMAT_Z_16;
+        break;
+    case 4:
+        pixelFormat = GGL_PIXEL_FORMAT_A_8; 
+        depthFormat = 0;
+        break;
+    case 5:
+        pixelFormat = GGL_PIXEL_FORMAT_A_8; 
+        depthFormat = GGL_PIXEL_FORMAT_Z_16;
+        break;
+    default:
+        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+    }
+
+    // FIXME: we don't have access to the pixelFormat here just yet.
+    // (it's possible that the surface is not fully initialized)
+    // maybe this should be done after the page-flip
+    //if (EGLint(info.format) != pixelFormat)
+    //    return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+    egl_surface_t* surface =
+        new egl_window_surface_t(dpy, config, depthFormat,
+                static_cast<egl_native_window_t*>(window));
+
+    if (!surface->isValid()) {
+        // there was a problem in the ctor, the error
+        // flag has been set.
+        delete surface;
+        surface = 0;
+    }
+    return surface;
+}
+
+static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
+        NativePixmapType pixmap, const EGLint *attrib_list)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+    if (pixmap == 0)
+        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+    EGLint surfaceType;
+    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+        return EGL_FALSE;
+
+    if (!(surfaceType & EGL_PIXMAP_BIT))
+        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+    EGLint configID;
+    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+        return EGL_FALSE;
+
+    int32_t depthFormat;
+    int32_t pixelFormat;
+    switch(configID) {
+    case 0: 
+        pixelFormat = GGL_PIXEL_FORMAT_RGB_565; 
+        depthFormat = 0;
+        break;
+    case 1:
+        pixelFormat = GGL_PIXEL_FORMAT_RGB_565; 
+        depthFormat = GGL_PIXEL_FORMAT_Z_16;
+        break;
+    case 2:
+        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; 
+        depthFormat = 0;
+        break;
+    case 3:
+        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; 
+        depthFormat = GGL_PIXEL_FORMAT_Z_16;
+        break;
+    case 4:
+        pixelFormat = GGL_PIXEL_FORMAT_A_8; 
+        depthFormat = 0;
+        break;
+    case 5:
+        pixelFormat = GGL_PIXEL_FORMAT_A_8; 
+        depthFormat = GGL_PIXEL_FORMAT_Z_16;
+        break;
+    default:
+        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+    }
+
+    if (pixmap->format != pixelFormat)
+        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+    egl_surface_t* surface =
+        new egl_pixmap_surface_t(dpy, config, depthFormat,
+                static_cast<egl_native_pixmap_t*>(pixmap));
+
+    if (!surface->isValid()) {
+        // there was a problem in the ctor, the error
+        // flag has been set.
+        delete surface;
+        surface = 0;
+    }
+    return surface;
+}
+
+static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
+        const EGLint *attrib_list)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+
+    EGLint surfaceType;
+    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+        return EGL_FALSE;
+    
+    if (!(surfaceType & EGL_PBUFFER_BIT))
+        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+        
+    EGLint configID;
+    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+        return EGL_FALSE;
+
+    int32_t depthFormat;
+    int32_t pixelFormat;
+    switch(configID) {
+    case 0: 
+        pixelFormat = GGL_PIXEL_FORMAT_RGB_565; 
+        depthFormat = 0;
+        break;
+    case 1:
+        pixelFormat = GGL_PIXEL_FORMAT_RGB_565; 
+        depthFormat = GGL_PIXEL_FORMAT_Z_16;
+        break;
+    case 2:
+        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; 
+        depthFormat = 0;
+        break;
+    case 3:
+        pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; 
+        depthFormat = GGL_PIXEL_FORMAT_Z_16;
+        break;
+    case 4:
+        pixelFormat = GGL_PIXEL_FORMAT_A_8; 
+        depthFormat = 0;
+        break;
+    case 5:
+        pixelFormat = GGL_PIXEL_FORMAT_A_8; 
+        depthFormat = GGL_PIXEL_FORMAT_Z_16;
+        break;
+    default:
+        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+    }
+
+    int32_t w = 0;
+    int32_t h = 0;
+    while (attrib_list[0]) {
+        if (attrib_list[0] == EGL_WIDTH)  w = attrib_list[1];
+        if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
+        attrib_list+=2;
+    }
+
+    egl_surface_t* surface =
+        new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
+
+    if (!surface->isValid()) {
+        // there was a problem in the ctor, the error
+        // flag has been set.
+        delete surface;
+        surface = 0;
+    }
+    return surface;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+// Initialization
+// ----------------------------------------------------------------------------
+
+EGLDisplay eglGetDisplay(NativeDisplayType display)
+{
+#ifndef HAVE_ANDROID_OS
+    // this just needs to be done once
+    if (gGLKey == -1) {
+        pthread_mutex_lock(&gInitMutex);
+        if (gGLKey == -1)
+            pthread_key_create(&gGLKey, NULL);
+        pthread_mutex_unlock(&gInitMutex);
+    }
+#endif
+    if (display == EGL_DEFAULT_DISPLAY) {
+        EGLDisplay dpy = (EGLDisplay)1;
+        egl_display_t& d = egl_display_t::get_display(dpy);
+        d.type = display;
+        return dpy;
+    }    
+    return EGL_NO_DISPLAY;
+}
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    
+    EGLBoolean res = EGL_TRUE;
+    egl_display_t& d = egl_display_t::get_display(dpy);
+    
+    if (android_atomic_inc(&d.initialized) == 0) {
+        // initialize stuff here if needed
+        //pthread_mutex_lock(&gInitMutex);
+        //pthread_mutex_unlock(&gInitMutex);
+    }
+
+    if (res == EGL_TRUE) {
+        if (major != NULL) *major = VERSION_MAJOR;
+        if (minor != NULL) *minor = VERSION_MINOR;
+    }
+    return res;
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+    EGLBoolean res = EGL_TRUE;
+    egl_display_t& d = egl_display_t::get_display(dpy);
+    if (android_atomic_dec(&d.initialized) == 1) {
+        // TODO: destroy all resources (surfaces, contexts, etc...)
+        //pthread_mutex_lock(&gInitMutex);
+        //pthread_mutex_unlock(&gInitMutex);
+    }
+    return res;
+}
+
+// ----------------------------------------------------------------------------
+// configuration
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglGetConfigs(   EGLDisplay dpy,
+                            EGLConfig *configs,
+                            EGLint config_size, EGLint *num_config)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+    GLint numConfigs = NELEM(gConfigs);
+    if (!configs) {
+        *num_config = numConfigs;
+        return EGL_TRUE;
+    }
+    GLint i;
+    for (i=0 ; i<numConfigs && i<config_size ; i++) {
+        *configs++ = (EGLConfig)i;
+    }
+    *num_config = i;
+    return EGL_TRUE;
+}
+
+EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
+                            EGLConfig *configs, EGLint config_size,
+                            EGLint *num_config)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+    if (ggl_unlikely(configs==0 || attrib_list==0)) {
+        *num_config = 0;
+        return EGL_TRUE;
+    }
+    
+    int numAttributes = 0;
+    int numConfigs =  NELEM(gConfigs);
+    uint32_t possibleMatch = (1<<numConfigs)-1;
+    while(possibleMatch && *attrib_list != EGL_NONE) {
+        numAttributes++;
+        EGLint attr = *attrib_list++;
+        EGLint val  = *attrib_list++;
+        for (int i=0 ; i<numConfigs ; i++) {
+            if (!(possibleMatch & (1<<i)))
+                continue;
+            if (isAttributeMatching(i, attr, val) == 0) {
+                possibleMatch &= ~(1<<i);
+            }
+        }
+    }
+
+    // now, handle the attributes which have a useful default value
+    for (size_t j=0 ; j<NELEM(config_defaults) ; j++) {
+        // see if this attribute was specified, if not apply its
+        // default value
+        if (binarySearch<config_pair_t>(
+                (config_pair_t const*)attrib_list,
+                0, numAttributes,
+                config_defaults[j].key) < 0)
+        {
+            for (int i=0 ; i<numConfigs ; i++) {
+                if (!(possibleMatch & (1<<i)))
+                    continue;
+                if (isAttributeMatching(i,
+                        config_defaults[j].key,
+                        config_defaults[j].value) == 0)
+                {
+                    possibleMatch &= ~(1<<i);
+                }
+            }
+        }
+    }
+
+    // return the configurations found
+    int n=0;
+    if (possibleMatch) {
+        for (int i=0 ; config_size && i<numConfigs ; i++) {
+            if (possibleMatch & (1<<i)) {
+               *configs++ = (EGLConfig)i;
+                config_size--;
+                n++;
+            }
+        }
+    }
+    *num_config = n;
+     return EGL_TRUE;
+}
+
+EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+        EGLint attribute, EGLint *value)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+    return getConfigAttrib(dpy, config, attribute, value);
+}
+
+// ----------------------------------------------------------------------------
+// surfaces
+// ----------------------------------------------------------------------------
+
+EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
+                                    NativeWindowType window,
+                                    const EGLint *attrib_list)
+{
+    return createWindowSurface(dpy, config, window, attrib_list);
+}
+    
+EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
+                                    NativePixmapType pixmap,
+                                    const EGLint *attrib_list)
+{
+    return createPixmapSurface(dpy, config, pixmap, attrib_list);
+}
+
+EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
+                                    const EGLint *attrib_list)
+{
+    return createPbufferSurface(dpy, config, attrib_list);
+}
+                                    
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    if (eglSurface != EGL_NO_SURFACE) {
+        egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
+        if (surface->magic != egl_surface_t::MAGIC)
+            return setError(EGL_BAD_SURFACE, EGL_FALSE);
+        if (surface->dpy != dpy)
+            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+        delete surface;
+    }
+    return EGL_TRUE;
+}
+
+EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
+                            EGLint attribute, EGLint *value)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
+    if (surface->dpy != dpy)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+    EGLBoolean ret = EGL_TRUE;
+    switch (attribute) {
+        case EGL_CONFIG_ID:
+            ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
+            break;
+        case EGL_WIDTH:
+            *value = surface->getWidth();
+            break;
+        case EGL_HEIGHT:
+            *value = surface->getHeight();
+            break;
+        case EGL_LARGEST_PBUFFER:
+            // not modified for a window or pixmap surface
+            break;
+        case EGL_TEXTURE_FORMAT:
+            *value = EGL_NO_TEXTURE;
+            break;
+        case EGL_TEXTURE_TARGET:
+            *value = EGL_NO_TEXTURE;
+            break;
+        case EGL_MIPMAP_TEXTURE:
+            *value = EGL_FALSE;
+            break;
+        case EGL_MIPMAP_LEVEL:
+            *value = 0;
+            break;
+        case EGL_RENDER_BUFFER:
+            // TODO: return the real RENDER_BUFFER here
+            *value = EGL_BACK_BUFFER;
+            break;
+        case EGL_HORIZONTAL_RESOLUTION:
+            // pixel/mm * EGL_DISPLAY_SCALING
+            *value = surface->getHorizontalResolution();
+            break;
+        case EGL_VERTICAL_RESOLUTION:
+            // pixel/mm * EGL_DISPLAY_SCALING
+            *value = surface->getVerticalResolution();
+            break;
+        case EGL_PIXEL_ASPECT_RATIO: {
+            // w/h * EGL_DISPLAY_SCALING
+            int wr = surface->getHorizontalResolution();
+            int hr = surface->getVerticalResolution();
+            *value = (wr * EGL_DISPLAY_SCALING) / hr;
+        } break;
+        case EGL_SWAP_BEHAVIOR:
+            *value = surface->getSwapBehavior(); 
+            break;
+        default:
+            ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+    }
+    return ret;
+}
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+                            EGLContext share_list, const EGLint *attrib_list)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+
+    ogles_context_t* gl = ogles_init(sizeof(egl_context_t));
+    if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+
+    egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
+    c->flags = egl_context_t::NEVER_CURRENT;
+    c->dpy = dpy;
+    c->config = config;
+    c->read = 0;
+    c->draw = 0;
+    return (EGLContext)gl;
+}
+
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    egl_context_t* c = egl_context_t::context(ctx);
+    if (c->flags & egl_context_t::IS_CURRENT)
+        setGlThreadSpecific(0);
+    ogles_uninit((ogles_context_t*)ctx);
+    return EGL_TRUE;
+}
+
+EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
+                            EGLSurface read, EGLContext ctx)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    if (draw) {
+        egl_surface_t* s = (egl_surface_t*)draw;
+        if (s->dpy != dpy)
+            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+        // TODO: check that draw and read are compatible with the context
+    }
+
+    EGLContext current_ctx = EGL_NO_CONTEXT;
+    
+    if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
+        return setError(EGL_BAD_MATCH, EGL_FALSE);
+
+    if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
+        return setError(EGL_BAD_MATCH, EGL_FALSE);
+
+    if (ctx == EGL_NO_CONTEXT) {
+        // if we're detaching, we need the current context
+        current_ctx = (EGLContext)getGlThreadSpecific();
+    } else {
+        egl_context_t* c = egl_context_t::context(ctx);
+        egl_surface_t* d = (egl_surface_t*)draw;
+        egl_surface_t* r = (egl_surface_t*)read;
+        if ((d && d->ctx && d->ctx != ctx) ||
+            (r && r->ctx && r->ctx != ctx)) {
+            // once of the surface is bound to a context in another thread
+            return setError(EGL_BAD_ACCESS, EGL_FALSE);
+        }
+    }
+
+    ogles_context_t* gl = (ogles_context_t*)ctx;
+    if (makeCurrent(gl) == 0) {
+        if (ctx) {
+            egl_context_t* c = egl_context_t::context(ctx);
+            egl_surface_t* d = (egl_surface_t*)draw;
+            egl_surface_t* r = (egl_surface_t*)read;
+            c->read = read;
+            c->draw = draw;
+            if (c->flags & egl_context_t::NEVER_CURRENT) {
+                c->flags &= ~egl_context_t::NEVER_CURRENT;
+                GLint w = 0;
+                GLint h = 0;
+                if (draw) {
+                    w = d->getWidth();
+                    h = d->getHeight();
+                }
+                ogles_surfaceport(gl, 0, 0);
+                ogles_viewport(gl, 0, 0, w, h);
+                ogles_scissor(gl, 0, 0, w, h);
+            }
+            if (d) {
+                d->ctx = ctx;
+                d->bindDrawSurface(gl);
+            }
+            if (r) {
+                r->ctx = ctx;
+                r->bindReadSurface(gl);
+            }
+        } else {
+            // if surfaces were bound to the context bound to this thread
+            // mark then as unbound.
+            if (current_ctx) {
+                egl_context_t* c = egl_context_t::context(current_ctx);
+                egl_surface_t* d = (egl_surface_t*)c->draw;
+                egl_surface_t* r = (egl_surface_t*)c->read;
+                if (d) d->ctx = EGL_NO_CONTEXT;
+                if (r) r->ctx = EGL_NO_CONTEXT;
+            }
+        }
+        return EGL_TRUE;
+    }
+    return setError(EGL_BAD_ACCESS, EGL_FALSE);
+}
+
+EGLContext eglGetCurrentContext(void)
+{
+    // eglGetCurrentContext returns the current EGL rendering context,
+    // as specified by eglMakeCurrent. If no context is current,
+    // EGL_NO_CONTEXT is returned.
+    return (EGLContext)getGlThreadSpecific();
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw)
+{
+    // eglGetCurrentSurface returns the read or draw surface attached
+    // to the current EGL rendering context, as specified by eglMakeCurrent.
+    // If no context is current, EGL_NO_SURFACE is returned.
+    EGLContext ctx = (EGLContext)getGlThreadSpecific();
+    if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
+    egl_context_t* c = egl_context_t::context(ctx);
+    if (readdraw == EGL_READ) {
+        return c->read;
+    } else if (readdraw == EGL_DRAW) {
+        return c->draw;
+    }
+    return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+}
+
+EGLDisplay eglGetCurrentDisplay(void)
+{
+    // eglGetCurrentDisplay returns the current EGL display connection
+    // for the current EGL rendering context, as specified by eglMakeCurrent.
+    // If no context is current, EGL_NO_DISPLAY is returned.
+    EGLContext ctx = (EGLContext)getGlThreadSpecific();
+    if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
+    egl_context_t* c = egl_context_t::context(ctx);
+    return c->dpy;
+}
+
+EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
+                            EGLint attribute, EGLint *value)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    egl_context_t* c = egl_context_t::context(ctx);
+    switch (attribute) {
+        case EGL_CONFIG_ID:
+            // Returns the ID of the EGL frame buffer configuration with
+            // respect to which the context was created
+            return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
+    }
+    return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+}
+
+EGLBoolean eglWaitGL(void)
+{
+    return EGL_TRUE;
+}
+
+EGLBoolean eglWaitNative(EGLint engine)
+{
+    return EGL_TRUE;
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    
+    egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+    if (d->dpy != dpy)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+    // post the surface
+    d->swapBuffers();
+
+    // if it's bound to a context, update the buffer
+    if (d->ctx != EGL_NO_CONTEXT) {
+        d->bindDrawSurface((ogles_context_t*)d->ctx);
+        // if this surface is also the read surface of the context
+        // it is bound to, make sure to update the read buffer as well.
+        // The EGL spec is a little unclear about this.
+        egl_context_t* c = egl_context_t::context(d->ctx);
+        if (c->read == draw) {
+            d->bindReadSurface((ogles_context_t*)d->ctx);
+        }
+    }
+
+    return EGL_TRUE;
+}
+
+EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
+                            NativePixmapType target)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    // TODO: eglCopyBuffers()
+    return EGL_FALSE;
+}
+
+EGLint eglGetError(void)
+{
+    return getError();
+}
+
+const char* eglQueryString(EGLDisplay dpy, EGLint name)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, (const char*)0);
+
+    switch (name) {
+        case EGL_VENDOR:
+            return gVendorString;
+        case EGL_VERSION:
+            return gVersionString;
+        case EGL_EXTENSIONS:
+            return gExtensionsString;
+        case EGL_CLIENT_APIS:
+            return gClientApiString;
+    }
+    return setError(EGL_BAD_PARAMETER, (const char *)0);
+}
+
+// ----------------------------------------------------------------------------
+// EGL 1.1
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSurfaceAttrib(
+        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    // TODO: eglSurfaceAttrib()
+    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+EGLBoolean eglBindTexImage(
+        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    // TODO: eglBindTexImage()
+    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+EGLBoolean eglReleaseTexImage(
+        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    // TODO: eglReleaseTexImage()
+    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    // TODO: eglSwapInterval()
+    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+// ----------------------------------------------------------------------------
+// EGL 1.2
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglBindAPI(EGLenum api)
+{
+    if (api != EGL_OPENGL_ES_API)
+        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+    return EGL_TRUE;
+}
+
+EGLenum eglQueryAPI(void)
+{
+    return EGL_OPENGL_ES_API;
+}
+
+EGLBoolean eglWaitClient(void)
+{
+    glFinish();
+    return EGL_TRUE;
+}
+
+EGLBoolean eglReleaseThread(void)
+{
+    // TODO: eglReleaseThread()
+    return EGL_TRUE;
+}
+
+EGLSurface eglCreatePbufferFromClientBuffer(
+          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+          EGLConfig config, const EGLint *attrib_list)
+{
+    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+    // TODO: eglCreatePbufferFromClientBuffer()
+    return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+}
+
+// ----------------------------------------------------------------------------
+// Android extensions
+// ----------------------------------------------------------------------------
+
+void (*eglGetProcAddress (const char *procname))()
+{
+    extention_map_t const * const map = gExtentionMap;
+    for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
+        if (!strcmp(procname, map[i].name)) {
+            return map[i].address;
+        }
+    }
+    return NULL;
+}
diff --git a/opengl/libagl/fixed_asm.S b/opengl/libagl/fixed_asm.S
new file mode 100644
index 0000000..6cbc56f
--- /dev/null
+++ b/opengl/libagl/fixed_asm.S
@@ -0,0 +1,65 @@
+/* libs/opengles/fixed_asm.S
+**
+** Copyright 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.
+*/
+
+
+    .text
+    .align
+    
+    .global gglFloatToFixed
+    .global gglFloatToFixedFast
+
+
+/*
+ * Converts a float to a s15.16 fixed-point number.
+ * this doesn't handle floats out of the [-32768, +32768[ range
+ * and doesn't performs round-to-nearest.
+ * however, it's very fast :-)
+ */
+
+gglFloatToFixedFast:
+        movs    r1, r0, lsl #1          /* remove bit sign */
+        mov     r2, #0x8E               /* 127 + 15 */
+        sub     r1, r2, r1, lsr #24     /* compute shift */
+        mov     r2, r0, lsl #8          /* mantissa<<8 */
+        orr     r2, r2, #0x80000000     /* add the missing 1 */
+        mov     r0, r2, lsr r1          /* scale to 16.16 */
+        rsbcs   r0, r0, #0              /* negate if needed */
+        bx      lr
+
+/*
+ * this version rounds-to-nearest and saturates numbers
+ * outside the range (but not NaNs).
+ */
+
+gglFloatToFixed:
+        mov     r1, r0, lsl #1          /* remove bit sign */
+        mov     r2, #0x8E               /* 127 + 15 */
+        subs    r1, r2, r1, lsr #24     /* compute shift */
+        bls     0f                      /* too big */
+        mov     r2, r0, lsl #8          /* mantissa<<8 */
+        orr     r2, r2, #0x80000000     /* add the missing 1 */
+        mov     r3, r0
+        movs    r0, r2, lsr r1          /* scale to 16.16 */
+        addcs   r0, r0, #1              /* round-to-nearest */
+        tst     r3, #0x80000000         /* negative? */
+        rsbne   r0, r0, #0              /* negate if needed */
+        bx      lr 
+ 
+0:      ands    r0, r0, #0x80000000     /* keep only the sign bit */
+        moveq   r0, #0x7fffffff         /* positive, maximum value */
+        bx      lr
+
diff --git a/opengl/libagl/fp.cpp b/opengl/libagl/fp.cpp
new file mode 100644
index 0000000..ae5f1fe
--- /dev/null
+++ b/opengl/libagl/fp.cpp
@@ -0,0 +1,87 @@
+/* libs/opengles/fp.cpp
+**
+** Copyright 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 "fp.h"
+
+// ----------------------------------------------------------------------------
+
+#if !defined(__arm__)
+GGLfixed gglFloatToFixed(float v) {   
+    return GGLfixed(floorf(v * 65536.0f + 0.5f));
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+namespace gl {
+
+GLfloat fixedToFloat(GLfixed x)
+{
+#if DEBUG_USE_FLOATS
+    return x / 65536.0f;
+#else
+    if (!x) return 0;
+    const uint32_t s = x & 0x80000000;
+    union {
+        uint32_t i;
+        float f;
+    };
+    i = s ? -x : x;
+    const int c = gglClz(i) - 8;
+    i = (c>=0) ? (i<<c) : (i>>-c);
+    const uint32_t e = 134 - c;
+    i &= ~0x800000;
+    i |= e<<23;
+    i |= s;
+    return f;
+#endif
+}
+
+float sinef(float x)
+{
+    const float A =   1.0f / (2.0f*M_PI);
+    const float B = -16.0f;
+    const float C =   8.0f;
+
+    // scale angle for easy argument reduction
+    x *= A;
+    
+    if (fabsf(x) >= 0.5f) {
+        // Argument reduction
+        x = x - ceilf(x + 0.5f) + 1.0f; 
+    }
+
+    const float y = B*x*fabsf(x) + C*x;
+    return 0.2215f * (y*fabsf(y) - y) + y;
+}
+
+float cosinef(float x)
+{
+    return sinef(x + float(M_PI/2));
+}
+
+void sincosf(GLfloat angle, GLfloat* s, GLfloat* c) {
+    *s = sinef(angle);
+    *c = cosinef(angle);
+}
+
+}; // namespace fp_utils
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/opengl/libagl/fp.h b/opengl/libagl/fp.h
new file mode 100644
index 0000000..6d0c183
--- /dev/null
+++ b/opengl/libagl/fp.h
@@ -0,0 +1,243 @@
+/* libs/opengles/fp.h
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_OPENGLES_FP_H
+#define ANDROID_OPENGLES_FP_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <math.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+#define DEBUG_USE_FLOATS      0
+
+// ----------------------------------------------------------------------------
+
+extern "C" GLfixed gglFloatToFixed(float f) __attribute__((const));
+
+// ----------------------------------------------------------------------------
+namespace android {
+
+namespace gl {
+
+        GLfloat fixedToFloat(GLfixed) CONST;
+
+        void    sincosf(GLfloat angle, GLfloat* s, GLfloat* c);
+        float   sinef(GLfloat x) CONST;
+        float   cosinef(GLfloat x) CONST;
+
+inline bool     cmpf(GLfloat a, GLfloat b) CONST;
+inline bool     isZerof(GLfloat) CONST;
+inline bool     isOnef(GLfloat) CONST;
+
+inline int      isZeroOrNegativef(GLfloat) CONST;
+
+inline int      exponent(GLfloat) CONST;
+inline int32_t  mantissa(GLfloat) CONST;
+inline GLfloat  clampToZerof(GLfloat) CONST;
+inline GLfloat  reciprocalf(GLfloat) CONST;
+inline GLfloat  rsqrtf(GLfloat) CONST;
+inline GLfloat  sqrf(GLfloat) CONST;
+inline GLfloat  addExpf(GLfloat v, int e) CONST;
+inline GLfloat  mul2f(GLfloat v) CONST;
+inline GLfloat  div2f(GLfloat v) CONST;
+inline GLfloat  absf(GLfloat v) CONST;
+
+
+/* 
+ * float fastexpf(float) : a fast approximation of expf(x)
+ *		give somewhat accurate results for -88 <= x <= 88
+ *
+ * exp(x) = 2^(x/ln(2))
+ * we use the properties of float encoding
+ * to get a fast 2^ and linear interpolation
+ *
+ */
+
+inline float fastexpf(float y) __attribute__((const));
+
+inline float fastexpf(float y)
+{
+	union {
+		float	r;
+		int32_t	i;
+	} u;	
+
+	// 127*ln(2) = 88
+	if (y < -88.0f) {
+		u.r = 0.0f;
+	} else if (y > 88.0f) {
+		u.r = INFINITY;
+	} else {
+		const float kOneOverLogTwo = (1L<<23) / M_LN2;
+		const int32_t kExponentBias = 127L<<23;
+		const int32_t e = int32_t(y*kOneOverLogTwo);
+		u.i = e + kExponentBias;
+	}
+	
+	return u.r;
+}
+
+
+bool cmpf(GLfloat a, GLfloat b) {
+#if DEBUG_USE_FLOATS
+    return a == b;
+#else
+    union {
+        float       f;
+        uint32_t    i;
+    } ua, ub;
+    ua.f = a;
+    ub.f = b;
+    return ua.i == ub.i;
+#endif
+} 
+
+bool isZerof(GLfloat v) {
+#if DEBUG_USE_FLOATS
+    return v == 0;
+#else
+    union {
+        float       f;
+        int32_t     i;
+    };
+    f = v;
+    return (i<<1) == 0;
+#endif
+}
+
+bool isOnef(GLfloat v) {
+    return cmpf(v, 1.0f);
+}
+
+int isZeroOrNegativef(GLfloat v) {
+#if DEBUG_USE_FLOATS
+    return v <= 0;
+#else
+    union {
+        float       f;
+        int32_t     i;
+    };
+    f = v;
+    return isZerof(v) | (i>>31);
+#endif
+}
+
+int exponent(GLfloat v) {
+    union {
+        float    f;
+        uint32_t i;
+    };
+    f = v;
+    return ((i << 1) >> 24) - 127;
+}
+
+int32_t mantissa(GLfloat v) {
+    union {
+        float    f;
+        uint32_t i;
+    };
+    f = v;
+    if (!(i&0x7F800000)) return 0;
+    const int s = i >> 31;
+    i |= (1L<<23);
+    i &= ~0xFF000000;
+    return s ? -i : i;
+}
+
+GLfloat clampToZerof(GLfloat v) {
+#if DEBUG_USE_FLOATS
+    return v<0 ? 0 : (v>1 ? 1 : v);
+#else
+    union {
+        float       f;
+        int32_t     i;
+    };
+    f = v;
+    i &= ~(i>>31);
+    return f;
+#endif
+}
+
+GLfloat reciprocalf(GLfloat v) {
+    // XXX: do better
+    return 1.0f / v;
+}
+
+GLfloat rsqrtf(GLfloat v) {
+    // XXX: do better
+    return 1.0f / sqrtf(v);
+}
+
+GLfloat sqrf(GLfloat v) {
+    // XXX: do better
+    return v*v;
+}
+
+GLfloat addExpf(GLfloat v, int e) {
+    union {
+        float       f;
+        int32_t     i;
+    };
+    f = v;
+    if (i<<1) { // XXX: deal with over/underflow	
+        i += int32_t(e)<<23;
+    }
+    return f;
+}
+
+GLfloat mul2f(GLfloat v) {
+#if DEBUG_USE_FLOATS
+    return v*2;
+#else
+    return addExpf(v, 1);
+#endif
+}
+
+GLfloat div2f(GLfloat v) {
+#if DEBUG_USE_FLOATS
+    return v*0.5f;
+#else
+    return addExpf(v, -1);
+#endif
+}
+
+GLfloat  absf(GLfloat v) {
+#if DEBUG_USE_FLOATS
+    return v<0 ? -v : v;
+#else
+    union {
+        float       f;
+        int32_t     i;
+    };
+    f = v;
+    i &= ~0x80000000;
+    return f;
+#endif
+}
+
+};  // namespace gl
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_FP_H
+
diff --git a/opengl/libagl/iterators.S b/opengl/libagl/iterators.S
new file mode 100644
index 0000000..daf2937
--- /dev/null
+++ b/opengl/libagl/iterators.S
@@ -0,0 +1,88 @@
+/* libs/opengles/iterators.S
+**
+** Copyright 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.
+*/
+
+
+    .text
+    .align
+    .arm
+    
+    .global iterators0032
+
+/*
+ * iterators0032
+ *
+ * MUST BE CALLED FROM ARM CODE
+ *
+ * r0: const compute_iterators_t* (this)
+ *      r0 + 0: m_dx01 
+ *      r0 + 4: m_dy10
+ *      r0 + 8: m_dx20
+ *      r0 +12: m_dy02
+ *      r0 +16: m_x0
+ *      r0 +20: m_y0
+ *      r0 +24: m_area
+ *		r0 +28: m_scale
+ *		r0 +29: m_area_scale;
+ * r1: int32_t* (out)
+ *      r1 + 0: c
+ *      r1 + 4: dcdx
+ *      r1 + 8: dcdy
+ *   r2: c0
+ *   r3: c1
+ * [sp]: c2
+ */
+ 
+iterators0032:
+        stmfd	sp!, {r4, r5, r6, r7, r8, lr}
+        ldr     r4, [sp, #4*6]
+
+        ldrb    r12, [r0, #29]
+        sub     r3, r3, r2
+        sub     r4, r4, r2
+        sub     r12, r12, #16
+        mov     r3, r3, asr r12
+        mov     r4, r4, asr r12
+        
+        ldr     r5, [r0, #0]
+        ldr     r12, [r0, #4]
+        smull   r8, lr, r4, r5
+        ldr     r5, [r0, #8]
+        smull   r6, r7, r4, r12
+        ldr     r12, [r0, #12]
+        smlal   r8, lr, r3, r5
+        smlal   r6, r7, r3, r12
+
+        ldr     r3, [r0, #16]        // m_x0
+        ldr     r4, [r0, #20]        // m_x1
+        
+        str     r6, [r1, #4]
+        str     r8, [r1, #8]
+
+        umull   r6, r5, r3, r6
+        umull   r8, r0, r4, r8
+        mla     r7, r3, r7, r5
+        mla     lr, r4, lr, r0
+        adds    r6, r6, r8
+        adc     r7, r7, lr
+
+        movs    r6, r6, lsr #4
+        adc     r6, r6, r7, lsl #28
+        rsb     r6, r6, r2, lsl #16
+        str     r6, [r1, #0]
+
+        ldmfd	sp!, {r4, r5, r6, r7, r8, pc}
+
diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp
new file mode 100644
index 0000000..25c41d0
--- /dev/null
+++ b/opengl/libagl/light.cpp
@@ -0,0 +1,852 @@
+/* libs/opengles/light.cpp
+**
+** Copyright 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 "context.h"
+#include "fp.h"
+#include "light.h"
+#include "state.h"
+#include "matrix.h"
+
+
+#if defined(__arm__) && defined(__thumb__)
+#warning "light.cpp should not be compiled in thumb on ARM."
+#endif
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static void invalidate_lighting(ogles_context_t* c);
+static void lightVertexValidate(ogles_context_t* c, vertex_t* v);
+static void lightVertexNop(ogles_context_t* c, vertex_t* v);
+static void lightVertex(ogles_context_t* c, vertex_t* v);
+static void lightVertexMaterial(ogles_context_t* c, vertex_t* v);
+
+static inline void vscale3(GLfixed* d, const GLfixed* m, GLfixed s);
+static inline void vsub3w(GLfixed* d, const GLfixed* a, const GLfixed* b);
+
+static __attribute__((noinline))
+void vnorm3(GLfixed* d, const GLfixed* a);
+
+static inline void vsa3(GLfixed* d,
+    const GLfixed* m, GLfixed s, const GLfixed* a);
+static inline void vmla3(GLfixed* d,
+    const GLfixed* m0, const GLfixed* m1, const GLfixed* a);
+static inline void vmul3(GLfixed* d,
+    const GLfixed* m0, const GLfixed* m1);
+
+static GLfixed fog_linear(ogles_context_t* c, GLfixed z);
+static GLfixed fog_exp(ogles_context_t* c, GLfixed z);
+static GLfixed fog_exp2(ogles_context_t* c, GLfixed z);
+
+
+// ----------------------------------------------------------------------------
+
+static void init_white(vec4_t& c) {
+    c.r = c.g = c.b = c.a = 0x10000;
+}
+
+void ogles_init_light(ogles_context_t* c)
+{
+    for (unsigned int i=0 ; i<OGLES_MAX_LIGHTS ; i++) {
+        c->lighting.lights[i].ambient.a = 0x10000;
+        c->lighting.lights[i].position.z = 0x10000;
+        c->lighting.lights[i].spotDir.z = -0x10000;
+        c->lighting.lights[i].spotCutoff = gglIntToFixed(180);
+        c->lighting.lights[i].attenuation[0] = 0x10000;
+    }
+    init_white(c->lighting.lights[0].diffuse);
+    init_white(c->lighting.lights[0].specular);
+
+    c->lighting.front.ambient.r =
+    c->lighting.front.ambient.g =
+    c->lighting.front.ambient.b = gglFloatToFixed(0.2f);
+    c->lighting.front.ambient.a = 0x10000;
+    c->lighting.front.diffuse.r =
+    c->lighting.front.diffuse.g =
+    c->lighting.front.diffuse.b = gglFloatToFixed(0.8f);
+    c->lighting.front.diffuse.a = 0x10000;
+    c->lighting.front.specular.a = 0x10000;
+    c->lighting.front.emission.a = 0x10000;
+
+    c->lighting.lightModel.ambient.r =
+    c->lighting.lightModel.ambient.g =
+    c->lighting.lightModel.ambient.b = gglFloatToFixed(0.2f);
+    c->lighting.lightModel.ambient.a = 0x10000;
+
+    c->lighting.colorMaterial.face = GL_FRONT_AND_BACK;
+    c->lighting.colorMaterial.mode = GL_AMBIENT_AND_DIFFUSE;
+
+    c->fog.mode = GL_EXP;
+    c->fog.fog = fog_exp;
+    c->fog.density = 0x10000;
+    c->fog.end = 0x10000;
+    c->fog.invEndMinusStart = 0x10000;
+
+    invalidate_lighting(c);
+       
+    c->rasterizer.procs.shadeModel(c, GL_SMOOTH);
+    c->lighting.shadeModel = GL_SMOOTH;
+}
+
+void ogles_uninit_light(ogles_context_t* c)
+{
+}
+
+static inline int32_t clampF(GLfixed f) CONST;
+int32_t clampF(GLfixed f) {
+    f = (f & ~(f>>31));
+    if (f >= 0x10000)
+        f = 0x10000;
+    return f;
+}
+
+static GLfixed fog_linear(ogles_context_t* c, GLfixed z) {
+    return clampF(gglMulx((c->fog.end - ((z<0)?-z:z)), c->fog.invEndMinusStart));
+}
+
+static GLfixed fog_exp(ogles_context_t* c, GLfixed z) {
+    const float e = fixedToFloat(gglMulx(c->fog.density, ((z<0)?-z:z)));
+    return clampF(gglFloatToFixed(fastexpf(-e)));
+}
+
+static GLfixed fog_exp2(ogles_context_t* c, GLfixed z) {
+    const float e = fixedToFloat(gglMulx(c->fog.density, z));
+    return clampF(gglFloatToFixed(fastexpf(-e*e)));
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark math helpers
+#endif
+
+static inline
+void vscale3(GLfixed* d, const GLfixed* m, GLfixed s) {
+    d[0] = gglMulx(m[0], s);
+    d[1] = gglMulx(m[1], s);
+    d[2] = gglMulx(m[2], s);
+}
+
+static inline
+void vsa3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a) {
+    d[0] = gglMulAddx(m[0], s, a[0]);
+    d[1] = gglMulAddx(m[1], s, a[1]);
+    d[2] = gglMulAddx(m[2], s, a[2]);
+}
+
+static inline
+void vsub3w(GLfixed* d, const GLfixed* a, const GLfixed* b) {
+    const GLfixed wa = a[3];
+    const GLfixed wb = b[3];
+    if (ggl_likely(wa == wb)) {
+        d[0] = a[0] - b[0];
+        d[1] = a[1] - b[1];
+        d[2] = a[2] - b[2];
+    } else {
+        d[0] = gglMulSubx(a[0], wb, gglMulx(b[0], wa));
+        d[1] = gglMulSubx(a[1], wb, gglMulx(b[1], wa));
+        d[2] = gglMulSubx(a[2], wb, gglMulx(b[2], wa));
+    }
+}
+
+static inline
+void vmla3(GLfixed* d,
+        const GLfixed* m0, const GLfixed* m1, const GLfixed* a)
+{
+    d[0] = gglMulAddx(m0[0], m1[0], a[0]);
+    d[1] = gglMulAddx(m0[1], m1[1], a[1]);
+    d[2] = gglMulAddx(m0[2], m1[2], a[2]);
+}
+
+static inline
+void vmul3(GLfixed* d, const GLfixed* m0, const GLfixed* m1) {
+    d[0] = gglMulx(m0[0], m1[0]);
+    d[1] = gglMulx(m0[1], m1[1]);
+    d[2] = gglMulx(m0[2], m1[2]);
+}
+
+void vnorm3(GLfixed* d, const GLfixed* a)
+{
+    // we must take care of overflows when normalizing a vector
+    GLfixed n;
+    int32_t x = a[0];   x = x>=0 ? x : -x;
+    int32_t y = a[1];   y = y>=0 ? y : -y;
+    int32_t z = a[2];   z = z>=0 ? z : -z;
+    if (ggl_likely(x<=0x6800 && y<=0x6800 && z<= 0x6800)) {
+        // in this case this will all fit on 32 bits
+        n = x*x + y*y + z*z;
+        n = gglSqrtRecipx(n);
+        n <<= 8;
+    } else {
+        // here norm^2 is at least 0x7EC00000 (>>32 == 0.495117)
+        n = vsquare3(x, y, z);
+        n = gglSqrtRecipx(n);
+    }
+    vscale3(d, a, n);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark lighting equations
+#endif
+
+static inline void light_picker(ogles_context_t* c)
+{
+    if (ggl_likely(!c->lighting.enable)) {
+        c->lighting.lightVertex = lightVertexNop;
+        return;
+    }
+    if (c->lighting.colorMaterial.enable) {
+        c->lighting.lightVertex = lightVertexMaterial;
+    } else {
+        c->lighting.lightVertex = lightVertex;
+    }
+}
+
+static inline void validate_light_mvi(ogles_context_t* c)
+{
+    uint32_t en = c->lighting.enabledLights;
+    while (en) {
+        const int i = 31 - gglClz(en);
+        en &= ~(1<<i);
+        light_t& l = c->lighting.lights[i];
+        c->transforms.mvui.point3(&c->transforms.mvui,
+                &l.objPosition, &l.position);
+        vnorm3(l.normalizedObjPosition.v, l.objPosition.v);
+    }
+}
+
+static inline void validate_light(ogles_context_t* c)
+{
+    // if colorMaterial is enabled, we get the color from the vertex
+    if (!c->lighting.colorMaterial.enable) {
+        material_t& material = c->lighting.front;
+        uint32_t en = c->lighting.enabledLights;
+        while (en) {
+            const int i = 31 - gglClz(en);
+            en &= ~(1<<i);
+            light_t& l = c->lighting.lights[i];
+            vmul3(l.implicitAmbient.v,  material.ambient.v,  l.ambient.v);
+            vmul3(l.implicitDiffuse.v,  material.diffuse.v,  l.diffuse.v);
+            vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v);
+            
+            // this is just a flag to tell if we have a specular component
+            l.implicitSpecular.v[3] =
+                    l.implicitSpecular.r |
+                    l.implicitSpecular.g |
+                    l.implicitSpecular.b;
+            
+            l.rConstAttenuation = (l.attenuation[1] | l.attenuation[2])==0;
+            if (l.rConstAttenuation)
+                l.rConstAttenuation = gglRecipFast(l.attenuation[0]);
+        }
+        // emission and ambient for the whole scene
+        vmla3(  c->lighting.implicitSceneEmissionAndAmbient.v,
+                c->lighting.lightModel.ambient.v,
+                material.ambient.v, 
+                material.emission.v);
+        c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a;
+    }
+    validate_light_mvi(c);
+}
+
+void invalidate_lighting(ogles_context_t* c)
+{
+    // TODO: pick lightVertexValidate or lightVertexValidateMVI
+    // instead of systematically the heavier lightVertexValidate()
+    c->lighting.lightVertex = lightVertexValidate;
+}
+
+void ogles_invalidate_lighting_mvui(ogles_context_t* c)
+{
+    invalidate_lighting(c);
+}
+
+void lightVertexNop(ogles_context_t*, vertex_t* v)
+{
+    // we should never end-up here
+}
+
+void lightVertexValidateMVI(ogles_context_t* c, vertex_t* v)
+{
+    validate_light_mvi(c);
+    light_picker(c);
+    c->lighting.lightVertex(c, v);
+}
+
+void lightVertexValidate(ogles_context_t* c, vertex_t* v)
+{
+    validate_light(c);
+    light_picker(c);
+    c->lighting.lightVertex(c, v);
+}
+
+void lightVertexMaterial(ogles_context_t* c, vertex_t* v)
+{
+    // fetch the material color
+    const GLvoid* cp = c->arrays.color.element(
+            v->index & vertex_cache_t::INDEX_MASK);
+    c->arrays.color.fetch(c, v->color.v, cp);
+
+    // acquire the color-material from the vertex
+    material_t& material = c->lighting.front;
+    material.ambient =
+    material.diffuse = v->color;
+    // implicit arguments need to be computed per/vertex
+    uint32_t en = c->lighting.enabledLights;
+    while (en) {
+        const int i = 31 - gglClz(en);
+        en &= ~(1<<i);
+        light_t& l = c->lighting.lights[i];
+        vmul3(l.implicitAmbient.v,  material.ambient.v,  l.ambient.v);
+        vmul3(l.implicitDiffuse.v,  material.diffuse.v,  l.diffuse.v);
+        vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v);
+    }
+    // emission and ambient for the whole scene
+    vmla3(  c->lighting.implicitSceneEmissionAndAmbient.v,
+            c->lighting.lightModel.ambient.v,
+            material.ambient.v, 
+            material.emission.v);
+    c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a;
+
+    // now we can light our vertex as usual
+    lightVertex(c, v);
+}
+
+void lightVertex(ogles_context_t* c, vertex_t* v)
+{
+    // emission and ambient for the whole scene
+    vec4_t r = c->lighting.implicitSceneEmissionAndAmbient;
+
+    uint32_t en = c->lighting.enabledLights;
+    if (ggl_likely(en)) {
+        // since we do the lighting in object-space, we don't need to
+        // transform each normal. However, we might still have to normalize
+        // it if GL_NORMALIZE is enabled.
+        vec4_t n;
+        c->arrays.normal.fetch(c, n.v,
+            c->arrays.normal.element(v->index & vertex_cache_t::INDEX_MASK));
+        if (c->transforms.rescaleNormals == GL_NORMALIZE)
+            vnorm3(n.v, n.v);
+
+        const material_t& material = c->lighting.front;
+        const int twoSide = c->lighting.lightModel.twoSide;
+
+        while (en) {
+            const int i = 31 - gglClz(en);
+            en &= ~(1<<i);
+            const light_t& l = c->lighting.lights[i];
+            
+            vec4_t d, t;
+            GLfixed s;
+            GLfixed sqDist = 0x10000;
+
+            // compute vertex-to-light vector
+            if (ggl_unlikely(l.position.w)) {
+                vsub3w(d.v, l.objPosition.v, v->obj.v);
+                sqDist = dot3(d.v, d.v);
+                vscale3(d.v, d.v, gglSqrtRecipx(sqDist));
+            } else {
+                // TODO: avoid copy here
+                d = l.normalizedObjPosition;
+            }
+
+            // ambient & diffuse
+            s = dot3(n.v, d.v);
+            s = (s<0) ? (twoSide?(-s):0) : s;
+            vsa3(t.v, l.implicitDiffuse.v, s, l.implicitAmbient.v);
+            
+            // specular
+            if (ggl_unlikely(s && l.implicitSpecular.v[3])) {
+                vec4_t h;
+                h.x = d.x;
+                h.y = d.y;
+                h.z = d.z + 0x10000;
+                vnorm3(h.v, h.v);
+                s = dot3(n.v, h.v);
+                s = (s<0) ? (twoSide?(-s):0) : s;
+                if (s > 0) {
+                    s = gglPowx(s, material.shininess);
+                    vsa3(t.v, l.implicitSpecular.v, s, t.v);
+                }
+            }
+
+            // spot
+            if (ggl_unlikely(l.spotCutoff != gglIntToFixed(180))) {
+                GLfixed spotAtt = -dot3(l.normalizedSpotDir.v, d.v);
+                if (spotAtt >= l.spotCutoffCosine) {
+                    vscale3(t.v, t.v, gglPowx(spotAtt, l.spotExp));
+                }
+            }
+
+            // attenuation
+            if (ggl_unlikely(l.position.w)) {
+                if (l.rConstAttenuation) {
+                    s = l.rConstAttenuation;
+                } else {
+                    s = gglMulAddx(sqDist, l.attenuation[2], l.attenuation[0]);
+                    if (l.attenuation[1])
+                        s = gglMulAddx(gglSqrtx(sqDist), l.attenuation[1], s);
+                    s = gglRecipFast(s);
+                }
+                vscale3(t.v, t.v, s);
+            }
+
+            r.r += t.r;
+            r.g += t.g;
+            r.b += t.b;
+        }
+    }
+    v->color.r = gglClampx(r.r);
+    v->color.g = gglClampx(r.g);
+    v->color.b = gglClampx(r.b);
+    v->color.a = gglClampx(r.a);
+    v->flags |= vertex_t::LIT;
+}
+
+static void lightModelx(GLenum pname, GLfixed param, ogles_context_t* c)
+{
+    if (ggl_unlikely(pname != GL_LIGHT_MODEL_TWO_SIDE)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->lighting.lightModel.twoSide = param ? GL_TRUE : GL_FALSE;
+    invalidate_lighting(c);
+}
+
+static void lightx(GLenum i, GLenum pname, GLfixed param, ogles_context_t* c)
+{
+    if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+
+    light_t& light = c->lighting.lights[i-GL_LIGHT0];
+    const GLfixed kDegToRad = GLfixed((M_PI * gglIntToFixed(1)) / 180.0f);
+    switch (pname) {
+    case GL_SPOT_EXPONENT:
+        if (GGLfixed(param) >= gglIntToFixed(128)) {
+            ogles_error(c, GL_INVALID_VALUE);
+            return;
+        }
+        light.spotExp = param;
+        break;
+    case GL_SPOT_CUTOFF:
+        if (param!=gglIntToFixed(180) && GGLfixed(param)>=gglIntToFixed(90)) {
+            ogles_error(c, GL_INVALID_VALUE);
+            return;
+        }
+        light.spotCutoff = param;
+        light.spotCutoffCosine = 
+                gglFloatToFixed(cosinef((M_PI/(180.0f*65536.0f))*param));
+        break;
+    case GL_CONSTANT_ATTENUATION:
+        if (param < 0) {
+            ogles_error(c, GL_INVALID_VALUE);
+            return;
+        }
+        light.attenuation[0] = param;
+        break;
+    case GL_LINEAR_ATTENUATION:
+        if (param < 0) {
+            ogles_error(c, GL_INVALID_VALUE);
+            return;
+        }
+        light.attenuation[1] = param;
+        break;
+    case GL_QUADRATIC_ATTENUATION:
+        if (param < 0) {
+            ogles_error(c, GL_INVALID_VALUE);
+            return;
+        }
+        light.attenuation[2] = param;
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    invalidate_lighting(c);
+}
+
+static void lightxv(GLenum i, GLenum pname, const GLfixed *params, ogles_context_t* c)
+{
+    if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+
+    GLfixed* what;
+    light_t& light = c->lighting.lights[i-GL_LIGHT0];
+    switch (pname) {
+    case GL_AMBIENT:
+        what = light.ambient.v;
+        break;
+    case GL_DIFFUSE:
+        what = light.diffuse.v;
+        break;
+    case GL_SPECULAR:
+        what = light.specular.v;
+        break;
+    case GL_POSITION: {
+        ogles_validate_transform(c, transform_state_t::MODELVIEW);
+        transform_t& mv = c->transforms.modelview.transform;
+        memcpy(light.position.v, params, sizeof(light.position.v));
+        mv.point4(&mv, &light.position, &light.position);
+        invalidate_lighting(c);
+        return;
+    }
+    case GL_SPOT_DIRECTION: {
+        ogles_validate_transform(c, transform_state_t::MVUI);
+        transform_t& mvui = c->transforms.mvui;
+        mvui.point3(&mvui, &light.spotDir, (vec4_t*)params);
+        vnorm3(light.normalizedSpotDir.v, light.spotDir.v);
+        invalidate_lighting(c);
+        return;
+    }
+    default:
+        lightx(i, pname, params[0], c);
+        return;
+    }
+    what[0] = params[0];
+    what[1] = params[1];
+    what[2] = params[2];
+    what[3] = params[3];
+    invalidate_lighting(c);
+}
+
+static void materialx(GLenum face, GLenum pname, GLfixed param, ogles_context_t* c)
+{
+    if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if (ggl_unlikely(pname != GL_SHININESS)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->lighting.front.shininess = param;
+    invalidate_lighting(c);
+}
+
+static void fogx(GLenum pname, GLfixed param, ogles_context_t* c)
+{
+    switch (pname) {
+    case GL_FOG_DENSITY:
+        if (param >= 0) {
+            c->fog.density = param;
+            break;
+        }
+        ogles_error(c, GL_INVALID_VALUE);
+        break;
+    case GL_FOG_START:
+        c->fog.start = param;
+        c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start);
+        break;
+    case GL_FOG_END:
+        c->fog.end = param;
+        c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start);
+        break;
+    case GL_FOG_MODE:
+        switch (param) {
+        case GL_LINEAR:
+            c->fog.mode = param;
+            c->fog.fog = fog_linear;
+            break;
+        case GL_EXP:
+            c->fog.mode = param;
+            c->fog.fog = fog_exp;
+            break;
+        case GL_EXP2:
+            c->fog.mode = param;
+            c->fog.fog = fog_exp2;
+            break;
+        default:
+            ogles_error(c, GL_INVALID_ENUM);
+            break;
+        }
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        break;
+    }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+#if 0
+#pragma mark -
+#pragma mark lighting APIs
+#endif
+
+void glShadeModel(GLenum mode)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (ggl_unlikely(mode != GL_SMOOTH && mode != GL_FLAT)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->lighting.shadeModel = mode;
+}
+
+void glLightModelf(GLenum pname, GLfloat param)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    lightModelx(pname, gglFloatToFixed(param), c);
+}
+
+void glLightModelx(GLenum pname, GLfixed param)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    lightModelx(pname, param, c);
+}
+
+void glLightModelfv(GLenum pname, const GLfloat *params)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (pname == GL_LIGHT_MODEL_TWO_SIDE) {
+        lightModelx(pname, gglFloatToFixed(params[0]), c);
+        return;
+    }
+
+    if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+
+    c->lighting.lightModel.ambient.r = gglFloatToFixed(params[0]);
+    c->lighting.lightModel.ambient.g = gglFloatToFixed(params[1]);
+    c->lighting.lightModel.ambient.b = gglFloatToFixed(params[2]);
+    c->lighting.lightModel.ambient.a = gglFloatToFixed(params[3]);
+    invalidate_lighting(c);
+}
+
+void glLightModelxv(GLenum pname, const GLfixed *params)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (pname == GL_LIGHT_MODEL_TWO_SIDE) {
+        lightModelx(pname, params[0], c);
+        return;
+    }
+
+    if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+
+    c->lighting.lightModel.ambient.r = params[0];
+    c->lighting.lightModel.ambient.g = params[1];
+    c->lighting.lightModel.ambient.b = params[2];
+    c->lighting.lightModel.ambient.a = params[3];
+    invalidate_lighting(c);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void glLightf(GLenum i, GLenum pname, GLfloat param)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    lightx(i, pname, gglFloatToFixed(param), c);
+}
+
+void glLightx(GLenum i, GLenum pname, GLfixed param)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    lightx(i, pname, param, c);
+}
+
+void glLightfv(GLenum i, GLenum pname, const GLfloat *params)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    switch (pname) {
+    case GL_SPOT_EXPONENT:
+    case GL_SPOT_CUTOFF:
+    case GL_CONSTANT_ATTENUATION:
+    case GL_LINEAR_ATTENUATION:
+    case GL_QUADRATIC_ATTENUATION:
+        lightx(i, pname, gglFloatToFixed(params[0]), c);
+        return;
+    }
+
+    GLfixed paramsx[4];
+    paramsx[0] = gglFloatToFixed(params[0]);
+    paramsx[1] = gglFloatToFixed(params[1]);
+    paramsx[2] = gglFloatToFixed(params[2]);
+    if (pname != GL_SPOT_DIRECTION)
+        paramsx[3] = gglFloatToFixed(params[3]);
+
+    lightxv(i, pname, paramsx, c);
+}
+
+void glLightxv(GLenum i, GLenum pname, const GLfixed *params)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    lightxv(i, pname, params, c);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void glMaterialf(GLenum face, GLenum pname, GLfloat param)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    materialx(face, pname, gglFloatToFixed(param), c);
+}
+
+void glMaterialx(GLenum face, GLenum pname, GLfixed param)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    materialx(face, pname, param, c);
+}
+
+void glMaterialfv(
+    GLenum face, GLenum pname, const GLfloat *params)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    GLfixed* what=0;
+    GLfixed* other=0;
+    switch (pname) {
+    case GL_AMBIENT:    what = c->lighting.front.ambient.v; break;
+    case GL_DIFFUSE:    what = c->lighting.front.diffuse.v; break;
+    case GL_SPECULAR:   what = c->lighting.front.specular.v; break;
+    case GL_EMISSION:   what = c->lighting.front.emission.v; break;
+    case GL_AMBIENT_AND_DIFFUSE:
+        what  = c->lighting.front.ambient.v; break;
+        other = c->lighting.front.diffuse.v; break;
+        break;
+    case GL_SHININESS:
+        c->lighting.front.shininess = gglFloatToFixed(params[0]);
+        invalidate_lighting(c);
+        return;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    what[0] = gglFloatToFixed(params[0]);
+    what[1] = gglFloatToFixed(params[1]);
+    what[2] = gglFloatToFixed(params[2]);
+    what[3] = gglFloatToFixed(params[3]);
+    if (other) {
+        other[0] = what[0];
+        other[1] = what[1];
+        other[2] = what[2];
+        other[3] = what[3];
+    }
+    invalidate_lighting(c);
+}
+
+void glMaterialxv(
+    GLenum face, GLenum pname, const GLfixed *params)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    GLfixed* what=0;
+    GLfixed* other=0;
+    switch (pname) {
+    case GL_AMBIENT:    what = c->lighting.front.ambient.v; break;
+    case GL_DIFFUSE:    what = c->lighting.front.diffuse.v; break;
+    case GL_SPECULAR:   what = c->lighting.front.specular.v; break;
+    case GL_EMISSION:   what = c->lighting.front.emission.v; break;
+    case GL_AMBIENT_AND_DIFFUSE:
+        what = c->lighting.front.ambient.v; break;
+        other= c->lighting.front.diffuse.v; break;
+        break;
+    case GL_SHININESS:
+        c->lighting.front.shininess = gglFloatToFixed(params[0]);
+        invalidate_lighting(c);
+        return;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    what[0] = params[0];
+    what[1] = params[1];
+    what[2] = params[2];
+    what[3] = params[3];
+    if (other) {
+        other[0] = what[0];
+        other[1] = what[1];
+        other[2] = what[2];
+        other[3] = what[3];
+    }
+    invalidate_lighting(c);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark fog
+#endif
+
+void glFogf(GLenum pname, GLfloat param) {
+    ogles_context_t* c = ogles_context_t::get();
+    GLfixed paramx = (GLfixed)param;
+    if (pname != GL_FOG_MODE)
+        paramx = gglFloatToFixed(param);
+    fogx(pname, paramx, c);
+}
+
+void glFogx(GLenum pname, GLfixed param) {
+    ogles_context_t* c = ogles_context_t::get();
+    fogx(pname, param, c);
+}
+
+void glFogfv(GLenum pname, const GLfloat *params)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (pname != GL_FOG_COLOR) {
+        GLfixed paramx = (GLfixed)params[0];
+        if (pname != GL_FOG_MODE)
+            paramx = gglFloatToFixed(params[0]);
+        fogx(pname, paramx, c);
+        return;
+    }
+    GLfixed paramsx[4];
+    paramsx[0] = gglFloatToFixed(params[0]);
+    paramsx[1] = gglFloatToFixed(params[1]);
+    paramsx[2] = gglFloatToFixed(params[2]);
+    paramsx[3] = gglFloatToFixed(params[3]);
+    c->rasterizer.procs.fogColor3xv(c, paramsx);
+}
+
+void glFogxv(GLenum pname, const GLfixed *params)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (pname != GL_FOG_COLOR) {
+        fogx(pname, params[0], c);
+        return;
+    }
+    c->rasterizer.procs.fogColor3xv(c, params);
+}
diff --git a/opengl/libagl/light.h b/opengl/libagl/light.h
new file mode 100644
index 0000000..6dae25f
--- /dev/null
+++ b/opengl/libagl/light.h
@@ -0,0 +1,38 @@
+/* libs/opengles/light.h
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_OPENGLES_LIGHT_H
+#define ANDROID_OPENGLES_LIGHT_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+namespace android {
+
+namespace gl {
+struct ogles_context_t;
+};
+
+void ogles_init_light(ogles_context_t* c);
+void ogles_uninit_light(ogles_context_t* c);
+void ogles_invalidate_lighting_mvui(ogles_context_t* c);
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_LIGHT_H
+
diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp
new file mode 100644
index 0000000..f175cda
--- /dev/null
+++ b/opengl/libagl/matrix.cpp
@@ -0,0 +1,1145 @@
+/* libs/opengles/matrix.cpp
+**
+** Copyright 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 <stdlib.h>
+#include <stdio.h>
+
+#include "context.h"
+#include "fp.h"
+#include "state.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "light.h"
+
+#if defined(__arm__) && defined(__thumb__)
+#warning "matrix.cpp should not be compiled in thumb on ARM."
+#endif
+
+#define I(_i, _j) ((_j)+ 4*(_i))
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static const GLfloat gIdentityf[16] = { 1,0,0,0,
+                                        0,1,0,0,
+                                        0,0,1,0,
+                                        0,0,0,1 };
+
+static const matrixx_t gIdentityx = { 
+            {   0x10000,0,0,0,
+                0,0x10000,0,0,
+                0,0,0x10000,0,
+                0,0,0,0x10000
+            }
+        };
+
+static void point2__nop(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point3__nop(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point4__nop(transform_t const*, vec4_t* c, vec4_t const* o);
+static void normal__nop(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point2__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+static void normal__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void ogles_init_matrix(ogles_context_t* c)
+{
+    c->transforms.modelview.init(OGLES_MODELVIEW_STACK_DEPTH);
+    c->transforms.projection.init(OGLES_PROJECTION_STACK_DEPTH);
+    for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++)
+        c->transforms.texture[i].init(OGLES_TEXTURE_STACK_DEPTH);
+
+    c->transforms.current = &c->transforms.modelview;
+    c->transforms.matrixMode = GL_MODELVIEW;
+    c->transforms.dirty =   transform_state_t::VIEWPORT | 
+                            transform_state_t::MVUI |
+                            transform_state_t::MVIT |
+                            transform_state_t::MVP;
+    c->transforms.mvp.loadIdentity();
+    c->transforms.mvp4.loadIdentity();
+    c->transforms.mvit4.loadIdentity();
+    c->transforms.mvui.loadIdentity();
+    c->transforms.vpt.loadIdentity();
+    c->transforms.vpt.zNear = 0.0f;
+    c->transforms.vpt.zFar  = 1.0f;
+}
+
+void ogles_uninit_matrix(ogles_context_t* c)
+{
+    c->transforms.modelview.uninit();
+    c->transforms.projection.uninit();
+    for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++)
+        c->transforms.texture[i].uninit();
+}
+
+static void validate_perspective(ogles_context_t* c, vertex_t* v)
+{
+    const uint32_t enables = c->rasterizer.state.enables;
+    c->arrays.perspective = (c->clipPlanes.enable) ?
+        ogles_vertex_clipAllPerspective3D : ogles_vertex_perspective3D;
+    if (enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) {
+        c->arrays.perspective = ogles_vertex_perspective3DZ;
+        if (c->clipPlanes.enable || (enables&GGL_ENABLE_FOG))
+            c->arrays.perspective = ogles_vertex_clipAllPerspective3DZ;
+    }
+    if ((c->arrays.vertex.size != 4) &&
+        (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION)) {
+        c->arrays.perspective = ogles_vertex_perspective2D;
+    }
+    c->arrays.perspective(c, v);
+}
+
+void ogles_invalidate_perspective(ogles_context_t* c)
+{
+    c->arrays.perspective = validate_perspective;
+}
+
+void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want)
+{
+    int dirty = c->transforms.dirty & want;
+
+    // Validate the modelview
+    if (dirty & transform_state_t::MODELVIEW) {
+        c->transforms.modelview.validate();
+    }
+
+    // Validate the projection stack (in fact, it's never needed)
+    if (dirty & transform_state_t::PROJECTION) {
+        c->transforms.projection.validate();
+    }
+
+    // Validate the viewport transformation
+    if (dirty & transform_state_t::VIEWPORT) {
+        vp_transform_t& vpt = c->transforms.vpt;
+        vpt.transform.matrix.load(vpt.matrix);
+        vpt.transform.picker();
+    }
+
+    // We need to update the mvp (used to transform each vertex)
+    if (dirty & transform_state_t::MVP) {
+        c->transforms.update_mvp();
+        // invalidate perspective (divide by W) and view volume clipping
+        ogles_invalidate_perspective(c);
+    }
+
+    // Validate the mvui (for normal transformation)
+    if (dirty & transform_state_t::MVUI) {
+        c->transforms.update_mvui();
+        ogles_invalidate_lighting_mvui(c);
+    }
+
+    // Validate the texture stack
+    if (dirty & transform_state_t::TEXTURE) {
+        for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++)
+            c->transforms.texture[i].validate();
+    }
+
+    // Validate the mvit4 (user-clip planes)
+    if (dirty & transform_state_t::MVIT) {
+        c->transforms.update_mvit();
+    }
+
+    c->transforms.dirty &= ~want;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark transform_t
+#endif
+
+void transform_t::loadIdentity() {
+    matrix = gIdentityx;
+    flags = 0;
+    ops = OP_IDENTITY;
+    point2 = point2__nop;
+    point3 = point3__nop;
+    point4 = point4__nop;
+}
+
+
+static inline
+int notZero(GLfixed v) {
+    return abs(v) & ~0x3;
+}
+
+static inline
+int notOne(GLfixed v) {
+    return notZero(v - 0x10000);
+}
+
+void transform_t::picker()
+{
+    const GLfixed* const m = matrix.m;
+
+    // XXX: picker needs to be smarter
+    flags = 0;
+    ops = OP_ALL;
+    point2 = point2__generic;
+    point3 = point3__generic;
+    point4 = point4__generic;
+    
+    // find out if this is a 2D projection
+    if (!(notZero(m[3]) | notZero(m[7]) | notZero(m[11]) | notOne(m[15]))) {
+        flags |= FLAGS_2D_PROJECTION;
+    }
+}
+
+void mvui_transform_t::picker()
+{
+    flags = 0;
+    ops = OP_ALL;
+    point3 = normal__generic;
+}
+
+void transform_t::dump(const char* what)
+{
+    GLfixed const * const m = matrix.m;
+    LOGD("%s:", what);
+    for (int i=0 ; i<4 ; i++)
+        LOGD("[%08x %08x %08x %08x] [%f %f %f %f]\n",
+            m[I(0,i)], m[I(1,i)], m[I(2,i)], m[I(3,i)],
+            fixedToFloat(m[I(0,i)]),
+            fixedToFloat(m[I(1,i)]), 
+            fixedToFloat(m[I(2,i)]),
+            fixedToFloat(m[I(3,i)]));
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark matrixx_t
+#endif
+
+void matrixx_t::load(const matrixf_t& rhs) {
+    GLfixed* xp = m;
+    GLfloat const* fp = rhs.elements();
+    unsigned int i = 16;
+    do {
+        const GLfloat f = *fp++;
+        *xp++ = isZerof(f) ? 0 : gglFloatToFixed(f);
+    } while (--i);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark matrixf_t
+#endif
+
+void matrixf_t::multiply(matrixf_t& r, const matrixf_t& lhs, const matrixf_t& rhs)
+{
+    GLfloat const* const m = lhs.m;
+    for (int i=0 ; i<4 ; i++) {
+        register const float rhs_i0 = rhs.m[ I(i,0) ];
+        register float ri0 = m[ I(0,0) ] * rhs_i0;
+        register float ri1 = m[ I(0,1) ] * rhs_i0;
+        register float ri2 = m[ I(0,2) ] * rhs_i0;
+        register float ri3 = m[ I(0,3) ] * rhs_i0;
+        for (int j=1 ; j<4 ; j++) {
+            register const float rhs_ij = rhs.m[ I(i,j) ];
+            ri0 += m[ I(j,0) ] * rhs_ij;
+            ri1 += m[ I(j,1) ] * rhs_ij;
+            ri2 += m[ I(j,2) ] * rhs_ij;
+            ri3 += m[ I(j,3) ] * rhs_ij;
+        }
+        r.m[ I(i,0) ] = ri0;
+        r.m[ I(i,1) ] = ri1;
+        r.m[ I(i,2) ] = ri2;
+        r.m[ I(i,3) ] = ri3;
+    }
+}
+
+void matrixf_t::dump(const char* what) {
+    LOGD("%s", what);
+    LOGD("[ %9f %9f %9f %9f ]", m[I(0,0)], m[I(1,0)], m[I(2,0)], m[I(3,0)]);
+    LOGD("[ %9f %9f %9f %9f ]", m[I(0,1)], m[I(1,1)], m[I(2,1)], m[I(3,1)]);
+    LOGD("[ %9f %9f %9f %9f ]", m[I(0,2)], m[I(1,2)], m[I(2,2)], m[I(3,2)]);
+    LOGD("[ %9f %9f %9f %9f ]", m[I(0,3)], m[I(1,3)], m[I(2,3)], m[I(3,3)]);
+}
+
+void matrixf_t::loadIdentity() {
+    memcpy(m, gIdentityf, sizeof(m));
+}
+
+void matrixf_t::set(const GLfixed* rhs) {
+    load(rhs);
+}
+
+void matrixf_t::set(const GLfloat* rhs) {
+    load(rhs);
+}
+
+void matrixf_t::load(const GLfixed* rhs) {
+    GLfloat* fp = m;
+    unsigned int i = 16;
+    do {
+        *fp++ = fixedToFloat(*rhs++);
+    } while (--i);
+}
+
+void matrixf_t::load(const GLfloat* rhs) {
+    memcpy(m, rhs, sizeof(m));
+}
+
+void matrixf_t::load(const matrixf_t& rhs) {
+    operator = (rhs);
+}
+
+void matrixf_t::multiply(const matrixf_t& rhs) {
+    matrixf_t r;
+    multiply(r, *this, rhs);
+    operator = (r);
+}
+
+void matrixf_t::translate(GLfloat x, GLfloat y, GLfloat z) {
+    for (int i=0 ; i<4 ; i++) {
+        m[12+i] += m[i]*x + m[4+i]*y + m[8+i]*z;
+    }
+}
+
+void matrixf_t::scale(GLfloat x, GLfloat y, GLfloat z) {
+    for (int i=0 ; i<4 ; i++) {
+        m[  i] *= x;
+        m[4+i] *= y;
+        m[8+i] *= z;
+    }
+}
+
+void matrixf_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
+{
+    matrixf_t rotation;
+    GLfloat* r = rotation.m;
+    GLfloat c, s;
+    r[3] = 0;   r[7] = 0;   r[11]= 0;
+    r[12]= 0;   r[13]= 0;   r[14]= 0;   r[15]= 1;
+    a *= GLfloat(M_PI / 180.0f);
+    sincosf(a, &s, &c);
+    if (isOnef(x) && isZerof(y) && isZerof(z)) {
+        r[5] = c;   r[10]= c;
+        r[6] = s;   r[9] = -s;
+        r[1] = 0;   r[2] = 0;
+        r[4] = 0;   r[8] = 0;
+        r[0] = 1;
+    } else if (isZerof(x) && isOnef(y) && isZerof(z)) {
+        r[0] = c;   r[10]= c;
+        r[8] = s;   r[2] = -s;
+        r[1] = 0;   r[4] = 0;
+        r[6] = 0;   r[9] = 0;
+        r[5] = 1;
+    } else if (isZerof(x) && isZerof(y) && isOnef(z)) {
+        r[0] = c;   r[5] = c;
+        r[1] = s;   r[4] = -s;
+        r[2] = 0;   r[6] = 0;
+        r[8] = 0;   r[9] = 0;
+        r[10]= 1;
+    } else {
+        const GLfloat len = sqrtf(x*x + y*y + z*z);
+        if (!isOnef(len)) {
+            const GLfloat recipLen = reciprocalf(len);
+            x *= recipLen;
+            y *= recipLen;
+            z *= recipLen;
+        }
+        const GLfloat nc = 1.0f - c;
+        const GLfloat xy = x * y;
+        const GLfloat yz = y * z;
+        const GLfloat zx = z * x;
+        const GLfloat xs = x * s;
+        const GLfloat ys = y * s;
+        const GLfloat zs = z * s;		
+        r[ 0] = x*x*nc +  c;    r[ 4] =  xy*nc - zs;    r[ 8] =  zx*nc + ys;
+        r[ 1] =  xy*nc + zs;    r[ 5] = y*y*nc +  c;    r[ 9] =  yz*nc - xs;
+        r[ 2] =  zx*nc - ys;    r[ 6] =  yz*nc + xs;    r[10] = z*z*nc +  c;
+    }
+    multiply(rotation);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark matrix_stack_t
+#endif
+
+void matrix_stack_t::init(int depth) {
+    stack = new matrixf_t[depth];
+    ops = new uint8_t[depth];
+    maxDepth = depth;
+    depth = 0;
+    dirty = 0;
+    loadIdentity();
+}
+
+void matrix_stack_t::uninit() {
+    delete [] stack;
+    delete [] ops;
+}
+
+void matrix_stack_t::loadIdentity() {
+    transform.loadIdentity();
+    stack[depth].loadIdentity();
+    ops[depth] = OP_IDENTITY;
+}
+
+void matrix_stack_t::load(const GLfixed* rhs)
+{   
+    memcpy(transform.matrix.m, rhs, sizeof(transform.matrix.m));
+    stack[depth].load(rhs);
+    ops[depth] = OP_ALL;    // TODO: we should look at the matrix
+}
+
+void matrix_stack_t::load(const GLfloat* rhs)
+{
+    stack[depth].load(rhs);
+    ops[depth] = OP_ALL;    // TODO: we should look at the matrix
+}
+
+void matrix_stack_t::multiply(const matrixf_t& rhs)
+{    
+    stack[depth].multiply(rhs);
+    ops[depth] = OP_ALL;    // TODO: we should look at the matrix
+}
+
+void matrix_stack_t::translate(GLfloat x, GLfloat y, GLfloat z)
+{
+    stack[depth].translate(x,y,z);
+    ops[depth] |= OP_TRANSLATE;
+}
+
+void matrix_stack_t::scale(GLfloat x, GLfloat y, GLfloat z)
+{
+    stack[depth].scale(x,y,z);
+    if (x==y && y==z) {
+        ops[depth] |= OP_UNIFORM_SCALE;
+    } else {
+        ops[depth] |= OP_SCALE;
+    }
+}
+
+void matrix_stack_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
+{
+    stack[depth].rotate(a,x,y,z);
+    ops[depth] |= OP_ROTATE;
+}
+
+void matrix_stack_t::validate()
+{
+    if (dirty & DO_FLOAT_TO_FIXED) {
+        transform.matrix.load(top());
+    }
+    if (dirty & DO_PICKER) {
+        transform.picker();
+    }
+    dirty = 0;
+}
+
+GLint matrix_stack_t::push()
+{
+    if (depth >= (maxDepth-1)) {
+        return GL_STACK_OVERFLOW;
+    }
+    stack[depth+1] = stack[depth];
+    ops[depth+1] = ops[depth];
+    depth++;
+    return 0;
+}
+
+GLint matrix_stack_t::pop()
+{
+    if (depth == 0) {
+        return GL_STACK_UNDERFLOW;
+    }
+    depth--;
+    return 0;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark vp_transform_t
+#endif
+
+void vp_transform_t::loadIdentity() {
+    transform.loadIdentity();
+    matrix.loadIdentity();
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark transform_state_t
+#endif
+
+void transform_state_t::invalidate()
+{
+    switch (matrixMode) {
+    case GL_MODELVIEW:  dirty |= MODELVIEW  | MVP | MVUI | MVIT;    break;
+    case GL_PROJECTION: dirty |= PROJECTION | MVP;                  break;
+    case GL_TEXTURE:    dirty |= TEXTURE    | MVP;                  break;
+    }
+    current->dirty =    matrix_stack_t::DO_PICKER |
+                        matrix_stack_t::DO_FLOAT_TO_FIXED;
+}
+
+void transform_state_t::update_mvp()
+{
+    matrixf_t temp_mvp;
+    matrixf_t::multiply(temp_mvp, projection.top(), modelview.top());
+    mvp4.matrix.load(temp_mvp);
+    mvp4.picker();
+
+    if (mvp4.flags & transform_t::FLAGS_2D_PROJECTION) {
+        // the mvp matrix doesn't transform W, in this case we can
+        // premultiply it with the viewport transformation. In addition to
+        // being more efficient, this is also much more accurate and in fact
+        // is needed for 2D drawing with a resulting 1:1 mapping.
+        matrixf_t mvpv;
+        matrixf_t::multiply(mvpv, vpt.matrix, temp_mvp);
+        mvp.matrix.load(mvpv);
+        mvp.picker();
+    } else {
+        mvp = mvp4;
+    }
+}
+
+static inline 
+GLfloat det22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) {
+    return a*d - b*c;
+}
+
+static inline
+GLfloat ndet22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) {
+    return b*c - a*d;
+}
+
+static __attribute__((noinline))
+void invert(GLfloat* inverse, const GLfloat* src)
+{
+    double t;
+    int i, j, k, swap;
+    GLfloat tmp[4][4];
+    
+    memcpy(inverse, gIdentityf, sizeof(gIdentityf));
+    memcpy(tmp, src, sizeof(GLfloat)*16);
+    
+    for (i = 0; i < 4; i++) {
+        // look for largest element in column
+        swap = i;
+        for (j = i + 1; j < 4; j++) {
+            if (fabs(tmp[j][i]) > fabs(tmp[i][i])) {
+                swap = j;
+            }
+        }
+        
+        if (swap != i) {
+            /* swap rows. */
+            for (k = 0; k < 4; k++) {
+                t = tmp[i][k];
+                tmp[i][k] = tmp[swap][k];
+                tmp[swap][k] = t;
+                
+                t = inverse[i*4+k];
+                inverse[i*4+k] = inverse[swap*4+k];
+                inverse[swap*4+k] = t;
+            }
+        }
+        
+        t = 1.0f / tmp[i][i];
+        for (k = 0; k < 4; k++) {
+            tmp[i][k] *= t;
+            inverse[i*4+k] *= t;
+        }
+        for (j = 0; j < 4; j++) {
+            if (j != i) {
+                t = tmp[j][i];
+                for (k = 0; k < 4; k++) {
+                    tmp[j][k] -= tmp[i][k]*t;
+                    inverse[j*4+k] -= inverse[i*4+k]*t;
+                }
+            }
+        }
+    }
+}
+
+void transform_state_t::update_mvit()
+{
+    GLfloat r[16];
+    const GLfloat* const mv = modelview.top().elements();
+    invert(r, mv);
+    // convert to fixed-point and transpose
+    GLfixed* const x = mvit4.matrix.m;
+    for (int i=0 ; i<4 ; i++)
+        for (int j=0 ; j<4 ; j++)
+            x[I(i,j)] = gglFloatToFixed(r[I(j,i)]);
+    mvit4.picker();
+}
+
+void transform_state_t::update_mvui()
+{
+    const GLfloat* const mv = modelview.top().elements();
+
+    /*
+    When transforming normals, we can use the upper 3x3 matrix, see:
+    http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node26.html
+    */
+    
+    // Also note that:
+    //      l(obj) =  tr(M).l(eye) for infinite light
+    //      l(obj) = inv(M).l(eye) for local light
+
+    const uint32_t ops = modelview.top_ops() & ~OP_TRANSLATE;
+    if (ggl_likely((!(ops & ~OP_ROTATE)) ||
+        (rescaleNormals && modelview.isRigidBody()))) {
+        // if the modelview matrix is a rigid body transformation
+        // (translation, rotation, uniform scaling), then we can bypass
+        // the inverse by transposing the matrix.
+        GLfloat rescale = 1.0f;
+        if (rescaleNormals == GL_RESCALE_NORMAL) {
+            if (!(ops & ~OP_UNIFORM_SCALE)) {
+                rescale = reciprocalf(mv[I(0,0)]);
+            } else {
+                rescale = rsqrtf(
+                        sqrf(mv[I(2,0)]) + sqrf(mv[I(2,1)]) + sqrf(mv[I(2,2)]));
+            }
+        }
+        GLfixed* const x = mvui.matrix.m;
+        for (int i=0 ; i<3 ; i++) {
+            x[I(i,0)] = gglFloatToFixed(mv[I(0,i)] * rescale);
+            x[I(i,1)] = gglFloatToFixed(mv[I(1,i)] * rescale);
+            x[I(i,2)] = gglFloatToFixed(mv[I(2,i)] * rescale);
+        }
+        mvui.picker();
+        return;
+    }
+
+    GLfloat r[3][3];
+    r[0][0] = det22(mv[I(1,1)], mv[I(2,1)], mv[I(1,2)], mv[I(2,2)]);
+    r[0][1] =ndet22(mv[I(0,1)], mv[I(2,1)], mv[I(0,2)], mv[I(2,2)]);
+    r[0][2] = det22(mv[I(0,1)], mv[I(1,1)], mv[I(0,2)], mv[I(1,2)]);
+    r[1][0] =ndet22(mv[I(1,0)], mv[I(2,0)], mv[I(1,2)], mv[I(2,2)]);
+    r[1][1] = det22(mv[I(0,0)], mv[I(2,0)], mv[I(0,2)], mv[I(2,2)]);
+    r[1][2] =ndet22(mv[I(0,0)], mv[I(1,0)], mv[I(0,2)], mv[I(1,2)]);
+    r[2][0] = det22(mv[I(1,0)], mv[I(2,0)], mv[I(1,1)], mv[I(2,1)]);
+    r[2][1] =ndet22(mv[I(0,0)], mv[I(2,0)], mv[I(0,1)], mv[I(2,1)]);
+    r[2][2] = det22(mv[I(0,0)], mv[I(1,0)], mv[I(0,1)], mv[I(1,1)]);        
+
+    GLfloat rdet;
+    if (rescaleNormals == GL_RESCALE_NORMAL) {
+        rdet = rsqrtf(sqrf(r[0][2]) + sqrf(r[1][2]) + sqrf(r[2][2]));
+    } else {
+        rdet = reciprocalf( 
+            r[0][0]*mv[I(0,0)] + r[0][1]*mv[I(1,0)] + r[0][2]*mv[I(2,0)]);
+    }
+
+    GLfixed* const x = mvui.matrix.m;
+    for (int i=0 ; i<3 ; i++) {
+        x[I(i,0)] = gglFloatToFixed(r[i][0] * rdet);
+        x[I(i,1)] = gglFloatToFixed(r[i][1] * rdet);
+        x[I(i,2)] = gglFloatToFixed(r[i][2] * rdet);
+    }
+    mvui.picker();
+}
+
+
+// ----------------------------------------------------------------------------
+// transformation and matrices API
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark transformation and matrices API
+#endif
+
+int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y)
+{
+    c->viewport.surfaceport.x = x;
+    c->viewport.surfaceport.y = y;
+
+    ogles_viewport(c, 
+            c->viewport.x,
+            c->viewport.y,
+            c->viewport.w,
+            c->viewport.h);
+
+    ogles_scissor(c,
+            c->viewport.scissor.x,
+            c->viewport.scissor.y,
+            c->viewport.scissor.w,
+            c->viewport.scissor.h);
+
+    return 0;
+}
+
+void ogles_scissor(ogles_context_t* c, 
+        GLint x, GLint y, GLsizei w, GLsizei h)
+{
+    if ((w|h) < 0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    c->viewport.scissor.x = x;
+    c->viewport.scissor.y = y;
+    c->viewport.scissor.w = w;
+    c->viewport.scissor.h = h;
+    
+    x += c->viewport.surfaceport.x;
+    y += c->viewport.surfaceport.y;
+
+    y = c->rasterizer.state.buffers.color.height - (y + h);
+    c->rasterizer.procs.scissor(c, x, y, w, h);
+}
+
+void ogles_viewport(ogles_context_t* c,
+        GLint x, GLint y, GLsizei w, GLsizei h)
+{
+    if ((w|h)<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+
+    c->viewport.x = x;
+    c->viewport.y = y;
+    c->viewport.w = w;
+    c->viewport.h = h;
+
+    x += c->viewport.surfaceport.x;
+    y += c->viewport.surfaceport.y;
+
+    GLint H = c->rasterizer.state.buffers.color.height;
+    GLfloat sx = div2f(w);
+    GLfloat ox = sx + x;
+    GLfloat sy = div2f(h);
+    GLfloat oy = sy - y + (H - h);
+
+    GLfloat near = c->transforms.vpt.zNear;
+    GLfloat far  = c->transforms.vpt.zFar;
+    GLfloat A = div2f(far - near);
+    GLfloat B = div2f(far + near);
+
+    // compute viewport matrix
+    GLfloat* const f = c->transforms.vpt.matrix.editElements();
+    f[0] = sx;  f[4] = 0;   f[ 8] = 0;  f[12] = ox;
+    f[1] = 0;   f[5] =-sy;  f[ 9] = 0;  f[13] = oy;
+    f[2] = 0;   f[6] = 0;   f[10] = A;  f[14] = B;
+    f[3] = 0;   f[7] = 0;   f[11] = 0;  f[15] = 1;
+    c->transforms.dirty |= transform_state_t::VIEWPORT;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark matrix * vertex
+#endif
+
+void point2__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+    const GLfixed* const m = mx->matrix.m;
+    const GLfixed rx = rhs->x;
+    const GLfixed ry = rhs->y;
+    lhs->x = mla2a(rx, m[ 0], ry, m[ 4], m[12]); 
+    lhs->y = mla2a(rx, m[ 1], ry, m[ 5], m[13]);
+    lhs->z = mla2a(rx, m[ 2], ry, m[ 6], m[14]);
+    lhs->w = mla2a(rx, m[ 3], ry, m[ 7], m[15]);
+}
+
+void point3__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+    const GLfixed* const m = mx->matrix.m;
+    const GLfixed rx = rhs->x;
+    const GLfixed ry = rhs->y;
+    const GLfixed rz = rhs->z;
+    lhs->x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]); 
+    lhs->y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
+    lhs->z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
+    lhs->w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
+}
+
+void point4__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+    const GLfixed* const m = mx->matrix.m;
+    const GLfixed rx = rhs->x;
+    const GLfixed ry = rhs->y;
+    const GLfixed rz = rhs->z;
+    const GLfixed rw = rhs->w;
+    lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]); 
+    lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]);
+    lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]);
+    lhs->w = mla4(rx, m[ 3], ry, m[ 7], rz, m[11], rw, m[15]);
+}
+
+void normal__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+    const GLfixed* const m = mx->matrix.m;
+    const GLfixed rx = rhs->x;
+    const GLfixed ry = rhs->y;
+    const GLfixed rz = rhs->z;
+    lhs->x = mla3(rx, m[ 0], ry, m[ 4], rz, m[ 8]); 
+    lhs->y = mla3(rx, m[ 1], ry, m[ 5], rz, m[ 9]);
+    lhs->z = mla3(rx, m[ 2], ry, m[ 6], rz, m[10]);
+}
+
+
+void point2__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
+    lhs->z = 0;
+    lhs->w = 0x10000;
+    if (lhs != rhs) {
+        lhs->x = rhs->x;
+        lhs->y = rhs->y;
+    }
+}
+
+void point3__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
+    lhs->w = 0x10000;
+    if (lhs != rhs) {
+        lhs->x = rhs->x;
+        lhs->y = rhs->y;
+        lhs->z = rhs->z;
+    }
+}
+
+void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
+    if (lhs != rhs)
+        *lhs = *rhs;
+}
+
+
+static void frustumf(
+            GLfloat left, GLfloat right, 
+            GLfloat bottom, GLfloat top,
+            GLfloat zNear, GLfloat zFar,
+            ogles_context_t* c)
+    {
+    if (cmpf(left,right) ||
+        cmpf(top, bottom) ||
+        cmpf(zNear, zFar) ||
+        isZeroOrNegativef(zNear) ||
+        isZeroOrNegativef(zFar))
+    {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    const GLfloat r_width  = reciprocalf(right - left);
+    const GLfloat r_height = reciprocalf(top - bottom);
+    const GLfloat r_depth  = reciprocalf(zNear - zFar);
+    const GLfloat x = mul2f(zNear * r_width);
+    const GLfloat y = mul2f(zNear * r_height);
+    const GLfloat A = mul2f((right + left) * r_width);
+    const GLfloat B = (top + bottom) * r_height;
+    const GLfloat C = (zFar + zNear) * r_depth;
+    const GLfloat D = mul2f(zFar * zNear * r_depth);
+    GLfloat f[16];
+    f[ 0] = x;
+    f[ 5] = y;
+    f[ 8] = A;
+    f[ 9] = B;
+    f[10] = C;
+    f[14] = D;
+    f[11] = -1.0f;
+    f[ 1] = f[ 2] = f[ 3] =
+    f[ 4] = f[ 6] = f[ 7] =
+    f[12] = f[13] = f[15] = 0.0f;
+
+    matrixf_t rhs;
+    rhs.set(f);
+    c->transforms.current->multiply(rhs);
+    c->transforms.invalidate();
+}
+
+static void orthof( 
+        GLfloat left, GLfloat right, 
+        GLfloat bottom, GLfloat top,
+        GLfloat zNear, GLfloat zFar,
+        ogles_context_t* c)
+{
+    if (cmpf(left,right) ||
+        cmpf(top, bottom) ||
+        cmpf(zNear, zFar))
+    {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    const GLfloat r_width  = reciprocalf(right - left);
+    const GLfloat r_height = reciprocalf(top - bottom);
+    const GLfloat r_depth  = reciprocalf(zFar - zNear);
+    const GLfloat x =  mul2f(r_width);
+    const GLfloat y =  mul2f(r_height);
+    const GLfloat z = -mul2f(r_depth);
+    const GLfloat tx = -(right + left) * r_width;
+    const GLfloat ty = -(top + bottom) * r_height;
+    const GLfloat tz = -(zFar + zNear) * r_depth;
+    GLfloat f[16];
+    f[ 0] = x;
+    f[ 5] = y;
+    f[10] = z;
+    f[12] = tx;
+    f[13] = ty;
+    f[14] = tz;
+    f[15] = 1.0f;
+    f[ 1] = f[ 2] = f[ 3] =
+    f[ 4] = f[ 6] = f[ 7] =
+    f[ 8] = f[ 9] = f[11] = 0.0f;
+    matrixf_t rhs;
+    rhs.set(f);
+    c->transforms.current->multiply(rhs);
+    c->transforms.invalidate();
+}
+
+static void depthRangef(GLclampf zNear, GLclampf zFar, ogles_context_t* c)
+{
+    zNear = clampToZerof(zNear > 1 ? 1 : zNear);
+    zFar  = clampToZerof(zFar  > 1 ? 1 : zFar);
+    GLfloat* const f = c->transforms.vpt.matrix.editElements();
+    f[10] = div2f(zFar - zNear);
+    f[14] = div2f(zFar + zNear);
+    c->transforms.dirty |= transform_state_t::VIEWPORT;
+    c->transforms.vpt.zNear = zNear;
+    c->transforms.vpt.zFar  = zFar;
+}
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+using namespace android;
+
+void glMatrixMode(GLenum mode)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    matrix_stack_t* stack = 0;
+    switch (mode) {
+    case GL_MODELVIEW:
+        stack = &c->transforms.modelview;
+        break;
+    case GL_PROJECTION:
+        stack = &c->transforms.projection;
+        break;
+    case GL_TEXTURE:
+        stack = &c->transforms.texture[c->textures.active];
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->transforms.matrixMode = mode;
+    c->transforms.current = stack;
+}
+
+void glLoadIdentity()
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->transforms.current->loadIdentity(); // also loads the GLfixed transform
+    c->transforms.invalidate();
+    c->transforms.current->dirty = 0;
+}
+
+void glLoadMatrixf(const GLfloat* m)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->transforms.current->load(m);
+    c->transforms.invalidate();
+}
+
+void glLoadMatrixx(const GLfixed* m)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->transforms.current->load(m); // also loads the GLfixed transform
+    c->transforms.invalidate();
+    c->transforms.current->dirty &= ~matrix_stack_t::DO_FLOAT_TO_FIXED;
+}
+
+void glMultMatrixf(const GLfloat* m)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    matrixf_t rhs;
+    rhs.set(m);
+    c->transforms.current->multiply(rhs);
+    c->transforms.invalidate();
+}
+
+void glMultMatrixx(const GLfixed* m)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    matrixf_t rhs;
+    rhs.set(m);
+    c->transforms.current->multiply(rhs);
+    c->transforms.invalidate();
+}
+
+void glPopMatrix()
+{
+    ogles_context_t* c = ogles_context_t::get();
+    GLint err = c->transforms.current->pop();
+    if (ggl_unlikely(err)) {
+        ogles_error(c, err);
+        return;
+    }
+    c->transforms.invalidate();
+}
+
+void glPushMatrix()
+{
+    ogles_context_t* c = ogles_context_t::get();
+    GLint err = c->transforms.current->push();
+    if (ggl_unlikely(err)) {
+        ogles_error(c, err);
+        return;
+    }
+    c->transforms.invalidate();
+}
+
+void glFrustumf(
+        GLfloat left, GLfloat right, 
+        GLfloat bottom, GLfloat top,
+        GLfloat zNear, GLfloat zFar)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    frustumf(left, right, bottom, top, zNear, zFar, c);
+}
+
+void glFrustumx( 
+        GLfixed left, GLfixed right,
+        GLfixed bottom, GLfixed top,
+        GLfixed zNear, GLfixed zFar)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    frustumf( fixedToFloat(left), fixedToFloat(right),
+              fixedToFloat(bottom), fixedToFloat(top),
+              fixedToFloat(zNear), fixedToFloat(zFar),
+              c);
+}
+
+void glOrthof( 
+        GLfloat left, GLfloat right, 
+        GLfloat bottom, GLfloat top,
+        GLfloat zNear, GLfloat zFar)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    orthof(left, right, bottom, top, zNear, zFar, c);
+}
+
+void glOrthox(
+        GLfixed left, GLfixed right,
+        GLfixed bottom, GLfixed top,
+        GLfixed zNear, GLfixed zFar)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    orthof( fixedToFloat(left), fixedToFloat(right),
+            fixedToFloat(bottom), fixedToFloat(top),
+            fixedToFloat(zNear), fixedToFloat(zFar),
+            c);
+}
+
+void glRotatef(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->transforms.current->rotate(a, x, y, z);
+    c->transforms.invalidate();
+}
+
+void glRotatex(GLfixed a, GLfixed x, GLfixed y, GLfixed z)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->transforms.current->rotate( 
+            fixedToFloat(a), fixedToFloat(x),
+            fixedToFloat(y), fixedToFloat(z));
+    c->transforms.invalidate();
+}
+
+void glScalef(GLfloat x, GLfloat y, GLfloat z)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->transforms.current->scale(x, y, z);
+    c->transforms.invalidate();
+}
+
+void glScalex(GLfixed x, GLfixed y, GLfixed z)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->transforms.current->scale(
+            fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));
+    c->transforms.invalidate();
+}
+
+void glTranslatef(GLfloat x, GLfloat y, GLfloat z)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->transforms.current->translate(x, y, z);
+    c->transforms.invalidate();
+}
+
+void glTranslatex(GLfixed x, GLfixed y, GLfixed z)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->transforms.current->translate(
+            fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));
+    c->transforms.invalidate();
+}
+
+void glScissor(GLint x, GLint y, GLsizei w, GLsizei h)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    ogles_scissor(c, x, y, w, h);
+}
+
+void glViewport(GLint x, GLint y, GLsizei w, GLsizei h)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    ogles_viewport(c, x, y, w, h);
+}
+
+void glDepthRangef(GLclampf zNear, GLclampf zFar)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    depthRangef(zNear, zFar, c);
+}
+
+void glDepthRangex(GLclampx zNear, GLclampx zFar)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    depthRangef(fixedToFloat(zNear), fixedToFloat(zFar), c);
+}
+
+void glPolygonOffsetx(GLfixed factor, GLfixed units)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->polygonOffset.factor = factor;
+    c->polygonOffset.units = units;
+}
+
+void glPolygonOffset(GLfloat factor, GLfloat units)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->polygonOffset.factor = gglFloatToFixed(factor);
+    c->polygonOffset.units = gglFloatToFixed(units);
+}
+
+GLbitfield glQueryMatrixxOES(GLfixed* m, GLint* e)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    GLbitfield status = 0;
+    GLfloat const* f = c->transforms.current->top().elements();
+    for  (int i=0 ; i<16 ; i++) {
+        if (isnan(f[i]) || isinf(f[i])) {
+            status |= 1<<i;
+            continue;
+        }
+        e[i] = exponent(f[i]) - 7;
+        m[i] = mantissa(f[i]);
+    }
+    return status;
+}
diff --git a/opengl/libagl/matrix.h b/opengl/libagl/matrix.h
new file mode 100644
index 0000000..c9a38a9
--- /dev/null
+++ b/opengl/libagl/matrix.h
@@ -0,0 +1,355 @@
+/* libs/opengles/matrix.h
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_OPENGLES_MATRIX_H
+#define ANDROID_OPENGLES_MATRIX_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+namespace android {
+
+const int OGLES_MODELVIEW_STACK_DEPTH   = 16;
+const int OGLES_PROJECTION_STACK_DEPTH  =  2;
+const int OGLES_TEXTURE_STACK_DEPTH     =  2;
+
+void ogles_init_matrix(ogles_context_t*);
+void ogles_uninit_matrix(ogles_context_t*);
+void ogles_invalidate_perspective(ogles_context_t* c);
+void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want);
+
+int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y);
+
+void ogles_scissor(ogles_context_t* c, 
+        GLint x, GLint y, GLsizei w, GLsizei h);
+
+void ogles_viewport(ogles_context_t* c,
+        GLint x, GLint y, GLsizei w, GLsizei h);
+
+inline void ogles_validate_transform(
+        ogles_context_t* c, uint32_t want)
+{
+    if (c->transforms.dirty & want)
+        ogles_validate_transform_impl(c, want);
+}
+
+// ----------------------------------------------------------------------------
+
+inline
+GLfixed vsquare3(GLfixed a, GLfixed b, GLfixed c) 
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+    GLfixed r;
+    int32_t t;
+    asm(
+        "smull %0, %1, %2, %2       \n"
+        "smlal %0, %1, %3, %3       \n"
+        "smlal %0, %1, %4, %4       \n"
+        "movs  %0, %0, lsr #16      \n"
+        "adc   %0, %0, %1, lsl #16  \n"
+        :   "=&r"(r), "=&r"(t) 
+        :   "%r"(a), "r"(b), "r"(c)
+        :   "cc"
+        ); 
+    return r;
+
+#else
+
+    return ((   int64_t(a)*a +
+                int64_t(b)*b +
+                int64_t(c)*c + 0x8000)>>16);
+
+#endif
+}
+
+static inline GLfixed mla2a( GLfixed a0, GLfixed b0,
+                            GLfixed a1, GLfixed b1,
+                            GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+                            
+    GLfixed r;
+    int32_t t;
+    asm(
+        "smull %0, %1, %2, %3       \n"
+        "smlal %0, %1, %4, %5       \n"
+        "add   %0, %6, %0, lsr #16  \n"
+        "add   %0, %0, %1, lsl #16  \n"
+        :   "=&r"(r), "=&r"(t) 
+        :   "%r"(a0), "r"(b0), 
+            "%r"(a1), "r"(b1),
+            "r"(c)
+        :
+        ); 
+    return r;
+    
+#else
+
+    return ((   int64_t(a0)*b0 +
+                int64_t(a1)*b1)>>16) + c;
+
+#endif
+}
+
+static inline GLfixed mla3a( GLfixed a0, GLfixed b0,
+                             GLfixed a1, GLfixed b1,
+                             GLfixed a2, GLfixed b2,
+                             GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+                            
+    GLfixed r;
+    int32_t t;
+    asm(
+        "smull %0, %1, %2, %3       \n"
+        "smlal %0, %1, %4, %5       \n"
+        "smlal %0, %1, %6, %7       \n"
+        "add   %0, %8, %0, lsr #16  \n"
+        "add   %0, %0, %1, lsl #16  \n"
+        :   "=&r"(r), "=&r"(t) 
+        :   "%r"(a0), "r"(b0),
+            "%r"(a1), "r"(b1),
+            "%r"(a2), "r"(b2),
+            "r"(c)
+        :
+        ); 
+    return r;
+    
+#else
+
+    return ((   int64_t(a0)*b0 +
+                int64_t(a1)*b1 +
+                int64_t(a2)*b2)>>16) + c;
+
+#endif
+}
+
+// b0, b1, b2 are signed 16-bit quanities
+// that have been shifted right by 'shift' bits relative to normal
+// S16.16 fixed point
+static inline GLfixed mla3a16( GLfixed a0, int32_t b1b0,
+                               GLfixed a1,
+                               GLfixed a2, int32_t b2,
+                               GLint shift,
+                               GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+                            
+    GLfixed r;
+    asm(
+        "smulwb %0, %1, %2          \n"
+        "smlawt %0, %3, %2, %0      \n" 
+        "smlawb %0, %4, %5, %0      \n"
+        "add    %0, %7, %0, lsl %6  \n"
+        :   "=&r"(r)
+        :   "r"(a0), "r"(b1b0),
+            "r"(a1),
+            "r"(a2), "r"(b2),
+            "r"(shift),
+            "r"(c)
+        :
+        ); 
+    return r;
+    
+#else
+
+    int32_t accum;
+    int16_t b0 = b1b0 & 0xffff;
+    int16_t b1 = (b1b0 >> 16) & 0xffff;
+    accum  = int64_t(a0)*int16_t(b0) >> 16;
+    accum += int64_t(a1)*int16_t(b1) >> 16;
+    accum += int64_t(a2)*int16_t(b2) >> 16;
+    accum = (accum << shift) + c;
+    return accum;
+
+#endif
+}
+
+
+static inline GLfixed mla3a16_btb( GLfixed a0,
+                                   GLfixed a1,
+                                   GLfixed a2,
+                                   int32_t b1b0, int32_t xxb2,
+                                   GLint shift,
+                                   GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+                            
+    GLfixed r;
+    asm(
+        "smulwb %0, %1, %4          \n"
+        "smlawt %0, %2, %4, %0      \n" 
+        "smlawb %0, %3, %5, %0      \n"
+        "add    %0, %7, %0, lsl %6  \n"
+        :   "=&r"(r)
+        :   "r"(a0),
+            "r"(a1),
+            "r"(a2),
+            "r"(b1b0), "r"(xxb2),
+            "r"(shift),
+            "r"(c)
+        :
+        ); 
+    return r;
+    
+#else
+
+    int32_t accum;
+    int16_t b0 =  b1b0        & 0xffff;
+    int16_t b1 = (b1b0 >> 16) & 0xffff;
+    int16_t b2 =  xxb2        & 0xffff;
+    accum  = int64_t(a0)*int16_t(b0) >> 16;
+    accum += int64_t(a1)*int16_t(b1) >> 16;
+    accum += int64_t(a2)*int16_t(b2) >> 16;
+    accum = (accum << shift) + c;
+    return accum;
+
+#endif
+}
+
+static inline GLfixed mla3a16_btt( GLfixed a0,
+                                   GLfixed a1,
+                                   GLfixed a2,
+                                   int32_t b1b0, int32_t b2xx,
+                                   GLint shift,
+                                   GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+                            
+    GLfixed r;
+    asm(
+        "smulwb %0, %1, %4          \n"
+        "smlawt %0, %2, %4, %0      \n" 
+        "smlawt %0, %3, %5, %0      \n"
+        "add    %0, %7, %0, lsl %6  \n"
+        :   "=&r"(r)
+        :   "r"(a0),
+            "r"(a1),
+            "r"(a2),
+            "r"(b1b0), "r"(b2xx),
+            "r"(shift),
+            "r"(c)
+        :
+        ); 
+    return r;
+    
+#else
+
+    int32_t accum;
+    int16_t b0 =  b1b0        & 0xffff;
+    int16_t b1 = (b1b0 >> 16) & 0xffff;
+    int16_t b2 = (b2xx >> 16) & 0xffff;
+    accum  = int64_t(a0)*int16_t(b0) >> 16;
+    accum += int64_t(a1)*int16_t(b1) >> 16;
+    accum += int64_t(a2)*int16_t(b2) >> 16;
+    accum = (accum << shift) + c;
+    return accum;
+
+#endif
+}
+
+static inline GLfixed mla3( GLfixed a0, GLfixed b0,
+                            GLfixed a1, GLfixed b1,
+                            GLfixed a2, GLfixed b2)
+{
+#if defined(__arm__) && !defined(__thumb__)
+                            
+    GLfixed r;
+    int32_t t;
+    asm(
+        "smull %0, %1, %2, %3       \n"
+        "smlal %0, %1, %4, %5       \n"
+        "smlal %0, %1, %6, %7       \n"
+        "movs  %0, %0, lsr #16      \n"
+        "adc   %0, %0, %1, lsl #16  \n"
+        :   "=&r"(r), "=&r"(t) 
+        :   "%r"(a0), "r"(b0),
+            "%r"(a1), "r"(b1),
+            "%r"(a2), "r"(b2)
+        :   "cc"
+        ); 
+    return r;
+    
+#else
+
+    return ((   int64_t(a0)*b0 +
+                int64_t(a1)*b1 +
+                int64_t(a2)*b2 + 0x8000)>>16);
+
+#endif
+}
+
+static inline GLfixed mla4( GLfixed a0, GLfixed b0,
+                            GLfixed a1, GLfixed b1,
+                            GLfixed a2, GLfixed b2,
+                            GLfixed a3, GLfixed b3)
+{
+#if defined(__arm__) && !defined(__thumb__)
+                            
+    GLfixed r;
+    int32_t t;
+    asm(
+        "smull %0, %1, %2, %3       \n"
+        "smlal %0, %1, %4, %5       \n"
+        "smlal %0, %1, %6, %7       \n"
+        "smlal %0, %1, %8, %9       \n"
+        "movs  %0, %0, lsr #16      \n"
+        "adc   %0, %0, %1, lsl #16  \n"
+        :   "=&r"(r), "=&r"(t) 
+        :   "%r"(a0), "r"(b0),
+            "%r"(a1), "r"(b1),
+            "%r"(a2), "r"(b2),
+            "%r"(a3), "r"(b3)
+        :   "cc"
+        ); 
+    return r;
+    
+#else
+
+    return ((   int64_t(a0)*b0 +
+                int64_t(a1)*b1 +
+                int64_t(a2)*b2 +
+                int64_t(a3)*b3 + 0x8000)>>16);
+
+#endif
+}
+
+inline
+GLfixed dot4(const GLfixed* a, const GLfixed* b) 
+{
+    return mla4(a[0], b[0], a[1], b[1], a[2], b[2], a[3], b[3]);
+}
+
+
+inline
+GLfixed dot3(const GLfixed* a, const GLfixed* b) 
+{
+    return mla3(a[0], b[0], a[1], b[1], a[2], b[2]);
+}
+
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_MATRIX_H
+
diff --git a/opengl/libagl/mipmap.cpp b/opengl/libagl/mipmap.cpp
new file mode 100644
index 0000000..ccd77b7
--- /dev/null
+++ b/opengl/libagl/mipmap.cpp
@@ -0,0 +1,192 @@
+/* libs/opengles/mipmap.cpp
+**
+** Copyright 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 <stdlib.h>
+
+#include "context.h"
+#include "state.h"
+#include "texture.h"
+#include "TextureObjectManager.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex)
+{
+    int level = 0;
+    const GGLSurface* base = &tex->surface;    
+    const GGLFormat& pixelFormat(c->rasterizer.formats[base->format]);
+
+    int w = base->width;
+    int h = base->height;
+    if ((w&h) == 1)
+        return NO_ERROR;
+
+    w = (w>>1) ? : 1;
+    h = (h>>1) ? : 1;
+
+    while(true) {
+        ++level;
+        const int bpr = w * pixelFormat.size;
+        if (tex->reallocate(level, w, h, w,
+                base->format, base->compressedFormat, bpr) != NO_ERROR) {
+            return NO_MEMORY;
+        }
+    
+        int stride = w;
+        int bs = base->stride;
+        GGLSurface& cur = tex->editMip(level);
+
+        if (base->format == GGL_PIXEL_FORMAT_RGB_565)
+        {
+            uint16_t const * src = (uint16_t const *)base->data;
+            uint16_t* dst = (uint16_t*)cur.data;
+            const uint32_t mask = 0x07E0F81F;
+            for (int y=0 ; y<h ; y++) {
+                size_t offset = (y*2) * bs;
+                for (int x=0 ; x<w ; x++) {
+                    uint32_t p00 = src[offset];
+                    uint32_t p10 = src[offset+1];
+                    uint32_t p01 = src[offset+bs];
+                    uint32_t p11 = src[offset+bs+1];
+                    p00 = (p00 | (p00 << 16)) & mask;
+                    p01 = (p01 | (p01 << 16)) & mask;
+                    p10 = (p10 | (p10 << 16)) & mask;
+                    p11 = (p11 | (p11 << 16)) & mask;
+                    uint32_t grb = ((p00 + p10 + p01 + p11) >> 2) & mask;
+                    uint32_t rgb = (grb & 0xFFFF) | (grb >> 16);
+                    dst[x + y*stride] = rgb;
+                    offset += 2;
+                }
+            }
+        }
+        else if (base->format == GGL_PIXEL_FORMAT_RGBA_5551)
+        {
+            uint16_t const * src = (uint16_t const *)base->data;
+            uint16_t* dst = (uint16_t*)cur.data;
+            for (int y=0 ; y<h ; y++) {
+                size_t offset = (y*2) * bs;
+                for (int x=0 ; x<w ; x++) {
+                    uint32_t p00 = src[offset];
+                    uint32_t p10 = src[offset+1];
+                    uint32_t p01 = src[offset+bs];
+                    uint32_t p11 = src[offset+bs+1];
+                    uint32_t r = ((p00>>11)+(p10>>11)+(p01>>11)+(p11>>11)+2)>>2;
+                    uint32_t g = (((p00>>6)+(p10>>6)+(p01>>6)+(p11>>6)+2)>>2)&0x3F;
+                    uint32_t b = ((p00&0x3E)+(p10&0x3E)+(p01&0x3E)+(p11&0x3E)+4)>>3;
+                    uint32_t a = ((p00&1)+(p10&1)+(p01&1)+(p11&1)+2)>>2;
+                    dst[x + y*stride] = (r<<11)|(g<<6)|(b<<1)|a;
+                    offset += 2;
+                }
+            }
+        }
+        else if (base->format == GGL_PIXEL_FORMAT_RGBA_8888)
+        {
+            uint32_t const * src = (uint32_t const *)base->data;
+            uint32_t* dst = (uint32_t*)cur.data;
+            for (int y=0 ; y<h ; y++) {
+                size_t offset = (y*2) * bs;
+                for (int x=0 ; x<w ; x++) {
+                    uint32_t p00 = src[offset];
+                    uint32_t p10 = src[offset+1];
+                    uint32_t p01 = src[offset+bs];
+                    uint32_t p11 = src[offset+bs+1];
+                    uint32_t rb00 = p00 & 0x00FF00FF;
+                    uint32_t rb01 = p01 & 0x00FF00FF;
+                    uint32_t rb10 = p10 & 0x00FF00FF;
+                    uint32_t rb11 = p11 & 0x00FF00FF;
+                    uint32_t ga00 = (p00 >> 8) & 0x00FF00FF;
+                    uint32_t ga01 = (p01 >> 8) & 0x00FF00FF;
+                    uint32_t ga10 = (p10 >> 8) & 0x00FF00FF;
+                    uint32_t ga11 = (p11 >> 8) & 0x00FF00FF;
+                    uint32_t rb = (rb00 + rb01 + rb10 + rb11)>>2;
+                    uint32_t ga = (ga00 + ga01 + ga10 + ga11)>>2;
+                    uint32_t rgba = (rb & 0x00FF00FF) | ((ga & 0x00FF00FF)<<8);
+                    dst[x + y*stride] = rgba;
+                    offset += 2;
+                }
+            }
+        }
+        else if ((base->format == GGL_PIXEL_FORMAT_RGB_888) ||
+                 (base->format == GGL_PIXEL_FORMAT_LA_88) ||
+                 (base->format == GGL_PIXEL_FORMAT_A_8) ||
+                 (base->format == GGL_PIXEL_FORMAT_L_8))
+        {
+            int skip;
+            switch (base->format) {
+            case GGL_PIXEL_FORMAT_RGB_888:  skip = 3;   break;
+            case GGL_PIXEL_FORMAT_LA_88:    skip = 2;   break;
+            default:                        skip = 1;   break;
+            }
+            uint8_t const * src = (uint8_t const *)base->data;
+            uint8_t* dst = (uint8_t*)cur.data;            
+            bs *= skip;
+            stride *= skip;
+            for (int y=0 ; y<h ; y++) {
+                size_t offset = (y*2) * bs;
+                for (int x=0 ; x<w ; x++) {
+                    for (int c=0 ; c<skip ; c++) {
+                        uint32_t p00 = src[c+offset];
+                        uint32_t p10 = src[c+offset+skip];
+                        uint32_t p01 = src[c+offset+bs];
+                        uint32_t p11 = src[c+offset+bs+skip];
+                        dst[x + y*stride + c] = (p00 + p10 + p01 + p11) >> 2;
+                    }
+                    offset += 2*skip;
+                }
+            }
+        }
+        else if (base->format == GGL_PIXEL_FORMAT_RGBA_4444)
+        {
+            uint16_t const * src = (uint16_t const *)base->data;
+            uint16_t* dst = (uint16_t*)cur.data;
+            for (int y=0 ; y<h ; y++) {
+                size_t offset = (y*2) * bs;
+                for (int x=0 ; x<w ; x++) {
+                    uint32_t p00 = src[offset];
+                    uint32_t p10 = src[offset+1];
+                    uint32_t p01 = src[offset+bs];
+                    uint32_t p11 = src[offset+bs+1];
+                    p00 = ((p00 << 12) & 0x0F0F0000) | (p00 & 0x0F0F);
+                    p10 = ((p10 << 12) & 0x0F0F0000) | (p10 & 0x0F0F);
+                    p01 = ((p01 << 12) & 0x0F0F0000) | (p01 & 0x0F0F);
+                    p11 = ((p11 << 12) & 0x0F0F0000) | (p11 & 0x0F0F);
+                    uint32_t rbga = (p00 + p10 + p01 + p11) >> 2;
+                    uint32_t rgba = (rbga & 0x0F0F) | ((rbga>>12) & 0xF0F0);
+                    dst[x + y*stride] = rgba;
+                    offset += 2;
+                }
+            }
+        } else {
+            LOGE("Unsupported format (%d)", base->format);
+            return BAD_TYPE;
+        }
+
+        // exit condition: we just processed the 1x1 LODs
+        if ((w&h) == 1)
+            break;
+
+        base = &cur;
+        w = (w>>1) ? : 1;
+        h = (h>>1) ? : 1;
+    }
+    return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp
new file mode 100644
index 0000000..f164c02
--- /dev/null
+++ b/opengl/libagl/primitives.cpp
@@ -0,0 +1,1111 @@
+/* libs/opengles/primitives.cpp
+**
+** Copyright 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 <stdlib.h>
+#include <math.h>
+
+#include "context.h"
+#include "primitives.h"
+#include "light.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "fp.h"
+#include "TextureObjectManager.h"
+
+extern "C" void iterators0032(const void* that,
+        int32_t* it, int32_t c0, int32_t c1, int32_t c2);
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static void primitive_point(ogles_context_t* c, vertex_t* v);
+static void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1);
+static void primitive_clip_triangle(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void primitive_nop_point(ogles_context_t* c, vertex_t* v);
+static void primitive_nop_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1);
+static void primitive_nop_triangle(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static inline bool cull_triangle(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void lerp_triangle(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void lerp_texcoords(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void lerp_texcoords_w(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void triangle(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void clip_triangle(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static unsigned int clip_line(ogles_context_t* c,
+        vertex_t* s, vertex_t* p);
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+static void lightTriangleDarkSmooth(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    if (!(v0->flags & vertex_t::LIT)) {
+        v0->flags |= vertex_t::LIT;
+        const GLvoid* cp = c->arrays.color.element(
+                v0->index & vertex_cache_t::INDEX_MASK);
+        c->arrays.color.fetch(c, v0->color.v, cp);
+    }
+    if (!(v1->flags & vertex_t::LIT)) {
+        v1->flags |= vertex_t::LIT;
+        const GLvoid* cp = c->arrays.color.element(
+                v1->index & vertex_cache_t::INDEX_MASK);
+        c->arrays.color.fetch(c, v1->color.v, cp);
+    }
+    if(!(v2->flags & vertex_t::LIT)) {
+        v2->flags |= vertex_t::LIT;
+        const GLvoid* cp = c->arrays.color.element(
+                v2->index & vertex_cache_t::INDEX_MASK);
+        c->arrays.color.fetch(c, v2->color.v, cp);
+    }
+}
+
+static void lightTriangleDarkFlat(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    if (!(v2->flags & vertex_t::LIT)) {
+        v2->flags |= vertex_t::LIT;
+        const GLvoid* cp = c->arrays.color.element(
+                v2->index & vertex_cache_t::INDEX_MASK);
+        c->arrays.color.fetch(c, v2->color.v, cp);
+    }
+    // configure the rasterizer here, before we clip
+    c->rasterizer.procs.color4xv(c, v2->color.v);
+}
+
+static void lightTriangleSmooth(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    if (!(v0->flags & vertex_t::LIT))
+        c->lighting.lightVertex(c, v0);
+    if (!(v1->flags & vertex_t::LIT))
+        c->lighting.lightVertex(c, v1);
+    if(!(v2->flags & vertex_t::LIT))
+        c->lighting.lightVertex(c, v2);
+}
+
+static void lightTriangleFlat(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    if (!(v2->flags & vertex_t::LIT))
+        c->lighting.lightVertex(c, v2);
+    // configure the rasterizer here, before we clip
+    c->rasterizer.procs.color4xv(c, v2->color.v);
+}
+
+// The fog versions...
+
+static inline
+void lightVertexDarkSmoothFog(ogles_context_t* c, vertex_t* v)
+{
+    if (!(v->flags & vertex_t::LIT)) {
+        v->flags |= vertex_t::LIT;
+        v->fog = c->fog.fog(c, v->eye.z);
+        const GLvoid* cp = c->arrays.color.element(
+                v->index & vertex_cache_t::INDEX_MASK);
+        c->arrays.color.fetch(c, v->color.v, cp);
+    }
+}
+static inline
+void lightVertexDarkFlatFog(ogles_context_t* c, vertex_t* v)
+{
+    if (!(v->flags & vertex_t::LIT)) {
+        v->flags |= vertex_t::LIT;
+        v->fog = c->fog.fog(c, v->eye.z);
+    }
+}
+static inline
+void lightVertexSmoothFog(ogles_context_t* c, vertex_t* v)
+{
+    if (!(v->flags & vertex_t::LIT)) {
+        v->fog = c->fog.fog(c, v->eye.z);
+        c->lighting.lightVertex(c, v);
+    }
+}
+
+static void lightTriangleDarkSmoothFog(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    lightVertexDarkSmoothFog(c, v0);
+    lightVertexDarkSmoothFog(c, v1);
+    lightVertexDarkSmoothFog(c, v2);
+}
+
+static void lightTriangleDarkFlatFog(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    lightVertexDarkFlatFog(c, v0);
+    lightVertexDarkFlatFog(c, v1);
+    lightVertexDarkSmoothFog(c, v2);
+    // configure the rasterizer here, before we clip
+    c->rasterizer.procs.color4xv(c, v2->color.v);
+}
+
+static void lightTriangleSmoothFog(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    lightVertexSmoothFog(c, v0);
+    lightVertexSmoothFog(c, v1);
+    lightVertexSmoothFog(c, v2);
+}
+
+static void lightTriangleFlatFog(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    lightVertexDarkFlatFog(c, v0);
+    lightVertexDarkFlatFog(c, v1);
+    lightVertexSmoothFog(c, v2);
+    // configure the rasterizer here, before we clip
+    c->rasterizer.procs.color4xv(c, v2->color.v);
+}
+
+
+
+typedef void (*light_primitive_t)(ogles_context_t*,
+        vertex_t*, vertex_t*, vertex_t*);
+
+// fog 0x4, light 0x2, smooth 0x1
+static const light_primitive_t lightPrimitive[8] = {
+    lightTriangleDarkFlat,          // no fog | dark  | flat
+    lightTriangleDarkSmooth,        // no fog | dark  | smooth
+    lightTriangleFlat,              // no fog | light | flat
+    lightTriangleSmooth,            // no fog | light | smooth
+    lightTriangleDarkFlatFog,       // fog    | dark  | flat
+    lightTriangleDarkSmoothFog,     // fog    | dark  | smooth
+    lightTriangleFlatFog,           // fog    | light | flat
+    lightTriangleSmoothFog          // fog    | light | smooth
+};
+
+void ogles_validate_primitives(ogles_context_t* c)
+{
+    const uint32_t enables = c->rasterizer.state.enables;
+
+    // set up the lighting/shading/smoothing/fogging function
+    int index = enables & GGL_ENABLE_SMOOTH ? 0x1 : 0;
+    index |= c->lighting.enable ? 0x2 : 0;
+    index |= enables & GGL_ENABLE_FOG ? 0x4 : 0;
+    c->lighting.lightTriangle = lightPrimitive[index];
+    
+    // set up the primitive renderers
+    if (ggl_likely(c->arrays.vertex.enable)) {
+        c->prims.renderPoint    = primitive_point;
+        c->prims.renderLine     = primitive_line;
+        c->prims.renderTriangle = primitive_clip_triangle;
+    } else {
+        c->prims.renderPoint    = primitive_nop_point;
+        c->prims.renderLine     = primitive_nop_line;
+        c->prims.renderTriangle = primitive_nop_triangle;
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+void compute_iterators_t::initTriangle(
+        vertex_t const* v0, vertex_t const* v1, vertex_t const* v2)
+{
+    m_dx01 = v1->window.x - v0->window.x;
+    m_dy10 = v0->window.y - v1->window.y;
+    m_dx20 = v0->window.x - v2->window.x;
+    m_dy02 = v2->window.y - v0->window.y;
+    m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20;
+}
+
+void compute_iterators_t::initLine(
+        vertex_t const* v0, vertex_t const* v1)
+{
+    m_dx01 = m_dy02 = v1->window.x - v0->window.x;
+    m_dy10 = m_dx20 = v0->window.y - v1->window.y;
+    m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20;
+}
+
+void compute_iterators_t::initLerp(vertex_t const* v0, uint32_t enables)
+{
+    m_x0 = v0->window.x;
+    m_y0 = v0->window.y;
+    const GGLcoord area = (m_area + TRI_HALF) >> TRI_FRACTION_BITS;
+    const GGLcoord minArea = 2; // cannot be inverted
+    // triangles with an area smaller than 1.0 are not smooth-shaded
+
+    int q=0, s=0, d=0;
+    if (abs(area) >= minArea) {
+        // Here we do some voodoo magic, to compute a suitable scale
+        // factor for deltas/area:
+
+        // First compute the 1/area with full 32-bits precision,
+        // gglRecipQNormalized returns a number [-0.5, 0.5[ and an exponent.
+        d = gglRecipQNormalized(area, &q);
+
+        // Then compute the minimum left-shift to not overflow the muls
+        // below. 
+        s = 32 - gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20));
+
+        // We'll keep 16-bits of precision for deltas/area. So we need
+        // to shift everything left an extra 15 bits.
+        s += 15;
+        
+        // make sure all final shifts are not > 32, because gglMulx
+        // can't handle it.
+        if (s < q) s = q;
+        if (s > 32) {
+            d >>= 32-s;
+            s = 32;
+        }
+    }
+
+    m_dx01 = gglMulx(m_dx01, d, s);
+    m_dy10 = gglMulx(m_dy10, d, s);
+    m_dx20 = gglMulx(m_dx20, d, s);
+    m_dy02 = gglMulx(m_dy02, d, s);
+    m_area_scale = 32 + q - s;
+    m_scale = 0;
+
+    if (enables & GGL_ENABLE_TMUS) {
+        const int A = gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20));
+        const int B = gglClz(abs(m_x0)|abs(m_y0));
+        m_scale = max(0, 32 - (A + 16)) +
+                  max(0, 32 - (B + TRI_FRACTION_BITS)) + 1;
+    }
+}
+
+int compute_iterators_t::iteratorsScale(GGLfixed* it,
+        int32_t c0, int32_t c1, int32_t c2) const
+{
+    int32_t dc01 = c1 - c0;
+    int32_t dc02 = c2 - c0;
+    const int A = gglClz(abs(c0));
+    const int B = gglClz(abs(dc01)|abs(dc02));
+    const int scale = min(A, B - m_scale) - 2;
+    if (scale >= 0) {
+        c0   <<= scale;
+        dc01 <<= scale;
+        dc02 <<= scale;
+    } else {
+        c0   >>= -scale;
+        dc01 >>= -scale;
+        dc02 >>= -scale;
+    }
+    const int s = m_area_scale;
+    int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s);
+    int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s);
+    int32_t c = c0 - (gglMulAddx(dcdx, m_x0, 
+            gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS));
+    it[0] = c;
+    it[1] = dcdx;
+    it[2] = dcdy;
+    return scale;
+}
+
+void compute_iterators_t::iterators1616(GGLfixed* it,
+        GGLfixed c0, GGLfixed c1, GGLfixed c2) const
+{
+    const GGLfixed dc01 = c1 - c0;
+    const GGLfixed dc02 = c2 - c0;
+    // 16.16 x 16.16 == 32.32 --> 16.16
+    const int s = m_area_scale;
+    int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s);
+    int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s);
+    int32_t c = c0 - (gglMulAddx(dcdx, m_x0,
+            gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS));
+    it[0] = c;
+    it[1] = dcdx;
+    it[2] = dcdy;
+}
+
+void compute_iterators_t::iterators0032(int64_t* it,
+        int32_t c0, int32_t c1, int32_t c2) const
+{
+    const int s = m_area_scale - 16;
+    int32_t dc01 = (c1 - c0)>>s;
+    int32_t dc02 = (c2 - c0)>>s;
+    // 16.16 x 16.16 == 32.32
+    int64_t dcdx = gglMulii(dc01, m_dy02) + gglMulii(dc02, m_dy10);
+    int64_t dcdy = gglMulii(dc02, m_dx01) + gglMulii(dc01, m_dx20);
+    it[ 0] = (c0<<16) - ((dcdx*m_x0 + dcdy*m_y0)>>4);
+    it[ 1] = dcdx;
+    it[ 2] = dcdy;
+}
+
+#if defined(__arm__) && !defined(__thumb__)
+inline void compute_iterators_t::iterators0032(int32_t* it,
+        int32_t c0, int32_t c1, int32_t c2) const
+{
+    ::iterators0032(this, it, c0, c1, c2);
+}
+#else
+void compute_iterators_t::iterators0032(int32_t* it,
+        int32_t c0, int32_t c1, int32_t c2) const
+{
+    int64_t it64[3];
+    iterators0032(it, c0, c1, c2);
+    it[0] = it64[0];
+    it[1] = it64[1];
+    it[2] = it64[2];
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+static inline int32_t clampZ(GLfixed z) CONST;
+int32_t clampZ(GLfixed z) {
+    z = (z & ~(z>>31));
+    if (z >= 0x10000)
+        z = 0xFFFF;
+    return z;
+}
+
+static __attribute__((noinline))
+void fetch_texcoord_impl(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    vertex_t* const vtx[3] = { v0, v1, v2 };
+    array_t const * const texcoordArray = c->arrays.texture;
+    
+    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+        if (!(c->rasterizer.state.texture[i].enable))
+            continue;
+        
+        for (int j=0 ; j<3 ; j++) {
+            vertex_t* const v = vtx[j];
+            if (v->flags & vertex_t::TT)
+                continue;
+
+            // NOTE: here we could compute automatic texgen
+            // such as sphere/cube maps, instead of fetching them
+            // from the textcoord array.
+
+            vec4_t& coords = v->texture[i];
+            const GLubyte* tp = texcoordArray[i].element(
+                    v->index & vertex_cache_t::INDEX_MASK);
+            texcoordArray[i].fetch(c, coords.v, tp);
+
+            // transform texture coordinates...
+            coords.Q = 0x10000;
+            const transform_t& tr = c->transforms.texture[i].transform; 
+            if (ggl_unlikely(tr.ops)) {
+                c->arrays.tex_transform[i](&tr, &coords, &coords);
+            }
+
+            // divide by Q
+            const GGLfixed q = coords.Q;
+            if (ggl_unlikely(q != 0x10000)) {
+                const int32_t qinv = gglRecip28(q);
+                coords.S = gglMulx(coords.S, qinv, 28);
+                coords.T = gglMulx(coords.T, qinv, 28);
+            }
+        }
+    }
+    v0->flags |= vertex_t::TT;
+    v1->flags |= vertex_t::TT;
+    v2->flags |= vertex_t::TT;
+}
+
+inline void fetch_texcoord(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    const uint32_t enables = c->rasterizer.state.enables;
+    if (!(enables & GGL_ENABLE_TMUS))
+        return;
+
+    // Fetch & transform texture coordinates...
+    if (ggl_likely(v0->flags & v1->flags & v2->flags & vertex_t::TT)) {
+        // already done for all three vertices, bail...
+        return;
+    }
+    fetch_texcoord_impl(c, v0, v1, v2);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Point
+#endif
+
+void primitive_nop_point(ogles_context_t*, vertex_t*) {
+}
+
+void primitive_point(ogles_context_t* c, vertex_t* v)
+{
+    // lighting & clamping...
+    const uint32_t enables = c->rasterizer.state.enables;
+
+    if (ggl_unlikely(!(v->flags & vertex_t::LIT))) {
+        if (c->lighting.enable) {
+            c->lighting.lightVertex(c, v);
+        } else {
+            v->flags |= vertex_t::LIT;
+            const GLvoid* cp = c->arrays.color.element(
+                    v->index & vertex_cache_t::INDEX_MASK);
+            c->arrays.color.fetch(c, v->color.v, cp);
+        }
+        if (enables & GGL_ENABLE_FOG) {
+            v->fog = c->fog.fog(c, v->eye.z);
+        }
+    }
+
+    // XXX: we don't need to do that each-time
+    // if color array and lighting not enabled 
+    c->rasterizer.procs.color4xv(c, v->color.v);
+
+    // XXX: look into ES point-sprite extension
+    if (enables & GGL_ENABLE_TMUS) {
+        fetch_texcoord(c, v,v,v);
+        for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+            if (!c->rasterizer.state.texture[i].enable) 
+                continue;
+            int32_t itt[8];
+            itt[1] = itt[2] = itt[4] = itt[5] = 0;
+            itt[6] = itt[7] = 16; // XXX: check that
+            if (c->rasterizer.state.texture[i].s_wrap == GGL_CLAMP) {
+                int width = c->textures.tmu[i].texture->surface.width;
+                itt[0] = v->texture[i].S * width;
+                itt[6] = 0;
+            }
+            if (c->rasterizer.state.texture[i].t_wrap == GGL_CLAMP) {
+                int height = c->textures.tmu[i].texture->surface.height;
+                itt[3] = v->texture[i].T * height;
+                itt[7] = 0;
+            }
+            c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
+        }
+    }
+    
+    if (enables & GGL_ENABLE_DEPTH_TEST) {
+        int32_t itz[3];
+        itz[0] = clampZ(v->window.z) * 0x00010001;
+        itz[1] = itz[2] = 0;
+        c->rasterizer.procs.zGrad3xv(c, itz);
+    }
+
+    if (enables & GGL_ENABLE_FOG) {
+        GLfixed itf[3];
+        itf[0] = v->fog;
+        itf[1] = itf[2] = 0;
+        c->rasterizer.procs.fogGrad3xv(c, itf);
+    }
+
+    // Render our point...
+    c->rasterizer.procs.pointx(c, v->window.v, c->point.size);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Line
+#endif
+
+void primitive_nop_line(ogles_context_t*, vertex_t*, vertex_t*) {
+}
+
+void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1)
+{
+    // get texture coordinates
+    fetch_texcoord(c, v0, v1, v1);
+
+    // light/shade the vertices first (they're copied below)
+    c->lighting.lightTriangle(c, v0, v1, v1);
+
+    // clip the line if needed
+    if (ggl_unlikely((v0->flags | v1->flags) & vertex_t::CLIP_ALL)) {
+        unsigned int count = clip_line(c, v0, v1);
+        if (ggl_unlikely(count == 0))
+            return;
+    }
+
+    // compute iterators...
+    const uint32_t enables = c->rasterizer.state.enables;
+    const uint32_t mask =   GGL_ENABLE_TMUS |
+                            GGL_ENABLE_SMOOTH |
+                            GGL_ENABLE_W | 
+                            GGL_ENABLE_FOG |
+                            GGL_ENABLE_DEPTH_TEST;
+
+    if (ggl_unlikely(enables & mask)) {
+        c->lerp.initLine(v0, v1);
+        lerp_triangle(c, v0, v1, v0);
+    }
+
+    // render our line
+    c->rasterizer.procs.linex(c, v0->window.v, v1->window.v, c->line.width);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Triangle
+#endif
+
+void primitive_nop_triangle(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2) {
+}
+
+void primitive_clip_triangle(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    uint32_t cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL;
+    if (ggl_likely(!cc)) {
+        // code below must be as optimized as possible, this is the
+        // common code path.
+
+        // This triangle is not clipped, test if it's culled
+        // unclipped triangle...
+        c->lerp.initTriangle(v0, v1, v2);
+        if (cull_triangle(c, v0, v1, v2))
+            return; // culled!
+
+        // Fetch all texture coordinates if needed
+        fetch_texcoord(c, v0, v1, v2);
+
+        // light (or shade) our triangle!
+        c->lighting.lightTriangle(c, v0, v1, v2);
+
+        triangle(c, v0, v1, v2);
+        return;
+    }
+
+    // The assumption here is that we're not going to clip very often,
+    // and even more rarely will we clip a triangle that ends up
+    // being culled out. So it's okay to light the vertices here, even though
+    // in a few cases we won't render the triangle (if culled).
+
+    // Fetch texture coordinates...
+    fetch_texcoord(c, v0, v1, v2);
+
+    // light (or shade) our triangle!
+    c->lighting.lightTriangle(c, v0, v1, v2);
+
+    clip_triangle(c, v0, v1, v2);
+}
+
+// -----------------------------------------------------------------------
+
+void triangle(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    // compute iterators...
+    const uint32_t enables = c->rasterizer.state.enables;
+    const uint32_t mask =   GGL_ENABLE_TMUS |
+                            GGL_ENABLE_SMOOTH |
+                            GGL_ENABLE_W | 
+                            GGL_ENABLE_FOG |
+                            GGL_ENABLE_DEPTH_TEST;
+
+    if (ggl_likely(enables & mask))
+        lerp_triangle(c, v0, v1, v2);
+
+    c->rasterizer.procs.trianglex(c, v0->window.v, v1->window.v, v2->window.v);
+}
+
+void lerp_triangle(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    const uint32_t enables = c->rasterizer.state.enables;
+    c->lerp.initLerp(v0, enables);
+
+    // set up texture iterators
+    if (enables & GGL_ENABLE_TMUS) {
+        if (enables & GGL_ENABLE_W) {
+            lerp_texcoords_w(c, v0, v1, v2);
+        } else {
+            lerp_texcoords(c, v0, v1, v2);
+        }
+    }
+
+    // set up the color iterators
+    const compute_iterators_t& lerp = c->lerp;
+    if (enables & GGL_ENABLE_SMOOTH) {
+        GLfixed itc[12];
+        for (int i=0 ; i<4 ; i++) {
+            const GGLcolor c0 = v0->color.v[i] * 255;
+            const GGLcolor c1 = v1->color.v[i] * 255;
+            const GGLcolor c2 = v2->color.v[i] * 255;
+            lerp.iterators1616(&itc[i*3], c0, c1, c2);
+        }
+        c->rasterizer.procs.colorGrad12xv(c, itc);
+    }
+
+    if (enables & GGL_ENABLE_DEPTH_TEST) {
+        int32_t itz[3];
+        const int32_t v0z = clampZ(v0->window.z);
+        const int32_t v1z = clampZ(v1->window.z);
+        const int32_t v2z = clampZ(v2->window.z);
+        if (ggl_unlikely(c->polygonOffset.enable)) {
+            const int32_t units = (c->polygonOffset.units << 16);
+            const GLfixed factor = c->polygonOffset.factor;
+            if (factor) {
+                int64_t itz64[3];
+                lerp.iterators0032(itz64, v0z, v1z, v2z);
+                int64_t maxDepthSlope = max(itz64[1], itz64[2]);
+                itz[0] = uint32_t(itz64[0]) 
+                        + uint32_t((maxDepthSlope*factor)>>16) + units;
+                itz[1] = uint32_t(itz64[1]);
+                itz[2] = uint32_t(itz64[2]);
+            } else {
+                lerp.iterators0032(itz, v0z, v1z, v2z);
+                itz[0] += units; 
+            }
+        } else {
+            lerp.iterators0032(itz, v0z, v1z, v2z);
+        }
+        c->rasterizer.procs.zGrad3xv(c, itz);
+    }    
+
+    if (ggl_unlikely(enables & GGL_ENABLE_FOG)) {
+        GLfixed itf[3];
+        lerp.iterators1616(itf, v0->fog, v1->fog, v2->fog);
+        c->rasterizer.procs.fogGrad3xv(c, itf);
+    }
+}
+
+
+static inline
+int compute_lod(ogles_context_t* c, int i,
+        int32_t s0, int32_t t0, int32_t s1, int32_t t1, int32_t s2, int32_t t2)
+{
+    // Compute mipmap level / primitive
+    // rho = sqrt( texelArea / area )
+    // lod = log2( rho )
+    // lod = log2( texelArea / area ) / 2
+    // lod = (log2( texelArea ) - log2( area )) / 2
+    const compute_iterators_t& lerp = c->lerp;
+    const GGLcoord area = abs(lerp.area());
+    const int w = c->textures.tmu[i].texture->surface.width;
+    const int h = c->textures.tmu[i].texture->surface.height;
+    const int shift = 16 + (16 - TRI_FRACTION_BITS);
+    int32_t texelArea = abs( gglMulx(s1-s0, t2-t0, shift) -
+            gglMulx(s2-s0, t1-t0, shift) )*w*h;
+    int log2TArea = (32-TRI_FRACTION_BITS  -1) - gglClz(texelArea);
+    int log2Area  = (32-TRI_FRACTION_BITS*2-1) - gglClz(area);
+    int lod = (log2TArea - log2Area + 1) >> 1;
+    return lod;
+}
+
+void lerp_texcoords(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    const compute_iterators_t& lerp = c->lerp;
+    int32_t itt[8] __attribute__((aligned(16)));
+    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+        const texture_t& tmu = c->rasterizer.state.texture[i];
+        if (!tmu.enable) 
+            continue;
+
+        // compute the jacobians using block floating-point
+        int32_t s0 = v0->texture[i].S;
+        int32_t t0 = v0->texture[i].T;
+        int32_t s1 = v1->texture[i].S;
+        int32_t t1 = v1->texture[i].T;
+        int32_t s2 = v2->texture[i].S;
+        int32_t t2 = v2->texture[i].T;
+
+        const GLenum min_filter = c->textures.tmu[i].texture->min_filter;
+        if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) {
+            int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2);
+            c->rasterizer.procs.bindTextureLod(c, i,
+                    &c->textures.tmu[i].texture->mip(lod));
+        }
+
+        // premultiply (s,t) when clampling
+        if (tmu.s_wrap == GGL_CLAMP) {
+            const int width = tmu.surface.width;
+            s0 *= width;
+            s1 *= width;
+            s2 *= width;
+        }
+        if (tmu.t_wrap == GGL_CLAMP) {
+            const int height = tmu.surface.height;
+            t0 *= height;
+            t1 *= height;
+            t2 *= height;
+        }
+        itt[6] = -lerp.iteratorsScale(itt+0, s0, s1, s2);
+        itt[7] = -lerp.iteratorsScale(itt+3, t0, t1, t2);
+        c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
+    }
+}
+
+void lerp_texcoords_w(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    const compute_iterators_t& lerp = c->lerp;
+    int32_t itt[8] __attribute__((aligned(16)));
+    int32_t itw[3];
+
+    // compute W's scale to 2.30
+    int32_t w0 = v0->window.w;
+    int32_t w1 = v1->window.w;
+    int32_t w2 = v2->window.w;
+    int wscale = 32 - gglClz(w0|w1|w2);
+
+    // compute the jacobian using block floating-point    
+    int sc = lerp.iteratorsScale(itw, w0, w1, w2);
+    sc +=  wscale - 16;
+    c->rasterizer.procs.wGrad3xv(c, itw);
+
+    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+        const texture_t& tmu = c->rasterizer.state.texture[i];
+        if (!tmu.enable) 
+            continue;
+
+        // compute the jacobians using block floating-point
+        int32_t s0 = v0->texture[i].S;
+        int32_t t0 = v0->texture[i].T;
+        int32_t s1 = v1->texture[i].S;
+        int32_t t1 = v1->texture[i].T;
+        int32_t s2 = v2->texture[i].S;
+        int32_t t2 = v2->texture[i].T;
+
+        const GLenum min_filter = c->textures.tmu[i].texture->min_filter;
+        if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) {
+            int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2);
+            c->rasterizer.procs.bindTextureLod(c, i,
+                    &c->textures.tmu[i].texture->mip(lod));
+        }
+
+        // premultiply (s,t) when clampling
+        if (tmu.s_wrap == GGL_CLAMP) {
+            const int width = tmu.surface.width;
+            s0 *= width;
+            s1 *= width;
+            s2 *= width;
+        }
+        if (tmu.t_wrap == GGL_CLAMP) {
+            const int height = tmu.surface.height;
+            t0 *= height;
+            t1 *= height;
+            t2 *= height;
+        }
+
+        s0 = gglMulx(s0, w0, wscale);
+        t0 = gglMulx(t0, w0, wscale);
+        s1 = gglMulx(s1, w1, wscale);
+        t1 = gglMulx(t1, w1, wscale);
+        s2 = gglMulx(s2, w2, wscale);
+        t2 = gglMulx(t2, w2, wscale);
+
+        itt[6] = sc - lerp.iteratorsScale(itt+0, s0, s1, s2);
+        itt[7] = sc - lerp.iteratorsScale(itt+3, t0, t1, t2);
+        c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
+    }
+}
+
+
+static inline
+bool cull_triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    if (ggl_likely(c->cull.enable)) {
+        const GLenum winding = (c->lerp.area() > 0) ? GL_CW : GL_CCW;
+        const GLenum face = (winding == c->cull.frontFace) ? GL_FRONT : GL_BACK;
+        if (face == c->cull.cullFace)
+            return true; // culled!
+    }
+    return false;
+}
+
+static inline
+GLfixed frustumPlaneDist(int plane, const vec4_t& s)
+{
+    const GLfixed d = s.v[ plane >> 1 ];
+    return  ((plane & 1) ? (s.w - d) : (s.w + d)); 
+}
+
+static inline
+int32_t clipDivide(GLfixed a, GLfixed b) {
+    // returns a 4.28 fixed-point
+    return gglMulDivi(1LU<<28, a, b);
+} 
+
+void clip_triangle(ogles_context_t* c,
+        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+    uint32_t all_cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL;
+
+    vertex_t *p0, *p1, *p2;
+    const int MAX_CLIPPING_PLANES = 6 + OGLES_MAX_CLIP_PLANES;
+    const int MAX_VERTICES = 3;
+
+    // Temporary buffer to hold the new vertices. Each plane can add up to 
+    // two new vertices (because the polygon is convex).
+    // We need one extra element, to handle an overflow case when
+    // the polygon degenerates into something non convex.
+    vertex_t buffer[MAX_CLIPPING_PLANES * 2 + 1];   // ~3KB
+    vertex_t* buf = buffer;
+
+    // original list of vertices (polygon to clip, in fact this
+    // function works with an arbitrary polygon).
+    vertex_t* in[3] = { v0, v1, v2 };
+    
+    // output lists (we need 2, which we use back and forth)
+    // (maximum outpout list's size is MAX_CLIPPING_PLANES + MAX_VERTICES)
+    // 2 more elements for overflow when non convex polygons.
+    vertex_t* out[2][MAX_CLIPPING_PLANES + MAX_VERTICES + 2];
+    unsigned int outi = 0;
+    
+    // current input list
+    vertex_t** ivl = in;
+
+    // 3 input vertices, 0 in the output list, first plane
+    unsigned int ic = 3;
+
+    // User clip-planes first, the clipping is always done in eye-coordinate
+    // this is basically the same algorithm than for the view-volume
+    // clipping, except for the computation of the distance (vertex, plane)
+    // and the fact that we need to compute the eye-coordinates of each
+    // new vertex we create.
+    
+    if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL))
+    {
+        unsigned int plane = 0;
+        uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8;
+        do {
+            if (cc & 1) {        
+                // pointers to our output list (head and current)
+                vertex_t** const ovl = &out[outi][0];
+                vertex_t** output = ovl;
+                unsigned int oc = 0;
+                unsigned int sentinel = 0;
+                // previous vertex, compute distance to the plane
+                vertex_t* s = ivl[ic-1];
+                const vec4_t& equation = c->clipPlanes.plane[plane].equation;
+                GLfixed sd = dot4(equation.v, s->eye.v);
+                // clip each vertex against this plane...
+                for (unsigned int i=0 ; i<ic ; i++) {            
+                    vertex_t* p = ivl[i];
+                    const GLfixed pd = dot4(equation.v, p->eye.v);
+                    if (sd >= 0) {
+                        if (pd >= 0) {
+                            // both inside
+                            *output++ = p;
+                            oc++;
+                        } else {
+                            // s inside, p outside (exiting)
+                            const GLfixed t = clipDivide(sd, sd-pd);
+                            c->arrays.clipEye(c, buf, t, p, s);
+                            *output++ = buf++;
+                            oc++;
+                            if (++sentinel >= 3)
+                                return; // non-convex polygon!
+                        }
+                    } else {
+                        if (pd >= 0) {
+                            // s outside (entering)
+                            if (pd) {
+                                const GLfixed t = clipDivide(pd, pd-sd);
+                                c->arrays.clipEye(c, buf, t, s, p);
+                                *output++ = buf++;
+                                oc++;
+                                if (++sentinel >= 3)
+                                    return; // non-convex polygon!
+                            }
+                            *output++ = p;
+                            oc++;
+                        } else {
+                           // both outside
+                        }
+                    }
+                    s = p;
+                    sd = pd;
+                }
+                // output list become the new input list
+                if (oc<3)
+                    return; // less than 3 vertices left? we're done!
+                ivl = ovl;
+                ic = oc;
+                outi = 1-outi;
+            }
+            cc >>= 1;
+            plane++;
+        } while (cc);
+    }
+
+    // frustum clip-planes
+    if (all_cc & vertex_t::FRUSTUM_CLIP_ALL)
+    {
+        unsigned int plane = 0;
+        uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL;
+        do {
+            if (cc & 1) {        
+                // pointers to our output list (head and current)
+                vertex_t** const ovl = &out[outi][0];
+                vertex_t** output = ovl;
+                unsigned int oc = 0;
+                unsigned int sentinel = 0;
+                // previous vertex, compute distance to the plane
+                vertex_t* s = ivl[ic-1];
+                GLfixed sd = frustumPlaneDist(plane, s->clip);
+                // clip each vertex against this plane...
+                for (unsigned int i=0 ; i<ic ; i++) {            
+                    vertex_t* p = ivl[i];
+                    const GLfixed pd = frustumPlaneDist(plane, p->clip);
+                    if (sd >= 0) {
+                        if (pd >= 0) {
+                            // both inside
+                            *output++ = p;
+                            oc++;
+                        } else {
+                            // s inside, p outside (exiting)
+                            const GLfixed t = clipDivide(sd, sd-pd);
+                            c->arrays.clipVertex(c, buf, t, p, s);
+                            *output++ = buf++;
+                            oc++;
+                            if (++sentinel >= 3)
+                                return; // non-convex polygon!
+                        }
+                    } else {
+                        if (pd >= 0) {
+                            // s outside (entering)
+                            if (pd) {
+                                const GLfixed t = clipDivide(pd, pd-sd);
+                                c->arrays.clipVertex(c, buf, t, s, p);
+                                *output++ = buf++;
+                                oc++;
+                                if (++sentinel >= 3)
+                                    return; // non-convex polygon!
+                            }
+                            *output++ = p;
+                            oc++;
+                        } else {
+                           // both outside
+                        }
+                    }
+                    s = p;
+                    sd = pd;
+                }
+                // output list become the new input list
+                if (oc<3)
+                    return; // less than 3 vertices left? we're done!
+                ivl = ovl;
+                ic = oc;
+                outi = 1-outi;
+            }
+            cc >>= 1;
+            plane++;
+        } while (cc);
+    }
+    
+    // finally we can render our triangles...
+    p0 = ivl[0];
+    p1 = ivl[1];
+    for (unsigned int i=2 ; i<ic ; i++) {
+        p2 = ivl[i];
+        c->lerp.initTriangle(p0, p1, p2);
+        if (cull_triangle(c, p0, p1, p2)) {
+            p1 = p2;
+            continue; // culled!
+        }
+        triangle(c, p0, p1, p2);
+        p1 = p2;
+    }
+}
+
+unsigned int clip_line(ogles_context_t* c, vertex_t* s, vertex_t* p)
+{
+    const uint32_t all_cc = (s->flags | p->flags) & vertex_t::CLIP_ALL;
+
+    if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL))
+    {
+        unsigned int plane = 0;
+        uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8;
+        do {
+            if (cc & 1) {
+                const vec4_t& equation = c->clipPlanes.plane[plane].equation;
+                const GLfixed sd = dot4(equation.v, s->eye.v);
+                const GLfixed pd = dot4(equation.v, p->eye.v);
+                if (sd >= 0) {
+                    if (pd >= 0) {
+                        // both inside
+                    } else {
+                        // s inside, p outside (exiting)
+                        const GLfixed t = clipDivide(sd, sd-pd);
+                        c->arrays.clipEye(c, p, t, p, s);
+                    }
+                } else {
+                    if (pd >= 0) {
+                        // s outside (entering)
+                        if (pd) {
+                            const GLfixed t = clipDivide(pd, pd-sd);
+                            c->arrays.clipEye(c, s, t, s, p);
+                        }
+                    } else {
+                       // both outside
+                       return 0;
+                    }
+                }
+            }
+            cc >>= 1;
+            plane++;
+        } while (cc);
+    }
+
+    // frustum clip-planes
+    if (all_cc & vertex_t::FRUSTUM_CLIP_ALL)
+    {
+        unsigned int plane = 0;
+        uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL;
+        do {
+            if (cc & 1) {
+                const GLfixed sd = frustumPlaneDist(plane, s->clip);
+                const GLfixed pd = frustumPlaneDist(plane, p->clip);
+                if (sd >= 0) {
+                    if (pd >= 0) {
+                        // both inside
+                    } else {
+                        // s inside, p outside (exiting)
+                        const GLfixed t = clipDivide(sd, sd-pd);
+                        c->arrays.clipVertex(c, p, t, p, s);
+                    }
+                } else {
+                    if (pd >= 0) {
+                        // s outside (entering)
+                        if (pd) {
+                            const GLfixed t = clipDivide(pd, pd-sd);
+                            c->arrays.clipVertex(c, s, t, s, p);
+                        }
+                    } else {
+                       // both outside
+                       return 0;
+                    }
+                }
+            }
+            cc >>= 1;
+            plane++;
+        } while (cc);
+    }
+
+    return 2;
+}
+
+
+}; // namespace android
diff --git a/opengl/libagl/primitives.h b/opengl/libagl/primitives.h
new file mode 100644
index 0000000..1bef604
--- /dev/null
+++ b/opengl/libagl/primitives.h
@@ -0,0 +1,37 @@
+/* libs/opengles/primitives.h
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_OPENGLES_PRIMITIVES_H
+#define ANDROID_OPENGLES_PRIMITIVES_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+
+namespace android {
+
+namespace gl {
+struct ogles_context_t;
+};
+
+void ogles_validate_primitives(ogles_context_t* c);
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_PRIMITIVES_H
+
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
new file mode 100644
index 0000000..5cbabea
--- /dev/null
+++ b/opengl/libagl/state.cpp
@@ -0,0 +1,586 @@
+/* libs/opengles/state.cpp
+**
+** Copyright 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 <stdlib.h>
+
+#include "context.h"
+#include "fp.h"
+#include "state.h"
+#include "array.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "light.h"
+#include "texture.h"
+#include "BufferObjectManager.h"
+#include "TextureObjectManager.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static char const * const gVendorString     = "Android";
+static char const * const gRendererString   = "Android PixelFlinger 1.0";
+static char const * const gVersionString    = "OpenGL ES-CM 1.0";
+static char const * const gExtensionsString =
+    "GL_OES_byte_coordinates "              // OK
+    "GL_OES_fixed_point "                   // OK
+    "GL_OES_single_precision "              // OK
+    "GL_OES_read_format "                   // OK
+    "GL_OES_compressed_paletted_texture "   // OK
+    "GL_OES_draw_texture "                  // OK
+    "GL_OES_matrix_get "                    // OK
+    "GL_OES_query_matrix "                  // OK
+    //        "GL_OES_point_size_array "              // TODO
+    //        "GL_OES_point_sprite "                  // TODO
+    "GL_ARB_texture_compression "           // OK
+    "GL_ARB_texture_non_power_of_two "      // OK
+    "GL_ANDROID_direct_texture "            // OK
+    "GL_ANDROID_user_clip_plane "           // OK
+    "GL_ANDROID_vertex_buffer_object "      // OK
+    "GL_ANDROID_generate_mipmap "           // OK
+    ;
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+ogles_context_t *ogles_init(size_t extra)
+{
+    void* const base = malloc(extra + sizeof(ogles_context_t) + 32);
+	if (!base) return 0;
+
+    ogles_context_t *c =
+            (ogles_context_t *)((ptrdiff_t(base) + extra + 31) & ~0x1FL);
+    memset(c, 0, sizeof(ogles_context_t));
+    ggl_init_context(&(c->rasterizer));
+    
+    // XXX: this should be passed as an argument
+    sp<EGLSurfaceManager> smgr(new EGLSurfaceManager());
+    c->surfaceManager = smgr.get();
+    c->surfaceManager->incStrong(c);
+
+    sp<EGLBufferObjectManager> bomgr(new EGLBufferObjectManager());
+    c->bufferObjectManager = bomgr.get();
+    c->bufferObjectManager->incStrong(c);
+
+    ogles_init_array(c);
+    ogles_init_matrix(c);
+    ogles_init_vertex(c);
+    ogles_init_light(c);
+    ogles_init_texture(c);
+
+    c->rasterizer.base = base;
+    c->point.size = TRI_ONE;
+    c->line.width = TRI_ONE;
+            
+    // in OpenGL, writing to the depth buffer is enabled by default.
+    c->rasterizer.procs.depthMask(c, 1);
+    
+    // OpenGL enables dithering by default
+    c->rasterizer.procs.enable(c, GL_DITHER);
+
+    return c;
+}
+
+void ogles_uninit(ogles_context_t* c)
+{
+    ogles_uninit_array(c);
+    ogles_uninit_matrix(c);
+    ogles_uninit_vertex(c);
+    ogles_uninit_light(c);
+    ogles_uninit_texture(c);
+    c->surfaceManager->decStrong(c);
+    c->bufferObjectManager->decStrong(c);
+    ggl_uninit_context(&(c->rasterizer));
+	free(c->rasterizer.base);
+}
+
+void _ogles_error(ogles_context_t* c, GLenum error)
+{
+    if (c->error == GL_NO_ERROR)
+        c->error = error;
+}
+
+static bool stencilop_valid(GLenum op) {
+    switch (op) {
+    case GL_KEEP:
+    case GL_ZERO:
+    case GL_REPLACE:
+    case GL_INCR:
+    case GL_DECR:
+    case GL_INVERT:
+        return true;
+    }
+    return false;
+}
+
+static void enable_disable(ogles_context_t* c, GLenum cap, int enabled)
+{
+    if ((cap >= GL_LIGHT0) && (cap<GL_LIGHT0+OGLES_MAX_LIGHTS)) {
+        c->lighting.lights[cap-GL_LIGHT0].enable = enabled;
+        c->lighting.enabledLights &= ~(1<<(cap-GL_LIGHT0));
+        c->lighting.enabledLights |= (enabled<<(cap-GL_LIGHT0));
+        return;
+    }
+
+    switch (cap) {
+    case GL_POINT_SMOOTH:
+        c->point.smooth = enabled;
+        break;
+    case GL_LINE_SMOOTH:
+        c->line.smooth = enabled;
+        break;
+    case GL_POLYGON_OFFSET_FILL:
+        c->polygonOffset.enable = enabled;
+        break;
+    case GL_CULL_FACE:
+        c->cull.enable = enabled;
+        break;
+    case GL_LIGHTING:
+        c->lighting.enable = enabled;
+        break;
+    case GL_COLOR_MATERIAL:
+        c->lighting.colorMaterial.enable = enabled;
+        break;
+    case GL_NORMALIZE:
+    case GL_RESCALE_NORMAL:
+        c->transforms.rescaleNormals = enabled ? cap : 0;
+        // XXX: invalidate mvit
+        break;
+
+    case GL_CLIP_PLANE0:
+    case GL_CLIP_PLANE1:
+    case GL_CLIP_PLANE2:
+    case GL_CLIP_PLANE3:
+    case GL_CLIP_PLANE4:
+    case GL_CLIP_PLANE5:
+        c->clipPlanes.enable &= ~(1<<(cap-GL_CLIP_PLANE0));
+        c->clipPlanes.enable |= (enabled<<(cap-GL_CLIP_PLANE0));
+        ogles_invalidate_perspective(c);
+        break;
+
+    case GL_FOG:
+    case GL_DEPTH_TEST:
+        ogles_invalidate_perspective(c);
+        // fall-through...
+    case GL_BLEND:
+    case GL_SCISSOR_TEST:
+    case GL_ALPHA_TEST:
+    case GL_COLOR_LOGIC_OP:
+    case GL_DITHER:
+    case GL_STENCIL_TEST:
+    case GL_TEXTURE_2D:
+        // these need to fall through into the rasterizer
+        c->rasterizer.procs.enableDisable(c, cap, enabled);
+        break;
+        
+    case GL_MULTISAMPLE:
+    case GL_SAMPLE_ALPHA_TO_COVERAGE:
+    case GL_SAMPLE_ALPHA_TO_ONE:
+    case GL_SAMPLE_COVERAGE:
+        // not supported in this implementation
+        break;
+
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+using namespace android;
+
+#if 0
+#pragma mark -
+#endif
+
+// These ones are super-easy, we're not supporting those features!
+void glSampleCoverage(GLclampf value, GLboolean invert) {
+}
+void glSampleCoveragex(GLclampx value, GLboolean invert) {
+}
+void glStencilFunc(GLenum func, GLint ref, GLuint mask) {
+    ogles_context_t* c = ogles_context_t::get();
+    if (func < GL_NEVER || func > GL_ALWAYS) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    // from OpenGL|ES 1.0 sepcification:
+    // If there is no stencil buffer, no stencil modification can occur
+    // and it is as if the stencil test always passes.
+}
+
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
+    ogles_context_t* c = ogles_context_t::get();
+    if ((stencilop_valid(fail) &
+         stencilop_valid(zfail) &
+         stencilop_valid(zpass)) == 0) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+void glAlphaFunc(GLenum func, GLclampf ref)
+{
+    glAlphaFuncx(func, gglFloatToFixed(ref));
+}
+
+void glCullFace(GLenum mode)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    switch (mode) {
+    case GL_FRONT:
+    case GL_BACK:
+    case GL_FRONT_AND_BACK:
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+    }
+    c->cull.cullFace = mode;
+}
+
+void glFrontFace(GLenum mode)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    switch (mode) {
+    case GL_CW:
+    case GL_CCW:
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->cull.frontFace = mode;
+}
+
+void glHint(GLenum target, GLenum mode)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    switch (target) {
+    case GL_FOG_HINT:
+    case GL_GENERATE_MIPMAP_HINT:
+    case GL_LINE_SMOOTH_HINT:
+        break;
+    case GL_POINT_SMOOTH_HINT:
+        c->rasterizer.procs.enableDisable(c, 
+                GGL_POINT_SMOOTH_NICE, mode==GL_NICEST);
+        break;
+    case GL_PERSPECTIVE_CORRECTION_HINT:
+        c->perspective = (mode == GL_NICEST) ? 1 : 0;
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+    }
+}
+
+void glEnable(GLenum cap) {
+    ogles_context_t* c = ogles_context_t::get();
+    enable_disable(c, cap, 1);
+}
+void glDisable(GLenum cap) {
+    ogles_context_t* c = ogles_context_t::get();
+    enable_disable(c, cap, 0);
+}
+
+void glFinish()
+{ // nothing to do for our software implementation
+}
+
+void glFlush()
+{ // nothing to do for our software implementation
+}
+
+GLenum glGetError()
+{
+    // From OpenGL|ES 1.0 specification:
+    // If more than one flag has recorded an error, glGetError returns
+    // and clears an arbitrary error flag value. Thus, glGetError should
+    // always be called in a loop, until it returns GL_NO_ERROR,
+    // if all error flags are to be reset.
+
+    ogles_context_t* c = ogles_context_t::get();
+    if (c->error) {
+        const GLenum ret(c->error);
+        c->error = 0;
+        return ret;
+    }
+    
+    if (c->rasterizer.error) {
+        const GLenum ret(c->rasterizer.error);
+        c->rasterizer.error = 0;
+        return ret;
+    }
+
+    return GL_NO_ERROR;
+}
+
+const GLubyte* glGetString(GLenum string)
+{
+    switch (string) {
+    case GL_VENDOR:     return (const GLubyte*)gVendorString;
+    case GL_RENDERER:   return (const GLubyte*)gRendererString;
+    case GL_VERSION:    return (const GLubyte*)gVersionString;
+    case GL_EXTENSIONS: return (const GLubyte*)gExtensionsString;
+    }
+    ogles_context_t* c = ogles_context_t::get();
+    ogles_error(c, GL_INVALID_ENUM);
+    return 0;
+}
+
+void glGetIntegerv(GLenum pname, GLint *params)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    switch (pname) {
+    case GL_ALIASED_POINT_SIZE_RANGE:
+        params[0] = 0;
+        params[1] = GGL_MAX_ALIASED_POINT_SIZE;
+        break;
+    case GL_ALIASED_LINE_WIDTH_RANGE:
+        params[0] = 0;
+        params[1] = GGL_MAX_ALIASED_POINT_SIZE;
+        break;
+    case GL_ALPHA_BITS: {
+        int index = c->rasterizer.state.buffers.color.format;
+        GGLFormat const * formats = gglGetPixelFormatTable();
+        params[0] = formats[index].ah - formats[index].al;
+        break; 
+        }
+    case GL_RED_BITS: {
+        int index = c->rasterizer.state.buffers.color.format;
+        GGLFormat const * formats = gglGetPixelFormatTable();
+        params[0] = formats[index].rh - formats[index].rl;
+        break; 
+        }
+    case GL_GREEN_BITS: {
+        int index = c->rasterizer.state.buffers.color.format;
+        GGLFormat const * formats = gglGetPixelFormatTable();
+        params[0] = formats[index].gh - formats[index].gl;
+        break; 
+        }
+    case GL_BLUE_BITS: {
+        int index = c->rasterizer.state.buffers.color.format;
+        GGLFormat const * formats = gglGetPixelFormatTable();
+        params[0] = formats[index].bh - formats[index].bl;
+        break; 
+        }
+    case GL_COMPRESSED_TEXTURE_FORMATS:
+        params[ 0] = GL_PALETTE4_RGB8_OES;
+        params[ 1] = GL_PALETTE4_RGBA8_OES;
+        params[ 2] = GL_PALETTE4_R5_G6_B5_OES;
+        params[ 3] = GL_PALETTE4_RGBA4_OES;
+        params[ 4] = GL_PALETTE4_RGB5_A1_OES;
+        params[ 5] = GL_PALETTE8_RGB8_OES;
+        params[ 6] = GL_PALETTE8_RGBA8_OES;
+        params[ 7] = GL_PALETTE8_R5_G6_B5_OES;
+        params[ 8] = GL_PALETTE8_RGBA4_OES;
+        params[ 9] = GL_PALETTE8_RGB5_A1_OES;
+        break;
+    case GL_DEPTH_BITS:
+        params[0] = c->rasterizer.state.buffers.depth.format ? 0 : 16;
+        break;
+    case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
+        params[0] = GL_RGB;
+        break;
+    case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
+        params[0] = GL_UNSIGNED_SHORT_5_6_5;
+        break;
+    case GL_MAX_LIGHTS:
+        params[0] = OGLES_MAX_LIGHTS;
+        break;
+    case GL_MAX_CLIP_PLANES:
+        params[0] = OGLES_MAX_CLIP_PLANES;
+        break;
+    case GL_MAX_MODELVIEW_STACK_DEPTH:
+        params[0] = OGLES_MODELVIEW_STACK_DEPTH;
+        break;
+    case GL_MAX_PROJECTION_STACK_DEPTH:
+        params[0] = OGLES_PROJECTION_STACK_DEPTH;
+        break;
+    case GL_MAX_TEXTURE_STACK_DEPTH:
+        params[0] = OGLES_TEXTURE_STACK_DEPTH;
+        break;
+    case GL_MAX_TEXTURE_SIZE:
+        params[0] = GGL_MAX_TEXTURE_SIZE;
+        break;
+    case GL_MAX_TEXTURE_UNITS:
+        params[0] = GGL_TEXTURE_UNIT_COUNT;
+        break;
+    case GL_MAX_VIEWPORT_DIMS:
+        params[0] = GGL_MAX_VIEWPORT_DIMS;
+        params[1] = GGL_MAX_VIEWPORT_DIMS;
+        break;
+    case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+        params[0] = OGLES_NUM_COMPRESSED_TEXTURE_FORMATS;
+        break;
+    case GL_SMOOTH_LINE_WIDTH_RANGE:
+        params[0] = 0;
+        params[1] = GGL_MAX_SMOOTH_LINE_WIDTH;
+        break;
+    case GL_SMOOTH_POINT_SIZE_RANGE:
+        params[0] = 0;
+        params[1] = GGL_MAX_SMOOTH_POINT_SIZE;
+        break;
+    case GL_STENCIL_BITS:
+        params[0] = 0;
+        break;
+    case GL_SUBPIXEL_BITS:
+        params[0] = GGL_SUBPIXEL_BITS;
+        break;
+
+    case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES:
+        memcpy( params,
+                c->transforms.modelview.top().elements(),
+                16*sizeof(GLint));
+        break;
+    case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES:
+        memcpy( params,
+                c->transforms.projection.top().elements(),
+                16*sizeof(GLint));
+        break;
+    case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES:
+        memcpy( params,
+                c->transforms.texture[c->textures.active].top().elements(),
+                16*sizeof(GLint));
+        break;
+
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        break;
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+void glPointSize(GLfloat size)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (size <= 0) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->point.size = TRI_FROM_FIXED(gglFloatToFixed(size));
+}
+
+void glPointSizex(GLfixed size)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (size <= 0) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->point.size = TRI_FROM_FIXED(size);
+}
+
+// ----------------------------------------------------------------------------
+
+void glLineWidth(GLfloat width)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (width <= 0) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->line.width = TRI_FROM_FIXED(gglFloatToFixed(width));
+}
+
+void glLineWidthx(GLfixed width)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (width <= 0) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->line.width = TRI_FROM_FIXED(width);
+}
+
+// ----------------------------------------------------------------------------
+
+void glColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) {
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.colorMask(c, r, g, b, a);
+}
+
+void glDepthMask(GLboolean flag) {
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.depthMask(c, flag);
+}
+
+void glStencilMask(GLuint mask) {
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.stencilMask(c, mask);
+}
+
+void glDepthFunc(GLenum func) {
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.depthFunc(c, func);
+}
+
+void glLogicOp(GLenum opcode) {
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.logicOp(c, opcode);
+}
+
+void glAlphaFuncx(GLenum func, GLclampx ref) {
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.alphaFuncx(c, func, ref);
+}
+
+void glBlendFunc(GLenum sfactor, GLenum dfactor) {
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.blendFunc(c, sfactor, dfactor);
+}
+
+void glClear(GLbitfield mask) {
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.clear(c, mask);
+}
+
+void glClearColorx(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) {
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.clearColorx(c, red, green, blue, alpha);
+}
+
+void glClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.clearColorx(c,
+                    gglFloatToFixed(r),
+                    gglFloatToFixed(g),
+                    gglFloatToFixed(b),
+                    gglFloatToFixed(a));
+}
+
+void glClearDepthx(GLclampx depth) {
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.clearDepthx(c, depth);
+}
+
+void glClearDepthf(GLclampf depth)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.clearDepthx(c, gglFloatToFixed(depth));
+}
+
+void glClearStencil(GLint s) {
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.clearStencil(c, s);
+}
diff --git a/opengl/libagl/state.h b/opengl/libagl/state.h
new file mode 100644
index 0000000..55a5ccb
--- /dev/null
+++ b/opengl/libagl/state.h
@@ -0,0 +1,54 @@
+/* libs/opengles/state.h
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_OPENGLES_STATE_H
+#define ANDROID_OPENGLES_STATE_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+#include <stdio.h>
+
+namespace android {
+
+ogles_context_t *ogles_init(size_t extra);
+void ogles_uninit(ogles_context_t* c);
+void _ogles_error(ogles_context_t* c, GLenum error);
+
+#ifndef TRACE_GL_ERRORS
+#define TRACE_GL_ERRORS 0
+#endif
+
+#if TRACE_GL_ERRORS
+#define ogles_error(c, error) \
+do { \
+  printf("ogles_error at file %s line %d\n", __FILE__, __LINE__); \
+  _ogles_error(c, error); \
+} while (0)
+#else /* !TRACE_GL_ERRORS */
+#define ogles_error(c, error) _ogles_error((c), (error))
+#endif
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_STATE_H
+
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
new file mode 100644
index 0000000..b6f534b
--- /dev/null
+++ b/opengl/libagl/texture.cpp
@@ -0,0 +1,1421 @@
+/* libs/opengles/texture.cpp
+**
+** Copyright 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 <stdlib.h>
+#include "context.h"
+#include "fp.h"
+#include "state.h"
+#include "texture.h"
+#include "TextureObjectManager.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static void bindTextureTmu(
+    ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex);
+
+static __attribute__((noinline))
+void generateMipmap(ogles_context_t* c, GLint level);
+
+// ----------------------------------------------------------------------------
+
+#if 0
+#pragma mark -
+#pragma mark Init
+#endif
+
+void ogles_init_texture(ogles_context_t* c)
+{
+    c->textures.packAlignment   = 4;
+    c->textures.unpackAlignment = 4;
+
+    // each context has a default named (0) texture (not shared)
+    c->textures.defaultTexture = new EGLTextureObject();
+    c->textures.defaultTexture->incStrong(c);
+    
+    // bind the default texture to each texture unit
+    for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+        bindTextureTmu(c, i, 0, c->textures.defaultTexture);
+        memset(c->current.texture[i].v, 0, sizeof(vec4_t));
+        c->current.texture[i].Q = 0x10000;
+    }
+}
+
+void ogles_uninit_texture(ogles_context_t* c)
+{
+    if (c->textures.ggl)
+        gglUninit(c->textures.ggl);
+    c->textures.defaultTexture->decStrong(c);
+    for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+        if (c->textures.tmu[i].texture)
+            c->textures.tmu[i].texture->decStrong(c);
+    }
+}
+
+static __attribute__((noinline))
+void validate_tmu(ogles_context_t* c, int i)
+{
+    texture_unit_t& u(c->textures.tmu[i]);
+    if (u.dirty) {
+        u.dirty = 0;
+        c->rasterizer.procs.activeTexture(c, i);
+        c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
+        c->rasterizer.procs.texGeni(c, GGL_S,
+                GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
+        c->rasterizer.procs.texGeni(c, GGL_T,
+                GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
+        c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+                GGL_TEXTURE_WRAP_S, u.texture->wraps);
+        c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+                GGL_TEXTURE_WRAP_T, u.texture->wrapt);
+        c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+                GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
+        c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+                GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
+
+        // disable this texture unit if it's not complete
+        if (!u.texture->isComplete()) {
+            c->rasterizer.procs.disable(c, GGL_TEXTURE_2D);
+        }
+    }
+}
+
+void ogles_validate_texture_impl(ogles_context_t* c)
+{
+    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+        if (c->rasterizer.state.texture[i].enable)
+            validate_tmu(c, i);
+    }
+    c->rasterizer.procs.activeTexture(c, c->textures.active);
+}
+
+static
+void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) {
+    c->textures.tmu[tmu].dirty = flags;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Format conversion
+#endif
+
+static uint32_t gl2format_table[6][4] = {
+    // BYTE, 565, 4444, 5551
+    { GGL_PIXEL_FORMAT_A_8,
+      0, 0, 0 },                        // GL_ALPHA
+    { GGL_PIXEL_FORMAT_RGB_888,
+      GGL_PIXEL_FORMAT_RGB_565,
+      0, 0 },                           // GL_RGB
+    { GGL_PIXEL_FORMAT_RGBA_8888,
+      0,
+      GGL_PIXEL_FORMAT_RGBA_4444,
+      GGL_PIXEL_FORMAT_RGBA_5551 },     // GL_RGBA
+    { GGL_PIXEL_FORMAT_L_8,
+      0, 0, 0 },                        // GL_LUMINANCE
+    { GGL_PIXEL_FORMAT_LA_88,
+      0, 0, 0 },                        // GL_LUMINANCE_ALPHA
+};
+
+static int32_t convertGLPixelFormat(GLint format, GLenum type)
+{
+    int32_t fi = -1;
+    int32_t ti = -1;
+    switch (format) {
+    case GL_ALPHA:              fi = 0;     break;
+    case GL_RGB:                fi = 1;     break;
+    case GL_RGBA:               fi = 2;     break;
+    case GL_LUMINANCE:          fi = 3;     break;
+    case GL_LUMINANCE_ALPHA:    fi = 4;     break;
+    }
+    switch (type) {
+    case GL_UNSIGNED_BYTE:          ti = 0; break;
+    case GL_UNSIGNED_SHORT_5_6_5:   ti = 1; break;
+    case GL_UNSIGNED_SHORT_4_4_4_4: ti = 2; break;
+    case GL_UNSIGNED_SHORT_5_5_5_1: ti = 3; break;
+    }
+    if (fi==-1 || ti==-1)
+        return 0;
+    return gl2format_table[fi][ti];
+}
+
+// ----------------------------------------------------------------------------
+
+static GLenum validFormatType(ogles_context_t* c, GLenum format, GLenum type)
+{
+    GLenum error = 0;
+    if (format<GL_ALPHA || format>GL_LUMINANCE_ALPHA) {
+        error = GL_INVALID_ENUM;
+    }
+    if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT_4_4_4_4 &&
+        type != GL_UNSIGNED_SHORT_5_5_5_1 && type != GL_UNSIGNED_SHORT_5_6_5) {
+        error = GL_INVALID_ENUM;
+    }
+    if (type == GL_UNSIGNED_SHORT_5_6_5 && format != GL_RGB) {
+        error = GL_INVALID_OPERATION;
+    }
+    if ((type == GL_UNSIGNED_SHORT_4_4_4_4 ||
+         type == GL_UNSIGNED_SHORT_5_5_5_1)  && format != GL_RGBA) {
+        error = GL_INVALID_OPERATION;
+    }
+    if (error) {
+        ogles_error(c, error);
+    }
+    return error;
+}
+
+// ----------------------------------------------------------------------------
+
+GGLContext* getRasterizer(ogles_context_t* c)
+{
+    GGLContext* ggl = c->textures.ggl;
+    if (ggl_unlikely(!ggl)) {
+        // this is quite heavy the first time...
+        gglInit(&ggl);
+        if (!ggl) {
+            return 0;
+        }
+        GGLfixed colors[4] = { 0, 0, 0, 0x10000 };
+        c->textures.ggl = ggl;
+        ggl->activeTexture(ggl, 0);
+        ggl->enable(ggl, GGL_TEXTURE_2D);
+        ggl->texEnvi(ggl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
+        ggl->disable(ggl, GGL_DITHER);
+        ggl->shadeModel(ggl, GGL_FLAT);
+        ggl->color4xv(ggl, colors);
+    }
+    return ggl;
+}
+
+static __attribute__((noinline))
+int copyPixels(
+        ogles_context_t* c,
+        const GGLSurface& dst,
+        GLint xoffset, GLint yoffset,
+        const GGLSurface& src,
+        GLint x, GLint y, GLsizei w, GLsizei h)
+{
+    if ((dst.format == src.format) &&
+        (dst.stride == src.stride) &&
+        (dst.width == src.width) &&
+        (dst.height == src.height) &&
+        (dst.stride > 0) &&
+        ((x|y) == 0) &&
+        ((xoffset|yoffset) == 0))
+    {
+        // this is a common case...
+        const GGLFormat& pixelFormat(c->rasterizer.formats[src.format]);
+        const size_t size = src.height * src.stride * pixelFormat.size;
+        memcpy(dst.data, src.data, size);
+        return 0;
+    }
+
+    // use pixel-flinger to handle all the conversions
+    GGLContext* ggl = getRasterizer(c);
+    if (!ggl) {
+        // the only reason this would fail is because we ran out of memory
+        return GL_OUT_OF_MEMORY;
+    }
+
+    ggl->colorBuffer(ggl, &dst);
+    ggl->bindTexture(ggl, &src);
+    ggl->texCoord2i(ggl, x-xoffset, y-yoffset);
+    ggl->recti(ggl, xoffset, yoffset, xoffset+w, yoffset+h);
+    return 0;
+}
+
+// ----------------------------------------------------------------------------
+
+static __attribute__((noinline))
+sp<EGLTextureObject> getAndBindActiveTextureObject(ogles_context_t* c)
+{
+    sp<EGLTextureObject> tex;
+    const int active = c->textures.active;
+    const GLuint name = c->textures.tmu[active].name;
+
+    // free the reference to the previously bound object
+    texture_unit_t& u(c->textures.tmu[active]);
+    if (u.texture)
+        u.texture->decStrong(c);
+
+    if (name == 0) {
+        // 0 is our local texture object, not shared with anyone. 
+        // But it affects all bound TMUs immediately.
+        // (we need to invalidate all units bound to this texture object)
+        tex = c->textures.defaultTexture;
+        for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+            if (c->textures.tmu[i].texture == tex.get())
+                invalidate_texture(c, i);
+        }
+    } else {
+        // get a new texture object for that name
+        tex = c->surfaceManager->replaceTexture(name);
+    }
+
+    // bind this texture to the current active texture unit
+    // and add a reference to this texture object
+    u.texture = tex.get();
+    u.texture->incStrong(c);
+    u.name = name;
+    invalidate_texture(c, active);    
+    return tex;
+}
+
+void bindTextureTmu(
+    ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex)
+{
+    if (tex.get() == c->textures.tmu[tmu].texture)
+        return;
+    
+    // free the reference to the previously bound object
+    texture_unit_t& u(c->textures.tmu[tmu]);
+    if (u.texture)
+        u.texture->decStrong(c);
+
+    // bind this texture to the current active texture unit
+    // and add a reference to this texture object
+    u.texture = tex.get();
+    u.texture->incStrong(c);
+    u.name = texture;
+    invalidate_texture(c, tmu);
+}
+
+int createTextureSurface(ogles_context_t* c,
+        GGLSurface** outSurface, int32_t* outSize, GLint level,
+        GLenum format, GLenum type, GLsizei width, GLsizei height,
+        GLenum compressedFormat = 0)
+{
+    // find out which texture is bound to the current unit
+    const int active = c->textures.active;
+    const GLuint name = c->textures.tmu[active].name;
+
+    // convert the pixelformat to one we can handle
+    const int32_t formatIdx = convertGLPixelFormat(format, type);
+    if (formatIdx == 0) { // we don't know what to do with this
+        return GL_INVALID_OPERATION;
+    }
+    
+    // figure out the size we need as well as the stride
+    const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
+    const int32_t align = c->textures.unpackAlignment-1;
+    const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
+    const size_t size = bpr * height;
+    const int32_t stride = bpr / pixelFormat.size;
+
+    if (level > 0) {
+        const int active = c->textures.active;
+        EGLTextureObject* tex = c->textures.tmu[active].texture;
+        status_t err = tex->reallocate(level,
+                width, height, stride, formatIdx, compressedFormat, bpr);
+        if (err != NO_ERROR)
+            return GL_OUT_OF_MEMORY;
+        GGLSurface& surface = tex->editMip(level);
+        *outSurface = &surface;
+        *outSize = size;
+        return 0;
+    }
+
+    sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
+    status_t err = tex->reallocate(level,
+            width, height, stride, formatIdx, compressedFormat, bpr);
+    if (err != NO_ERROR)
+        return GL_OUT_OF_MEMORY;
+
+    tex->internalformat = format;
+    *outSurface = &tex->surface;
+    *outSize = size;
+    return 0;
+}
+
+static void decodePalette4(const GLvoid *data, int level, int width, int height,
+                           void *surface, int stride, int format)
+
+{
+    int indexBits = 8;
+    int entrySize = 0;
+    switch (format) {
+    case GL_PALETTE4_RGB8_OES:
+        indexBits = 4;
+        /* FALLTHROUGH */
+    case GL_PALETTE8_RGB8_OES:
+        entrySize = 3;
+        break;
+
+    case GL_PALETTE4_RGBA8_OES:
+        indexBits = 4;
+        /* FALLTHROUGH */
+    case GL_PALETTE8_RGBA8_OES:
+        entrySize = 4;
+        break;
+
+    case GL_PALETTE4_R5_G6_B5_OES:
+    case GL_PALETTE4_RGBA4_OES:
+    case GL_PALETTE4_RGB5_A1_OES:
+        indexBits = 4;
+        /* FALLTHROUGH */
+    case GL_PALETTE8_R5_G6_B5_OES:
+    case GL_PALETTE8_RGBA4_OES:
+    case GL_PALETTE8_RGB5_A1_OES:
+        entrySize = 2;
+        break;
+    }
+
+    const int paletteSize = (1 << indexBits) * entrySize;
+    uint8_t const* pixels = (uint8_t *)data + paletteSize;
+    for (int i=0 ; i<level ; i++) {
+        int w = (width  >> i) ? : 1;
+        int h = (height >> i) ? : 1;
+        pixels += h * ((w * indexBits) / 8);
+    }
+    width  = (width  >> level) ? : 1;
+    height = (height >> level) ? : 1;
+
+    if (entrySize == 2) {
+        uint8_t const* const palette = (uint8_t*)data;
+        for (int y=0 ; y<height ; y++) {
+            uint8_t* p = (uint8_t*)surface + y*stride*2;
+            if (indexBits == 8) {
+                for (int x=0 ; x<width ; x++) {
+                    int index = 2 * (*pixels++);
+                    *p++ = palette[index + 0];
+                    *p++ = palette[index + 1];
+                }
+            } else {
+                for (int x=0 ; x<width ; x+=2) {
+                    int v = *pixels++;
+                    int index = 2 * (v >> 4);
+                    *p++ = palette[index + 0];
+                    *p++ = palette[index + 1];
+                    if (x+1 < width) {
+                        index = 2 * (v & 0xF);
+                        *p++ = palette[index + 0];
+                        *p++ = palette[index + 1];
+                    }
+                }
+            }
+        }
+    } else if (entrySize == 3) {
+        uint8_t const* const palette = (uint8_t*)data;
+        for (int y=0 ; y<height ; y++) {
+            uint8_t* p = (uint8_t*)surface + y*stride*3;
+            if (indexBits == 8) {
+                for (int x=0 ; x<width ; x++) {
+                    int index = 3 * (*pixels++);
+                    *p++ = palette[index + 0];
+                    *p++ = palette[index + 1];
+                    *p++ = palette[index + 2];
+                }
+            } else {
+                for (int x=0 ; x<width ; x+=2) {
+                    int v = *pixels++;
+                    int index = 3 * (v >> 4);
+                    *p++ = palette[index + 0];
+                    *p++ = palette[index + 1];
+                    *p++ = palette[index + 2];
+                    if (x+1 < width) {
+                        index = 3 * (v & 0xF);
+                        *p++ = palette[index + 0];
+                        *p++ = palette[index + 1];
+                        *p++ = palette[index + 2];
+                    }
+                }
+            }
+        }
+    } else if (entrySize == 4) {
+        uint8_t const* const palette = (uint8_t*)data;
+        for (int y=0 ; y<height ; y++) {
+            uint8_t* p = (uint8_t*)surface + y*stride*4;
+            if (indexBits == 8) {
+                for (int x=0 ; x<width ; x++) {
+                    int index = 4 * (*pixels++);
+                    *p++ = palette[index + 0];
+                    *p++ = palette[index + 1];
+                    *p++ = palette[index + 2];
+                    *p++ = palette[index + 3];
+                }
+            } else {
+                for (int x=0 ; x<width ; x+=2) {
+                    int v = *pixels++;
+                    int index = 4 * (v >> 4);
+                    *p++ = palette[index + 0];
+                    *p++ = palette[index + 1];
+                    *p++ = palette[index + 2];
+                    *p++ = palette[index + 3];
+                    if (x+1 < width) {
+                        index = 4 * (v & 0xF);
+                        *p++ = palette[index + 0];
+                        *p++ = palette[index + 1];
+                        *p++ = palette[index + 2];
+                        *p++ = palette[index + 3];
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+
+static __attribute__((noinline))
+void set_depth_and_fog(ogles_context_t* c, GLint z)
+{
+    const uint32_t enables = c->rasterizer.state.enables;
+    // we need to compute Zw
+    int32_t iterators[3];
+    iterators[1] = iterators[2] = 0;
+    GGLfixed Zw;
+    GGLfixed n = gglFloatToFixed(c->transforms.vpt.zNear);
+    GGLfixed f = gglFloatToFixed(c->transforms.vpt.zFar);
+    if (z<=0)       Zw = n;
+    else if (z>=1)  Zw = f;
+    else            Zw = gglMulAddx(z, (f-n), n);
+    if (enables & GGL_ENABLE_FOG) {
+        // set up fog if needed...
+        iterators[0] = c->fog.fog(c, Zw);
+        c->rasterizer.procs.fogGrad3xv(c, iterators);
+    }
+    if (enables & GGL_ENABLE_DEPTH_TEST) {
+        // set up z-test if needed...
+        int32_t z = (Zw & ~(Zw>>31));
+        if (z >= 0x10000)
+            z = 0xFFFF;
+        iterators[0] = (z << 16) | z;
+        c->rasterizer.procs.zGrad3xv(c, iterators);
+    }
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Generate mimaps
+#endif
+
+extern status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex);
+
+void generateMipmap(ogles_context_t* c, GLint level)
+{
+    if (level == 0) {
+        const int active = c->textures.active;
+        EGLTextureObject* tex = c->textures.tmu[active].texture;
+        if (tex->generate_mipmap) {
+            if (buildAPyramid(c, tex) != NO_ERROR) {
+                ogles_error(c, GL_OUT_OF_MEMORY);
+                return;
+            }
+        }
+    }
+}
+
+
+static void texParameterx(
+        GLenum target, GLenum pname, GLfixed param, ogles_context_t* c)
+{
+    if (target != GL_TEXTURE_2D) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    
+    EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;    
+    switch (pname) {
+    case GL_TEXTURE_WRAP_S:
+        if ((param == GL_REPEAT) ||
+            (param == GL_CLAMP_TO_EDGE)) {
+            textureObject->wraps = param;
+        } else {
+            goto invalid_enum;
+        }
+        break;
+    case GL_TEXTURE_WRAP_T:
+        if ((param == GL_REPEAT) ||
+            (param == GL_CLAMP_TO_EDGE)) {
+            textureObject->wrapt = param;
+        } else {
+            goto invalid_enum;
+        }
+        break;
+    case GL_TEXTURE_MIN_FILTER:
+        if ((param == GL_NEAREST) ||
+            (param == GL_LINEAR) ||
+            (param == GL_NEAREST_MIPMAP_NEAREST) ||
+            (param == GL_LINEAR_MIPMAP_NEAREST) ||
+            (param == GL_NEAREST_MIPMAP_LINEAR) ||
+            (param == GL_LINEAR_MIPMAP_LINEAR)) {
+            textureObject->min_filter = param;
+        } else {
+            goto invalid_enum;
+        }
+        break;
+    case GL_TEXTURE_MAG_FILTER:
+        if ((param == GL_NEAREST) ||
+            (param == GL_LINEAR)) {
+            textureObject->mag_filter = param;
+        } else {
+            goto invalid_enum;
+        }
+        break;
+    case GL_GENERATE_MIPMAP:
+        textureObject->generate_mipmap = param;
+        break;
+    default:
+invalid_enum:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    invalidate_texture(c, c->textures.active);
+}
+
+
+static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
+        ogles_context_t* c)
+{
+    // quickly reject empty rects
+    if ((w|h) <= 0)
+        return;                
+
+    const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+    y = gglIntToFixed(cbSurface.height) - (y + h);
+    w >>= FIXED_BITS;
+    h >>= FIXED_BITS;
+
+    // set up all texture units
+    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+        if (!c->rasterizer.state.texture[i].enable)
+            continue;
+
+        int32_t texcoords[8];
+        texture_unit_t& u(c->textures.tmu[i]);
+
+        // validate this tmu (bind, wrap, filter)
+        validate_tmu(c, i);
+        // we CLAMP here, which works with premultiplied (s,t)
+        c->rasterizer.procs.texParameteri(c,
+                GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP);
+        c->rasterizer.procs.texParameteri(c,
+                GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
+        u.dirty = 0xFF; // XXX: should be more subtle
+
+        EGLTextureObject* textureObject = u.texture;  
+        const GLint Ucr = textureObject->crop_rect[0] << 16;
+        const GLint Vcr = textureObject->crop_rect[1] << 16;
+        const GLint Wcr = textureObject->crop_rect[2] << 16;
+        const GLint Hcr = textureObject->crop_rect[3] << 16;
+
+        // computes texture coordinates (pre-multiplied)
+        int32_t dsdx = Wcr / w;   // dsdx =  ((Wcr/w)/Wt)*Wt
+        int32_t dtdy =-Hcr / h;   // dtdy = -((Hcr/h)/Ht)*Ht
+        int32_t s0   = Ucr       - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx
+        int32_t t0   = (Vcr+Hcr) - gglMulx(dtdy, y); // t0 = (Vcr+Hcr) - y*dtdy
+        texcoords[0] = s0;
+        texcoords[1] = dsdx;
+        texcoords[2] = 0;
+        texcoords[3] = t0;
+        texcoords[4] = 0;
+        texcoords[5] = dtdy;
+        texcoords[6] = 0;
+        texcoords[7] = 0;
+        c->rasterizer.procs.texCoordGradScale8xv(c, i, texcoords);
+    }
+
+    const uint32_t enables = c->rasterizer.state.enables;
+    if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
+        set_depth_and_fog(c, z);
+
+    c->rasterizer.procs.activeTexture(c, c->textures.active);
+    c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
+    c->rasterizer.procs.disable(c, GGL_W_LERP);
+    c->rasterizer.procs.disable(c, GGL_AA);
+    c->rasterizer.procs.shadeModel(c, GL_FLAT);
+    c->rasterizer.procs.recti(c, 
+            gglFixedToIntRound(x),
+            gglFixedToIntRound(y),
+            gglFixedToIntRound(x)+w,
+            gglFixedToIntRound(y)+h);
+}
+
+static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)
+{
+    // All coordinates are integer, so if we have only one
+    // texture unit active and no scaling is required
+    // THEN, we can use our special 1:1 mapping
+    // which is a lot faster.
+
+    if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
+        const int tmu = 0;
+        texture_unit_t& u(c->textures.tmu[tmu]);
+        EGLTextureObject* textureObject = u.texture;  
+        const GLint Wcr = textureObject->crop_rect[2];
+        const GLint Hcr = textureObject->crop_rect[3];
+
+        if ((w == Wcr) && (h == -Hcr)) {
+            if ((w|h) <= 0) return; // quickly reject empty rects
+
+            if (u.dirty) {
+                c->rasterizer.procs.activeTexture(c, tmu);
+                c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
+                c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+                        GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
+                c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+                        GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
+            }
+            c->rasterizer.procs.texGeni(c, GGL_S,
+                    GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
+            c->rasterizer.procs.texGeni(c, GGL_T,
+                    GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
+            u.dirty = 0xFF; // XXX: should be more subtle
+            c->rasterizer.procs.activeTexture(c, c->textures.active);
+            
+            const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+            y = cbSurface.height - (y + h);
+            const GLint Ucr = textureObject->crop_rect[0];
+            const GLint Vcr = textureObject->crop_rect[1];
+            const GLint s0  = Ucr - x;
+            const GLint t0  = (Vcr + Hcr) - y;
+            
+            const GLuint tw = textureObject->surface.width;
+            const GLuint th = textureObject->surface.height;
+            if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) {
+                // The GL spec is unclear about what should happen
+                // in this case, so we just use the slow case, which
+                // at least won't crash
+                goto slow_case;
+            } 
+
+            c->rasterizer.procs.texCoord2i(c, s0, t0);
+            const uint32_t enables = c->rasterizer.state.enables;
+            if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
+                set_depth_and_fog(c, z);
+
+            c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
+            c->rasterizer.procs.disable(c, GGL_W_LERP);
+            c->rasterizer.procs.disable(c, GGL_AA);
+            c->rasterizer.procs.shadeModel(c, GL_FLAT);
+            c->rasterizer.procs.recti(c, x, y, x+w, y+h);
+            return;
+        }
+    }
+
+slow_case:
+    drawTexxOES(
+            gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z),
+            gglIntToFixed(w), gglIntToFixed(h),
+            c);
+}
+
+
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+
+#if 0
+#pragma mark -
+#pragma mark Texture API
+#endif
+
+void glActiveTexture(GLenum texture)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (uint32_t(texture-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    c->textures.active = texture - GL_TEXTURE0;
+    c->rasterizer.procs.activeTexture(c, c->textures.active);
+}
+
+void glBindTexture(GLenum target, GLuint texture)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (target != GL_TEXTURE_2D) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+
+    // Bind or create a texture
+    sp<EGLTextureObject> tex;    
+    if (texture == 0) {
+        // 0 is our local texture object
+        tex = c->textures.defaultTexture;
+    } else {
+        tex = c->surfaceManager->texture(texture);
+        if (ggl_unlikely(tex == 0)) {
+            tex = c->surfaceManager->createTexture(texture);
+            if (tex == 0) {
+                ogles_error(c, GL_OUT_OF_MEMORY);
+                return;
+            }
+        }
+    }
+    bindTextureTmu(c, c->textures.active, texture, tex);
+}
+
+void glGenTextures(GLsizei n, GLuint *textures)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (n<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    // generate unique (shared) texture names
+    c->surfaceManager->getToken(n, textures);
+}
+
+void glDeleteTextures(GLsizei n, const GLuint *textures)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (n<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+
+    // If deleting a bound texture, bind this unit to 0
+    for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
+        if (c->textures.tmu[t].name == 0)
+            continue;
+        for (int i=0 ; i<n ; i++) {
+            if (textures[i] && (textures[i] == c->textures.tmu[t].name)) {
+                // bind this tmu to texture 0
+                sp<EGLTextureObject> tex(c->textures.defaultTexture);
+                bindTextureTmu(c, t, 0, tex);
+            }
+        }
+    }
+    c->surfaceManager->deleteTextures(n, textures);
+    c->surfaceManager->recycleTokens(n, textures);
+}
+
+void glMultiTexCoord4f(
+        GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    const int tmu = target-GL_TEXTURE0;
+    c->current.texture[tmu].S = gglFloatToFixed(s);
+    c->current.texture[tmu].T = gglFloatToFixed(t);
+    c->current.texture[tmu].R = gglFloatToFixed(r);
+    c->current.texture[tmu].Q = gglFloatToFixed(q);
+}
+
+void glMultiTexCoord4x(
+        GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    const int tmu = target-GL_TEXTURE0;
+    c->current.texture[tmu].S = s;
+    c->current.texture[tmu].T = t;
+    c->current.texture[tmu].R = r;
+    c->current.texture[tmu].Q = q;
+}
+
+void glPixelStorei(GLenum pname, GLint param)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }    
+    if ((param<=0 || param>8) || (param & (param-1))) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    if (pname == GL_PACK_ALIGNMENT)
+        c->textures.packAlignment = param;
+    if (pname == GL_UNPACK_ALIGNMENT)
+        c->textures.unpackAlignment = param;
+}
+
+void glTexEnvf(GLenum target, GLenum pname, GLfloat param)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.texEnvi(c, target, pname, GLint(param));
+}
+
+void glTexEnvfv(
+        GLenum target, GLenum pname, const GLfloat *params)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (pname == GL_TEXTURE_ENV_MODE) {
+        c->rasterizer.procs.texEnvi(c, target, pname, GLint(*params));
+        return;
+    }
+    if (pname == GL_TEXTURE_ENV_COLOR) {
+        GGLfixed fixed[4];
+        for (int i=0 ; i<4 ; i++)
+            fixed[i] = gglFloatToFixed(params[i]);
+        c->rasterizer.procs.texEnvxv(c, target, pname, fixed);
+        return;
+    }
+    ogles_error(c, GL_INVALID_ENUM);
+}
+
+void glTexEnvx(GLenum target, GLenum pname, GLfixed param)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.texEnvi(c, target, pname, param);
+}
+
+void glTexEnvxv(
+        GLenum target, GLenum pname, const GLfixed *params)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->rasterizer.procs.texEnvxv(c, target, pname, params);
+}
+
+void glTexParameteriv(
+        GLenum target, GLenum pname, const GLint* params)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (target != GGL_TEXTURE_2D) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+
+    EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
+    switch (pname) {
+    case GL_TEXTURE_CROP_RECT_OES:
+        memcpy(textureObject->crop_rect, params, 4*sizeof(GLint));
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+}
+
+void glTexParameterf(
+        GLenum target, GLenum pname, GLfloat param)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    texParameterx(target, pname, GLfixed(param), c);
+}
+
+void glTexParameterx(
+        GLenum target, GLenum pname, GLfixed param)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    texParameterx(target, pname, param, c);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void glCompressedTexImage2D(
+        GLenum target, GLint level, GLenum internalformat,
+        GLsizei width, GLsizei height, GLint border,
+        GLsizei imageSize, const GLvoid *data)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (target != GL_TEXTURE_2D) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if ((internalformat < GL_PALETTE4_RGB8_OES ||
+         internalformat > GL_PALETTE8_RGB5_A1_OES)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if (width<0 || height<0 || border!=0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+
+    // "uncompress" the texture since pixelflinger doesn't support
+    // any compressed texture format natively. 
+    GLenum format;
+    GLenum type;
+    switch (internalformat) {
+    case GL_PALETTE8_RGB8_OES:
+    case GL_PALETTE4_RGB8_OES:
+        format      = GL_RGB;
+        type        = GL_UNSIGNED_BYTE;
+        break;
+    case GL_PALETTE8_RGBA8_OES:
+    case GL_PALETTE4_RGBA8_OES:
+        format      = GL_RGBA;
+        type        = GL_UNSIGNED_BYTE;
+        break;
+    case GL_PALETTE8_R5_G6_B5_OES:
+    case GL_PALETTE4_R5_G6_B5_OES:
+        format      = GL_RGB;
+        type        = GL_UNSIGNED_SHORT_5_6_5;
+        break;
+    case GL_PALETTE8_RGBA4_OES:
+    case GL_PALETTE4_RGBA4_OES:
+        format      = GL_RGBA;
+        type        = GL_UNSIGNED_SHORT_4_4_4_4;
+        break;
+    case GL_PALETTE8_RGB5_A1_OES:
+    case GL_PALETTE4_RGB5_A1_OES:
+        format      = GL_RGBA;
+        type        = GL_UNSIGNED_SHORT_5_5_5_1;
+        break;
+    default:
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+
+    if (!data || !width || !height) {
+        // unclear if this is an error or not...
+        return;
+    }
+
+    int32_t size;
+    GGLSurface* surface;
+    // all mipmap levels are specified at once.
+    const int numLevels = level<0 ? -level : 1;
+    for (int i=0 ; i<numLevels ; i++) {
+        int lod_w = (width  >> i) ? : 1;
+        int lod_h = (height >> i) ? : 1;
+        int error = createTextureSurface(c, &surface, &size,
+                i, format, type, lod_w, lod_h);
+        if (error) {
+            ogles_error(c, error);
+            return;
+        }
+        decodePalette4(data, i, width, height,
+                surface->data, surface->stride, internalformat);
+    }
+}
+
+
+void glTexImage2D(
+        GLenum target, GLint level, GLint internalformat,
+        GLsizei width, GLsizei height, GLint border,
+        GLenum format, GLenum type, const GLvoid *pixels)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (target != GL_TEXTURE_2D && target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if (width<0 || height<0 || border!=0 || level < 0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    if (format != internalformat) {
+        ogles_error(c, GL_INVALID_OPERATION);
+        return;
+    }
+    if (validFormatType(c, format, type)) {
+        return;
+    }
+
+    int32_t size = 0;
+    GGLSurface* surface = 0;
+    if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
+        int error = createTextureSurface(c, &surface, &size,
+                level, format, type, width, height);
+        if (error) {
+            ogles_error(c, error);
+            return;
+        }
+    } else if (pixels == 0 || level != 0) {
+        // pixel can't be null for direct texture
+        ogles_error(c, GL_INVALID_OPERATION);
+        return;
+    }
+
+    if (pixels) {
+        const int32_t formatIdx = convertGLPixelFormat(format, type);
+        const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
+        const int32_t align = c->textures.unpackAlignment-1;
+        const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
+        const size_t size = bpr * height;
+        const int32_t stride = bpr / pixelFormat.size;
+
+        GGLSurface userSurface;
+        userSurface.version = sizeof(userSurface);
+        userSurface.width  = width;
+        userSurface.height = height;
+        userSurface.stride = stride;
+        userSurface.format = formatIdx;
+        userSurface.compressedFormat = 0;
+        userSurface.data = (GLubyte*)pixels;
+
+        if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
+            int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height); 
+            if (err) {
+                ogles_error(c, err);
+                return;
+            }
+            generateMipmap(c, level);
+        } else {
+            // bind it to the texture unit
+            sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
+            tex->setSurface(&userSurface);
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+void glCompressedTexSubImage2D(
+        GLenum target, GLint level, GLint xoffset,
+        GLint yoffset, GLsizei width, GLsizei height,
+        GLenum format, GLsizei imageSize,
+        const GLvoid *data)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    ogles_error(c, GL_INVALID_ENUM);
+}
+
+void glTexSubImage2D(
+        GLenum target, GLint level, GLint xoffset,
+        GLint yoffset, GLsizei width, GLsizei height,
+        GLenum format, GLenum type, const GLvoid *pixels)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (target != GL_TEXTURE_2D) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    if (validFormatType(c, format, type)) {
+        return;
+    }
+
+    // find out which texture is bound to the current unit
+    const int active = c->textures.active;
+    EGLTextureObject* tex = c->textures.tmu[active].texture;
+    const GGLSurface& surface(tex->mip(level));
+
+    if (!tex->internalformat || tex->direct) {
+        ogles_error(c, GL_INVALID_OPERATION);
+        return;
+    }
+    if ((xoffset + width  > GLsizei(surface.width)) ||
+        (yoffset + height > GLsizei(surface.height))) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    if (!width || !height) {
+        return; // okay, but no-op.
+    }
+
+    // figure out the size we need as well as the stride
+    const int32_t formatIdx = convertGLPixelFormat(format, type);
+    if (formatIdx == 0) { // we don't know what to do with this
+        ogles_error(c, GL_INVALID_OPERATION);
+        return;
+    }
+
+    const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
+    const int32_t align = c->textures.unpackAlignment-1;
+    const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
+    const size_t size = bpr * height;
+    const int32_t stride = bpr / pixelFormat.size;
+    GGLSurface userSurface;
+    userSurface.version = sizeof(userSurface);
+    userSurface.width  = width;
+    userSurface.height = height;
+    userSurface.stride = stride;
+    userSurface.format = formatIdx;
+    userSurface.compressedFormat = 0;
+    userSurface.data = (GLubyte*)pixels;
+
+    int err = copyPixels(c,
+            surface, xoffset, yoffset,
+            userSurface, 0, 0, width, height); 
+    if (err) {
+        ogles_error(c, err);
+        return;
+    }
+
+    generateMipmap(c, level);
+
+    // since we only changed the content of the texture, we don't need
+    // to call bindTexture on the main rasterizer.
+}
+
+// ----------------------------------------------------------------------------
+
+void glCopyTexImage2D(
+        GLenum target, GLint level, GLenum internalformat,
+        GLint x, GLint y, GLsizei width, GLsizei height,
+        GLint border)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (target != GL_TEXTURE_2D) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if (internalformat<GL_ALPHA || internalformat>GL_LUMINANCE_ALPHA) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if (width<0 || height<0 || border!=0 || level<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+
+    GLenum format = 0;
+    GLenum type = GL_UNSIGNED_BYTE;
+    const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+    const int cbFormatIdx = cbSurface.format;
+    switch (cbFormatIdx) {
+    case GGL_PIXEL_FORMAT_RGB_565:
+        type = GL_UNSIGNED_SHORT_5_6_5;
+        break;
+    case GGL_PIXEL_FORMAT_RGBA_5551:
+        type = GL_UNSIGNED_SHORT_5_5_5_1;
+        break;
+    case GGL_PIXEL_FORMAT_RGBA_4444:
+        type = GL_UNSIGNED_SHORT_4_4_4_4;
+        break;
+    }
+    switch (internalformat) {
+    case GL_ALPHA:
+    case GL_LUMINANCE_ALPHA:
+    case GL_LUMINANCE:
+        type = GL_UNSIGNED_BYTE;
+        break;    
+    }
+
+    // figure out the format to use for the new texture
+    switch (cbFormatIdx) {
+    case GGL_PIXEL_FORMAT_RGBA_8888:
+    case GGL_PIXEL_FORMAT_A_8:
+    case GGL_PIXEL_FORMAT_RGBA_5551:
+    case GGL_PIXEL_FORMAT_RGBA_4444:
+        format = internalformat;
+        break;    
+    case GGL_PIXEL_FORMAT_RGBX_8888:
+    case GGL_PIXEL_FORMAT_RGB_888:
+    case GGL_PIXEL_FORMAT_RGB_565:
+    case GGL_PIXEL_FORMAT_L_8:
+        switch (internalformat) {
+        case GL_LUMINANCE:
+        case GL_RGB:
+            format = internalformat;
+            break;    
+        }
+        break;
+    }
+
+    if (format == 0) {
+        // invalid combination
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+
+    // create the new texture...
+    int32_t size;
+    GGLSurface* surface;
+    int error = createTextureSurface(c, &surface, &size,
+            level, format, type, width, height);
+    if (error) {
+        ogles_error(c, error);
+        return;
+    }
+    
+    // The bottom row is stored first in textures
+    GGLSurface txSurface(*surface);
+    txSurface.stride = -txSurface.stride;
+
+    // (x,y) is the lower-left corner of colorBuffer
+    y = cbSurface.height - (y + height);
+
+    int err = copyPixels(c,
+            txSurface, 0, 0,
+            cbSurface, x, y, cbSurface.width, cbSurface.height);  
+    if (err) {
+        ogles_error(c, err);
+    }
+
+    generateMipmap(c, level);
+}
+
+void glCopyTexSubImage2D(
+        GLenum target, GLint level, GLint xoffset, GLint yoffset,
+        GLint x, GLint y, GLsizei width, GLsizei height)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if (target != GL_TEXTURE_2D) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    if (!width || !height) {
+        return; // okay, but no-op.
+    }
+
+    // find out which texture is bound to the current unit
+    const int active = c->textures.active;
+    EGLTextureObject* tex = c->textures.tmu[active].texture;
+    const GGLSurface& surface(tex->mip(level));
+
+    if (!tex->internalformat) {
+        ogles_error(c, GL_INVALID_OPERATION);
+        return;
+    }
+    if ((xoffset + width  > GLsizei(surface.width)) ||
+        (yoffset + height > GLsizei(surface.height))) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+
+    // The bottom row is stored first in textures
+    GGLSurface txSurface(surface);
+    txSurface.stride = -txSurface.stride;
+
+    // (x,y) is the lower-left corner of colorBuffer
+    const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+    y = cbSurface.height - (y + height);
+
+    int err = copyPixels(c,
+            surface, xoffset, yoffset,
+            cbSurface, x, y, width, height);  
+    if (err) {
+        ogles_error(c, err);
+        return;
+    }
+
+    generateMipmap(c, level);
+}
+
+void glReadPixels(
+        GLint x, GLint y, GLsizei width, GLsizei height,
+        GLenum format, GLenum type, GLvoid *pixels)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    if ((format != GL_RGBA) && (format != GL_RGB)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+    if (width<0 || height<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+    if (x<0 || x<0) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+
+    int32_t formatIdx = GGL_PIXEL_FORMAT_NONE;
+    if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) {
+        formatIdx = GGL_PIXEL_FORMAT_RGBA_8888;
+    } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) {
+        formatIdx = GGL_PIXEL_FORMAT_RGB_565;
+    } else {
+        ogles_error(c, GL_INVALID_OPERATION);
+        return;
+    }
+
+    const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s;
+    if ((x+width > GLint(readSurface.width)) ||
+            (y+height > GLint(readSurface.height))) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+
+    const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
+    const int32_t align = c->textures.packAlignment-1;
+    const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
+    const int32_t stride = bpr / pixelFormat.size;
+
+    GGLSurface userSurface;
+    userSurface.version = sizeof(userSurface);
+    userSurface.width  = width;
+    userSurface.height = height;
+    userSurface.stride = -stride; // bottom row is transfered first
+    userSurface.format = formatIdx;
+    userSurface.compressedFormat = 0;
+    userSurface.data = (GLubyte*)pixels;
+
+    // use pixel-flinger to handle all the conversions
+    GGLContext* ggl = getRasterizer(c);
+    if (!ggl) {
+        // the only reason this would fail is because we ran out of memory
+        ogles_error(c, GL_OUT_OF_MEMORY);
+        return;
+    }
+
+    ggl->colorBuffer(ggl, &userSurface);  // destination is user buffer 
+    ggl->bindTexture(ggl, &readSurface);  // source is read-buffer
+    ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
+    ggl->recti(ggl, 0, 0, width, height);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark DrawTexture Extension
+#endif
+
+void glDrawTexsvOES(const GLshort* coords) {
+    ogles_context_t* c = ogles_context_t::get();
+    drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
+}
+void glDrawTexivOES(const GLint* coords) {
+    ogles_context_t* c = ogles_context_t::get();
+    drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
+}
+void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
+    ogles_context_t* c = ogles_context_t::get();
+    drawTexiOES(x, y, z, w, h, c);
+}
+void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) {
+    ogles_context_t* c = ogles_context_t::get();
+    drawTexiOES(x, y, z, w, h, c);
+}
+
+void glDrawTexfvOES(const GLfloat* coords) {
+    ogles_context_t* c = ogles_context_t::get();
+    drawTexxOES(
+            gglFloatToFixed(coords[0]),
+            gglFloatToFixed(coords[1]),
+            gglFloatToFixed(coords[2]),
+            gglFloatToFixed(coords[3]),
+            gglFloatToFixed(coords[4]),
+            c);
+}
+void glDrawTexxvOES(const GLfixed* coords) {
+    ogles_context_t* c = ogles_context_t::get();
+    drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
+}
+void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){
+    ogles_context_t* c = ogles_context_t::get();
+    drawTexxOES(
+            gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z),
+            gglFloatToFixed(w), gglFloatToFixed(h),
+            c);
+}
+void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
+    ogles_context_t* c = ogles_context_t::get();
+    drawTexxOES(x, y, z, w, h, c);
+}
diff --git a/opengl/libagl/texture.h b/opengl/libagl/texture.h
new file mode 100644
index 0000000..5c57948
--- /dev/null
+++ b/opengl/libagl/texture.h
@@ -0,0 +1,45 @@
+/* libs/opengles/texture.h
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_OPENGLES_TEXTURE_H
+#define ANDROID_OPENGLES_TEXTURE_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+#include "context.h"
+
+namespace android {
+
+void ogles_init_texture(ogles_context_t* c);
+void ogles_uninit_texture(ogles_context_t* c);
+void ogles_validate_texture_impl(ogles_context_t* c);
+
+inline void ogles_validate_texture(ogles_context_t* c) {
+    if (c->rasterizer.state.enables & GGL_ENABLE_TMUS)
+        ogles_validate_texture_impl(c);
+}
+
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_TEXTURE_H
diff --git a/opengl/libagl/vertex.cpp b/opengl/libagl/vertex.cpp
new file mode 100644
index 0000000..dad04d6
--- /dev/null
+++ b/opengl/libagl/vertex.cpp
@@ -0,0 +1,247 @@
+/* libs/opengles/vertex.cpp
+**
+** Copyright 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 <stdlib.h>
+#include "context.h"
+#include "fp.h"
+#include "vertex.h"
+#include "state.h"
+#include "matrix.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+void ogles_init_vertex(ogles_context_t* c)
+{
+    c->cull.enable = GL_FALSE;
+    c->cull.cullFace = GL_BACK;
+    c->cull.frontFace = GL_CCW;
+
+    c->current.color.r = 0x10000;
+    c->current.color.g = 0x10000;
+    c->current.color.b = 0x10000;
+    c->current.color.a = 0x10000;
+
+    c->currentNormal.z = 0x10000;
+}
+
+void ogles_uninit_vertex(ogles_context_t* c)
+{
+}
+
+// ----------------------------------------------------------------------------
+// vertex processing
+// ----------------------------------------------------------------------------
+
+// Divides a vertex clip coordinates by W
+static inline
+void perspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
+{
+    // [x,y,z]window = vpt * ([x,y,z]clip / clip.w)
+    // [w]window = 1/w
+
+    // With a regular projection generated by glFrustum(),
+    // we have w=-z, therefore, w is in [zNear, zFar].
+    // Also, zNear and zFar are stricly positive,
+    // and 1/w (window.w) is in [1/zFar, 1/zNear], usually this
+    // means ]0, +inf[ -- however, it is always recommended
+    // to use as large values as possible for zNear.
+    // All in all, w is usually smaller than 1.0 (assuming
+    // zNear is at least 1.0); and even if zNear is smaller than 1.0
+    // values of w won't be too big.
+
+    const int32_t rw = gglRecip28(v->clip.w);
+    const GLfixed* const m = c->transforms.vpt.transform.matrix.m;
+    v->window.w = rw;
+    v->window.x = gglMulAddx(gglMulx(v->clip.x, rw, 16), m[ 0], m[12], 28); 
+    v->window.y = gglMulAddx(gglMulx(v->clip.y, rw, 16), m[ 5], m[13], 28);
+    v->window.x = TRI_FROM_FIXED(v->window.x);
+    v->window.y = TRI_FROM_FIXED(v->window.y);
+    if (enables & GGL_ENABLE_DEPTH_TEST) {
+        v->window.z = gglMulAddx(gglMulx(v->clip.z, rw, 16), m[10], m[14], 28);
+    }
+}
+
+// frustum clipping and W-divide
+static inline
+void clipFrustumPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
+{
+    // ndc = clip / W
+    // window = ncd * viewport
+    
+    // clip to the view-volume
+    uint32_t clip = v->flags & vertex_t::CLIP_ALL;
+    const GLfixed w = v->clip.w;
+    if (v->clip.x < -w)   clip |= vertex_t::CLIP_L;
+    if (v->clip.x >  w)   clip |= vertex_t::CLIP_R;
+    if (v->clip.y < -w)   clip |= vertex_t::CLIP_B;
+    if (v->clip.y >  w)   clip |= vertex_t::CLIP_T;
+    if (v->clip.z < -w)   clip |= vertex_t::CLIP_N;
+    if (v->clip.z >  w)   clip |= vertex_t::CLIP_F;
+
+    v->flags |= clip;
+    c->arrays.cull &= clip;
+
+    if (ggl_likely(!clip)) {
+        // if the vertex is clipped, we don't do the perspective
+        // divide, since we don't need its window coordinates.
+        perspective(c, v, enables);
+    }
+}
+
+// frustum clipping, user clipping and W-divide
+static inline
+void clipAllPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
+{
+    // compute eye coordinates
+    c->arrays.mv_transform(
+            &c->transforms.modelview.transform, &v->eye, &v->obj);
+    v->flags |= vertex_t::EYE;
+
+    // clip this vertex against each user clip plane
+    uint32_t clip = 0;
+    int planes = c->clipPlanes.enable;
+    while (planes) {
+        const int i = 31 - gglClz(planes);
+        planes &= ~(1<<i);
+        // XXX: we should have a special dot() for 2,3,4 coords vertices
+        GLfixed d = dot4(c->clipPlanes.plane[i].equation.v, v->eye.v);
+        if (d < 0) {
+            clip |= 0x100<<i;
+        }
+    }
+    v->flags |= clip;
+
+    clipFrustumPerspective(c, v, enables);
+}
+
+// ----------------------------------------------------------------------------
+
+void ogles_vertex_project(ogles_context_t* c, vertex_t* v) {
+    perspective(c, v, c->rasterizer.state.enables);
+}
+
+void ogles_vertex_perspective2D(ogles_context_t* c, vertex_t* v)
+{
+    // here we assume w=1.0 and the viewport transformation
+    // has been applied already.
+    c->arrays.cull = 0;
+    v->window.x = TRI_FROM_FIXED(v->clip.x);
+    v->window.y = TRI_FROM_FIXED(v->clip.y);
+    v->window.z = v->clip.z;
+    v->window.w = v->clip.w << 12;
+}
+
+void ogles_vertex_perspective3DZ(ogles_context_t* c, vertex_t* v) {
+    clipFrustumPerspective(c, v, GGL_ENABLE_DEPTH_TEST);
+}
+void ogles_vertex_perspective3D(ogles_context_t* c, vertex_t* v) {
+    clipFrustumPerspective(c, v, 0);
+}
+void ogles_vertex_clipAllPerspective3DZ(ogles_context_t* c, vertex_t* v) {
+    clipAllPerspective(c, v, GGL_ENABLE_DEPTH_TEST);
+}
+void ogles_vertex_clipAllPerspective3D(ogles_context_t* c, vertex_t* v) {
+    clipAllPerspective(c, v, 0);
+}
+
+static void clipPlanex(GLenum plane, const GLfixed* equ, ogles_context_t* c)
+{
+    const int p = plane - GL_CLIP_PLANE0;
+    if (ggl_unlikely(uint32_t(p) > (GL_CLIP_PLANE5 - GL_CLIP_PLANE0))) {
+        ogles_error(c, GL_INVALID_ENUM);
+        return;
+    }
+
+    vec4_t& equation = c->clipPlanes.plane[p].equation;
+    memcpy(equation.v, equ, sizeof(vec4_t));
+
+    ogles_validate_transform(c, transform_state_t::MVIT);
+    transform_t& mvit = c->transforms.mvit4;
+    mvit.point4(&mvit, &equation, &equation);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+
+void glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->current.color.r       = gglFloatToFixed(r);
+    c->currentColorClamped.r = gglClampx(c->current.color.r);
+    c->current.color.g       = gglFloatToFixed(g);
+    c->currentColorClamped.g = gglClampx(c->current.color.g);
+    c->current.color.b       = gglFloatToFixed(b);
+    c->currentColorClamped.b = gglClampx(c->current.color.b);
+    c->current.color.a       = gglFloatToFixed(a);
+    c->currentColorClamped.a = gglClampx(c->current.color.a);
+}
+
+void glColor4x(GLfixed r, GLfixed g, GLfixed b, GLfixed a)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->current.color.r = r;
+    c->current.color.g = g;
+    c->current.color.b = b;
+    c->current.color.a = a;
+    c->currentColorClamped.r = gglClampx(r);
+    c->currentColorClamped.g = gglClampx(g);
+    c->currentColorClamped.b = gglClampx(b);
+    c->currentColorClamped.a = gglClampx(a);
+}
+
+void glNormal3f(GLfloat x, GLfloat y, GLfloat z)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->currentNormal.x = gglFloatToFixed(x);
+    c->currentNormal.y = gglFloatToFixed(y);
+    c->currentNormal.z = gglFloatToFixed(z);
+}
+
+void glNormal3x(GLfixed x, GLfixed y, GLfixed z)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    c->currentNormal.x = x;
+    c->currentNormal.y = y;
+    c->currentNormal.z = z;
+}
+
+// ----------------------------------------------------------------------------
+
+void glClipPlanef(GLenum plane, const GLfloat* equ)
+{
+    const GLfixed equx[4] = {
+            gglFloatToFixed(equ[0]),
+            gglFloatToFixed(equ[1]),
+            gglFloatToFixed(equ[2]),
+            gglFloatToFixed(equ[3])
+    };
+    ogles_context_t* c = ogles_context_t::get();
+    clipPlanex(plane, equx, c);
+}
+
+void glClipPlanex(GLenum plane, const GLfixed* equ)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    clipPlanex(plane, equ, c);
+}
diff --git a/opengl/libagl/vertex.h b/opengl/libagl/vertex.h
new file mode 100644
index 0000000..55e6213
--- /dev/null
+++ b/opengl/libagl/vertex.h
@@ -0,0 +1,48 @@
+/* libs/opengles/vertex.h
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_OPENGLES_VERTEX_H
+#define ANDROID_OPENGLES_VERTEX_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+namespace android {
+
+namespace gl {
+struct vertex_t;
+struct ogles_context_t;
+};
+
+void ogles_init_vertex(ogles_context_t* c);
+void ogles_uninit_vertex(ogles_context_t* c);
+
+void ogles_vertex_perspective2D(ogles_context_t*, vertex_t*);
+
+void ogles_vertex_perspective3D(ogles_context_t*, vertex_t*);
+void ogles_vertex_perspective3DZ(ogles_context_t*, vertex_t*);
+void ogles_vertex_clipAllPerspective3D(ogles_context_t*, vertex_t*);
+void ogles_vertex_clipAllPerspective3DZ(ogles_context_t*, vertex_t*);
+
+
+void ogles_vertex_project(ogles_context_t* c, vertex_t*);
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_VERTEX_H
+
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
new file mode 100644
index 0000000..2ecc776
--- /dev/null
+++ b/opengl/libs/Android.mk
@@ -0,0 +1,53 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Build META EGL library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= 	\
+	EGL/egl.cpp 		\
+	EGL/gpu.cpp			\
+#
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libui
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libEGL
+
+# needed on sim build because of weird logging issues
+ifeq ($(TARGET_SIMULATOR),true)
+else
+    LOCAL_SHARED_LIBRARIES += libdl
+    # we need to access the Bionic private header <bionic_tls.h>
+    LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+
+#
+# Build the wrapper OpenGL ES library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= 	\
+	GLES_CM/gl.cpp.arm 		\
+	GLES_CM/gl_logger.cpp 	\
+#
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libui libEGL
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libGLESv1_CM
+
+# needed on sim build because of weird logging issues
+ifeq ($(TARGET_SIMULATOR),true)
+else
+    LOCAL_SHARED_LIBRARIES += libdl
+    # we need to access the Bionic private header <bionic_tls.h>
+    LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
new file mode 100644
index 0000000..687c8bc
--- /dev/null
+++ b/opengl/libs/EGL/egl.cpp
@@ -0,0 +1,1363 @@
+/* 
+ ** Copyright 2007, 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.
+ */
+
+#define LOG_TAG "GLLogger"
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+
+#include <sys/ioctl.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <cutils/properties.h>
+#include <cutils/memory.h>
+
+#include <utils/RefBase.h>
+
+#include "hooks.h"
+#include "egl_impl.h"
+
+
+#define MAKE_CONFIG(_impl, _index)  ((EGLConfig)(((_impl)<<24) | (_index)))
+#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 4
+static char const * const gVendorString     = "Android";
+static char const * const gVersionString    = "1.31 Android META-EGL";
+static char const * const gClientApiString  = "OpenGL ES";
+static char const * const gExtensionString  = "";
+
+template <int MAGIC>
+struct egl_object_t
+{
+    egl_object_t() : magic(MAGIC) { }
+    ~egl_object_t() { magic = 0; }
+    bool isValid() const { return magic == MAGIC; }
+private:
+    uint32_t    magic;
+};
+
+struct egl_display_t : public egl_object_t<'_dpy'>
+{
+    EGLDisplay  dpys[2];
+    EGLConfig*  configs[2];
+    EGLint      numConfigs[2];
+    EGLint      numTotalConfigs;
+    char const* extensionsString;
+    volatile int32_t refs;
+    struct strings_t {
+        char const * vendor;
+        char const * version;
+        char const * clientApi;
+        char const * extensions;
+    };
+    strings_t   queryString[2];
+};
+
+struct egl_surface_t : public egl_object_t<'_srf'>
+{
+    egl_surface_t(EGLDisplay dpy, EGLSurface surface,
+            NativeWindowType window, int impl, egl_connection_t const* cnx) 
+    : dpy(dpy), surface(surface), window(window), impl(impl), cnx(cnx)
+    {
+        // NOTE: window must be incRef'ed and connected already
+    }
+    ~egl_surface_t() {
+        if (window) {
+            if (window->disconnect)
+                window->disconnect(window);
+            window->decRef(window);
+        }
+    }
+    EGLDisplay                  dpy;
+    EGLSurface                  surface;
+    NativeWindowType            window;
+    int                         impl;
+    egl_connection_t const*     cnx;
+};
+
+struct egl_context_t : public egl_object_t<'_ctx'>
+{
+    egl_context_t(EGLDisplay dpy, EGLContext context,
+            int impl, egl_connection_t const* cnx) 
+    : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
+    {
+    }
+    EGLDisplay                  dpy;
+    EGLContext                  context;
+    EGLSurface                  read;
+    EGLSurface                  draw;
+    int                         impl;
+    egl_connection_t const*     cnx;
+};
+
+struct tls_t
+{
+    tls_t() : error(EGL_SUCCESS), ctx(0) { }
+    EGLint      error;
+    EGLContext  ctx;
+};
+
+static void gl_unimplemented() {
+    LOGE("called unimplemented OpenGL ES API");
+}
+
+// ----------------------------------------------------------------------------
+// GL / EGL hooks
+// ----------------------------------------------------------------------------
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+#define GL_ENTRY(_r, _api, ...) #_api,
+#define EGL_ENTRY(_r, _api, ...) #_api,
+
+static char const * const gl_names[] = {
+    #include "gl_entries.in"
+    NULL
+};
+
+static char const * const egl_names[] = {
+    #include "egl_entries.in"
+    NULL
+};
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+
+// ----------------------------------------------------------------------------
+
+egl_connection_t gEGLImpl[2];
+static egl_display_t gDisplay[NUM_DISPLAYS];
+static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_key_t gEGLThreadLocalStorageKey = -1;
+
+// ----------------------------------------------------------------------------
+
+gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
+pthread_key_t gGLWrapperKey = -1;
+
+// ----------------------------------------------------------------------------
+
+static __attribute__((noinline))
+const char *egl_strerror(EGLint err)
+{
+    switch (err){
+        case EGL_SUCCESS:               return "EGL_SUCCESS";
+        case EGL_NOT_INITIALIZED:       return "EGL_NOT_INITIALIZED";
+        case EGL_BAD_ACCESS:            return "EGL_BAD_ACCESS";
+        case EGL_BAD_ALLOC:             return "EGL_BAD_ALLOC";
+        case EGL_BAD_ATTRIBUTE:         return "EGL_BAD_ATTRIBUTE";
+        case EGL_BAD_CONFIG:            return "EGL_BAD_CONFIG";
+        case EGL_BAD_CONTEXT:           return "EGL_BAD_CONTEXT";
+        case EGL_BAD_CURRENT_SURFACE:   return "EGL_BAD_CURRENT_SURFACE";
+        case EGL_BAD_DISPLAY:           return "EGL_BAD_DISPLAY";
+        case EGL_BAD_MATCH:             return "EGL_BAD_MATCH";
+        case EGL_BAD_NATIVE_PIXMAP:     return "EGL_BAD_NATIVE_PIXMAP";
+        case EGL_BAD_NATIVE_WINDOW:     return "EGL_BAD_NATIVE_WINDOW";
+        case EGL_BAD_PARAMETER:         return "EGL_BAD_PARAMETER";
+        case EGL_BAD_SURFACE:           return "EGL_BAD_SURFACE";
+        case EGL_CONTEXT_LOST:          return "EGL_CONTEXT_LOST";
+        default: return "UNKNOWN";
+    }
+}
+
+static __attribute__((noinline))
+void clearTLS() {
+    if (gEGLThreadLocalStorageKey != -1) {
+        tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
+        if (tls) {
+            delete tls;
+            pthread_setspecific(gEGLThreadLocalStorageKey, 0);
+        }
+    }
+}
+
+static tls_t* getTLS()
+{
+    tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
+    if (tls == 0) {
+        tls = new tls_t;
+        pthread_setspecific(gEGLThreadLocalStorageKey, tls);
+    }
+    return tls;
+}
+
+template<typename T>
+static __attribute__((noinline))
+T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
+    if (gEGLThreadLocalStorageKey == -1) {
+        pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
+        if (gEGLThreadLocalStorageKey == -1)
+            pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
+        pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
+    }
+    tls_t* tls = getTLS();
+    if (tls->error != error) {
+        LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
+        tls->error = error;
+    }
+    return returnValue;
+}
+
+static __attribute__((noinline))
+GLint getError() {
+    if (gEGLThreadLocalStorageKey == -1)
+        return EGL_SUCCESS;
+    tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
+    if (!tls) return EGL_SUCCESS;
+    GLint error = tls->error;
+    tls->error = EGL_SUCCESS;
+    return error;
+}
+
+static __attribute__((noinline))
+void setContext(EGLContext ctx) {
+    if (gEGLThreadLocalStorageKey == -1) {
+        pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
+        if (gEGLThreadLocalStorageKey == -1)
+            pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
+        pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
+    }
+    tls_t* tls = getTLS();
+    tls->ctx = ctx;
+}
+
+static __attribute__((noinline))
+EGLContext getContext() {
+    if (gEGLThreadLocalStorageKey == -1)
+        return EGL_NO_CONTEXT;
+    tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
+    if (!tls) return EGL_NO_CONTEXT;
+    return tls->ctx;
+}
+
+
+/*****************************************************************************/
+
+class ISurfaceComposer;
+const sp<ISurfaceComposer>& getSurfaceFlinger();
+request_gpu_t* gpu_acquire(void* user);
+int gpu_release(void*, request_gpu_t* gpu);
+
+static __attribute__((noinline))
+void *load_driver(const char* driver, gl_hooks_t* hooks)
+{
+    void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
+    LOGE_IF(!dso,
+            "couldn't load <%s> library (%s)",
+            driver, dlerror());
+
+    if (dso) {
+        void** curr;
+        char const * const * api;
+        gl_hooks_t::gl_t* gl = &hooks->gl;
+        curr = (void**)gl;
+        api = gl_names;
+        while (*api) {
+            void* f = dlsym(dso, *api);
+            //LOGD("<%s> @ 0x%p", *api, f);
+            if (f == NULL) {
+                //LOGW("<%s> not found in %s", *api, driver);
+                f = (void*)gl_unimplemented;
+            }
+            *curr++ = f;
+            api++;
+        }
+        gl_hooks_t::egl_t* egl = &hooks->egl;
+        curr = (void**)egl;
+        api = egl_names;
+        while (*api) {
+            void* f = dlsym(dso, *api);
+            if (f == NULL) {
+                //LOGW("<%s> not found in %s", *api, driver);
+                f = (void*)0;
+            }
+            *curr++ = f;
+            api++;
+        }
+
+        // hook this driver up with surfaceflinger if needed
+        register_gpu_t register_gpu = 
+            (register_gpu_t)dlsym(dso, "oem_register_gpu");
+
+        if (register_gpu != NULL) {
+            if (getSurfaceFlinger() != 0) {
+                register_gpu(dso, gpu_acquire, gpu_release);
+            }
+        }
+    }
+    return dso;
+}
+
+template<typename T>
+static __attribute__((noinline))
+int binarySearch(
+        T const sortedArray[], int first, int last, T key)
+{
+    while (first <= last) {
+        int mid = (first + last) / 2;
+        if (key > sortedArray[mid]) { 
+            first = mid + 1;
+        } else if (key < sortedArray[mid]) { 
+            last = mid - 1;
+        } else {
+            return mid;
+        }
+    }
+    return -1;
+}
+
+static EGLint configToUniqueId(egl_display_t const* dp, int i, int index) 
+{
+    // NOTE: this mapping works only if we have no more than two EGLimpl
+    return (i>0 ? dp->numConfigs[0] : 0) + index;
+}
+
+static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
+        int& i, int& index) 
+{
+    // NOTE: this mapping works only if we have no more than two EGLimpl
+    size_t numConfigs = dp->numConfigs[0];
+    i = configId / numConfigs;
+    index = configId % numConfigs;
+}
+
+static int cmp_configs(const void* a, const void *b)
+{
+    EGLConfig c0 = *(EGLConfig const *)a;
+    EGLConfig c1 = *(EGLConfig const *)b;
+    return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
+}
+
+struct extention_map_t {
+    const char* name;
+    __eglMustCastToProperFunctionPointerType address;
+};
+
+static const extention_map_t gExtentionMap[] = {
+};
+
+static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
+
+static void(*findProcAddress(const char* name,
+        const extention_map_t* map, size_t n))() 
+{
+    for (uint32_t i=0 ; i<n ; i++) {
+        if (!strcmp(name, map[i].name)) {
+            return map[i].address;
+        }
+    }
+    return NULL;
+}
+
+// ----------------------------------------------------------------------------
+
+static int gl_context_lost() {
+    setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
+    return 0;
+}
+static int egl_context_lost() {
+    setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
+    return EGL_FALSE;
+}
+static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
+    usleep(100000); // don't use all the CPU
+    setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
+    return EGL_FALSE;
+}
+static GLint egl_context_lost_get_error() {
+    return EGL_CONTEXT_LOST;
+}
+static int ext_context_lost() {
+    return 0;
+}
+
+static void gl_no_context() {
+    LOGE("call to OpenGL ES API with no current context");
+}
+static void early_egl_init(void) 
+{
+#if !USE_FAST_TLS_KEY
+    pthread_key_create(&gGLWrapperKey, NULL);
+#endif
+    uint32_t addr = (uint32_t)((void*)gl_no_context);
+    android_memset32(
+            (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT], 
+            addr, 
+            sizeof(gHooks[IMPL_NO_CONTEXT]));
+    setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
+}
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
+
+
+static inline
+egl_display_t* get_display(EGLDisplay dpy)
+{
+    uintptr_t index = uintptr_t(dpy)-1U;
+    return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
+}
+
+static inline
+egl_surface_t* get_surface(EGLSurface surface)
+{
+    egl_surface_t* s = (egl_surface_t *)surface;
+    return s;
+}
+
+static inline
+egl_context_t* get_context(EGLContext context)
+{
+    egl_context_t* c = (egl_context_t *)context;
+    return c;
+}
+
+static egl_connection_t* validate_display_config(
+        EGLDisplay dpy, EGLConfig config,
+        egl_display_t const*& dp, int& impl, int& index)
+{
+    dp = get_display(dpy);
+    if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
+
+    impl = uintptr_t(config)>>24;
+    if (uint32_t(impl) >= 2) {
+        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
+    } 
+    index = uintptr_t(config) & 0xFFFFFF;
+    if (index >= dp->numConfigs[impl]) {
+        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
+    }
+    egl_connection_t* const cnx = &gEGLImpl[impl];
+    if (cnx->dso == 0) {
+        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
+    }
+    return cnx;
+}
+
+static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
+{
+    if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    if (!get_display(dpy)->isValid())
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    if (!ctx) // TODO: make sure context is a valid object
+        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+    if (!get_context(ctx)->isValid())
+        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+    return EGL_TRUE;
+}
+
+static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
+{
+    if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    if (!get_display(dpy)->isValid())
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    if (!surface) // TODO: make sure surface is a valid object
+        return setError(EGL_BAD_SURFACE, EGL_FALSE);
+    if (!get_surface(surface)->isValid())
+        return setError(EGL_BAD_SURFACE, EGL_FALSE);
+    return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+EGLDisplay eglGetDisplay(NativeDisplayType display)
+{
+    if (sEarlyInitState) {
+        return EGL_NO_DISPLAY;
+    }
+
+    uint32_t index = uint32_t(display);
+    if (index >= NUM_DISPLAYS) {
+        return EGL_NO_DISPLAY;
+    }
+    
+    EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
+    egl_display_t* d = &gDisplay[index];
+        
+    // dynamically load all our EGL implementations for that display
+    // and call into the real eglGetGisplay()
+    egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
+    if (cnx->dso == 0) {
+        cnx->hooks = &gHooks[IMPL_SOFTWARE];
+        cnx->dso = load_driver("libagl.so", cnx->hooks);
+    }
+    if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
+        d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
+        LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
+                "No EGLDisplay for software EGL!");
+    }
+
+    cnx = &gEGLImpl[IMPL_HARDWARE];
+    if (cnx->dso == 0 && cnx->unavailable == 0) {
+        char value[PROPERTY_VALUE_MAX];
+        property_get("debug.egl.hw", value, "1");
+        if (atoi(value) != 0) {
+            cnx->hooks = &gHooks[IMPL_HARDWARE];
+            cnx->dso = load_driver("libhgl.so", cnx->hooks);
+        } else {
+            LOGD("3D hardware acceleration is disabled");
+        }
+    }
+    if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
+        android_memset32(
+                (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
+                (uint32_t)((void*)gl_context_lost),
+                sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
+        android_memset32(
+                (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
+                (uint32_t)((void*)egl_context_lost),
+                sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
+        android_memset32(
+                (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
+                (uint32_t)((void*)ext_context_lost),
+                sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
+
+        gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
+                egl_context_lost_swap_buffers;
+        
+        gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
+                egl_context_lost_get_error;
+
+        gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
+                gHooks[IMPL_HARDWARE].egl.eglTerminate;
+        
+        d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
+        if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
+            LOGE("h/w accelerated eglGetDisplay() failed (%s)",
+                    egl_strerror(cnx->hooks->egl.eglGetError()));
+            dlclose((void*)cnx->dso);
+            cnx->dso = 0;
+            // in case of failure, we want to make sure we don't try again
+            // as it's expensive.
+            cnx->unavailable = 1;
+        }
+    }
+
+    return dpy;
+}
+
+// ----------------------------------------------------------------------------
+// Initialization
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+    egl_display_t * const dp = get_display(dpy);
+    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+    if (android_atomic_inc(&dp->refs) > 0) {
+        if (major != NULL) *major = VERSION_MAJOR;
+        if (minor != NULL) *minor = VERSION_MINOR;
+        return EGL_TRUE;
+    }
+    
+    setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
+    
+    // initialize each EGL and
+    // build our own extension string first, based on the extension we know
+    // and the extension supported by our client implementation
+    dp->extensionsString = strdup(gExtensionString);
+    for (int i=0 ; i<2 ; i++) {
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        cnx->major = -1;
+        cnx->minor = -1;
+        if (!cnx->dso) 
+            continue;
+
+        if (cnx->hooks->egl.eglInitialize(
+                dp->dpys[i], &cnx->major, &cnx->minor)) {
+
+            //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
+            //        i, dp->dpys[i], cnx->major, cnx->minor, cnx);
+
+            // get the query-strings for this display for each implementation
+            dp->queryString[i].vendor =
+                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
+            dp->queryString[i].version =
+                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
+            dp->queryString[i].extensions = strdup(
+                    cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
+            dp->queryString[i].clientApi =
+                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
+
+        } else {
+            LOGD("%d: eglInitialize() failed (%s)", 
+                    i, egl_strerror(cnx->hooks->egl.eglGetError()));
+        }
+    }
+
+    EGLBoolean res = EGL_FALSE;
+    for (int i=0 ; i<2 ; i++) {
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
+            EGLint n;
+            if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
+                dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
+                if (dp->configs[i]) {
+                    if (cnx->hooks->egl.eglGetConfigs(
+                            dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
+                    {
+                        // sort the configurations so we can do binary searches
+                        qsort(  dp->configs[i],
+                                dp->numConfigs[i],
+                                sizeof(EGLConfig), cmp_configs);
+
+                        dp->numTotalConfigs += n;
+                        res = EGL_TRUE;
+                    }
+                }
+            }
+        }
+    }
+
+    if (res == EGL_TRUE) {
+        if (major != NULL) *major = VERSION_MAJOR;
+        if (minor != NULL) *minor = VERSION_MINOR;
+        return EGL_TRUE;
+    }
+    return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy)
+{
+    egl_display_t* const dp = get_display(dpy);
+    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    if (android_atomic_dec(&dp->refs) != 1)
+        return EGL_TRUE;
+        
+    EGLBoolean res = EGL_FALSE;
+    for (int i=0 ; i<2 ; i++) {
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        if (cnx->dso) {
+            cnx->hooks->egl.eglTerminate(dp->dpys[i]);
+            
+            /* REVISIT: it's unclear what to do if eglTerminate() fails,
+             * on one end we shouldn't care, on the other end if it fails
+             * it might not be safe to call dlclose() (there could be some
+             * threads around). */
+            
+            free(dp->configs[i]);
+            free((void*)dp->queryString[i].extensions);
+            dp->numConfigs[i] = 0;
+            dp->dpys[i] = EGL_NO_DISPLAY;
+            dlclose((void*)cnx->dso);
+            cnx->dso = 0;
+            res = EGL_TRUE;
+        }
+    }
+    free((void*)dp->extensionsString);
+    dp->extensionsString = 0;
+    dp->numTotalConfigs = 0;
+    clearTLS();
+    return res;
+}
+
+// ----------------------------------------------------------------------------
+// configuration
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglGetConfigs(   EGLDisplay dpy,
+                            EGLConfig *configs,
+                            EGLint config_size, EGLint *num_config)
+{
+    egl_display_t const * const dp = get_display(dpy);
+    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+    GLint numConfigs = dp->numTotalConfigs;
+    if (!configs) {
+        *num_config = numConfigs;
+        return EGL_TRUE;
+    }
+    GLint n = 0;
+    for (int j=0 ; j<2 ; j++) {
+        for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
+            *configs++ = MAKE_CONFIG(j, i);
+            config_size--;
+            n++;
+        }
+    }    
+    
+    *num_config = n;
+    return EGL_TRUE;
+}
+
+EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
+                            EGLConfig *configs, EGLint config_size,
+                            EGLint *num_config)
+{
+    egl_display_t const * const dp = get_display(dpy);
+    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+    if (configs == 0) {
+        *num_config = 0;
+        return EGL_TRUE;
+    }
+
+    EGLint n;
+    EGLBoolean res = EGL_FALSE;
+    *num_config = 0;
+
+    
+    // It is unfortunate, but we need to remap the EGL_CONFIG_IDs, 
+    // to do  this, we have to go through the attrib_list array once
+    // to figure out both its size and if it contains an EGL_CONFIG_ID
+    // key. If so, the full array is copied and patched.
+    // NOTE: we assume that there can be only one occurrence
+    // of EGL_CONFIG_ID.
+    
+    EGLint patch_index = -1;
+    GLint attr;
+    size_t size = 0;
+    while ((attr=attrib_list[size])) {
+        if (attr == EGL_CONFIG_ID)
+            patch_index = size;
+        size += 2;
+    }
+    if (patch_index >= 0) {
+        size += 2; // we need copy the sentinel as well
+        EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
+        if (new_list == 0)
+            return setError(EGL_BAD_ALLOC, EGL_FALSE);
+        memcpy(new_list, attrib_list, size*sizeof(EGLint));
+
+        // patch the requested EGL_CONFIG_ID
+        int i, index;
+        EGLint& configId(new_list[patch_index+1]);
+        uniqueIdToConfig(dp, configId, i, index);
+        
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        if (cnx->dso) {
+            cnx->hooks->egl.eglGetConfigAttrib(
+                    dp->dpys[i], dp->configs[i][index], 
+                    EGL_CONFIG_ID, &configId);
+
+            // and switch to the new list
+            attrib_list = const_cast<const EGLint *>(new_list);
+
+            // At this point, the only configuration that can match is
+            // dp->configs[i][index], however, we don't know if it would be
+            // rejected because of the other attributes, so we do have to call
+            // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
+            // through all the EGLimpl[].
+            // We also know we can only get a single config back, and we know
+            // which one.
+
+            res = cnx->hooks->egl.eglChooseConfig(
+                    dp->dpys[i], attrib_list, configs, config_size, &n);
+            if (res && n>0) {
+                // n has to be 0 or 1, by construction, and we already know
+                // which config it will return (since there can be only one).
+                configs[0] = MAKE_CONFIG(i, index);
+                *num_config = 1;
+            }
+        }
+
+        free(const_cast<EGLint *>(attrib_list));
+        return res;
+    }
+
+    for (int i=0 ; i<2 ; i++) {
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        if (cnx->dso) {
+            if (cnx->hooks->egl.eglChooseConfig(
+                    dp->dpys[i], attrib_list, configs, config_size, &n)) {
+                // now we need to convert these client EGLConfig to our
+                // internal EGLConfig format. This is done in O(n log n).
+                for (int j=0 ; j<n ; j++) {
+                    int index = binarySearch<EGLConfig>(
+                            dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
+                    if (index >= 0) {
+                        configs[j] = MAKE_CONFIG(i, index);
+                    } else {
+                        return setError(EGL_BAD_CONFIG, EGL_FALSE);
+                    }
+                }
+                configs += n;
+                config_size -= n;
+                *num_config += n;
+                res = EGL_TRUE;
+            }
+        }
+    }
+    return res;
+}
+
+EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+        EGLint attribute, EGLint *value)
+{
+    egl_display_t const* dp = 0;
+    int i=0, index=0;
+    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+    if (!cnx) return EGL_FALSE;
+    
+    if (attribute == EGL_CONFIG_ID) {
+        // EGL_CONFIG_IDs must be unique, just use the order of the selected
+        // EGLConfig.
+        *value = configToUniqueId(dp, i, index);
+        return EGL_TRUE;
+    }
+    return cnx->hooks->egl.eglGetConfigAttrib(
+            dp->dpys[i], dp->configs[i][index], attribute, value);
+}
+
+// ----------------------------------------------------------------------------
+// surfaces
+// ----------------------------------------------------------------------------
+
+EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
+                                    NativeWindowType window,
+                                    const EGLint *attrib_list)
+{
+    egl_display_t const* dp = 0;
+    int i=0, index=0;
+    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+    if (cnx) {
+        // window must be connected upon calling underlying
+        // eglCreateWindowSurface
+        if (window) {
+            window->incRef(window);
+            if (window->connect)
+                window->connect(window);
+        }
+
+        EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
+                dp->dpys[i], dp->configs[i][index], window, attrib_list);       
+        if (surface != EGL_NO_SURFACE) {
+            egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
+            return s;
+        }
+        
+        // something went wrong, disconnect and free window
+        // (will disconnect() automatically)
+        if (window) {
+            window->decRef(window);
+        }        
+    }
+    return EGL_NO_SURFACE;
+}
+
+EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
+                                    NativePixmapType pixmap,
+                                    const EGLint *attrib_list)
+{
+    egl_display_t const* dp = 0;
+    int i=0, index=0;
+    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+    if (cnx) {
+        EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
+                dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
+        if (surface != EGL_NO_SURFACE) {
+            egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
+            return s;
+        }
+    }
+    return EGL_NO_SURFACE;
+}
+
+EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
+                                    const EGLint *attrib_list)
+{
+    egl_display_t const* dp = 0;
+    int i=0, index=0;
+    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+    if (cnx) {
+        EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
+                dp->dpys[i], dp->configs[i][index], attrib_list);
+        if (surface != EGL_NO_SURFACE) {
+            egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
+            return s;
+        }
+    }
+    return EGL_NO_SURFACE;
+}
+                                    
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
+{
+    if (!validate_display_surface(dpy, surface))
+        return EGL_FALSE;    
+    egl_display_t const * const dp = get_display(dpy);
+    egl_surface_t const * const s = get_surface(surface);
+
+    EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
+            dp->dpys[s->impl], s->surface);
+    
+    delete s;
+    return result;
+}
+
+EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
+                            EGLint attribute, EGLint *value)
+{
+    if (!validate_display_surface(dpy, surface))
+        return EGL_FALSE;    
+    egl_display_t const * const dp = get_display(dpy);
+    egl_surface_t const * const s = get_surface(surface);
+
+    return s->cnx->hooks->egl.eglQuerySurface(
+            dp->dpys[s->impl], s->surface, attribute, value);
+}
+
+// ----------------------------------------------------------------------------
+// contextes
+// ----------------------------------------------------------------------------
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+                            EGLContext share_list, const EGLint *attrib_list)
+{
+    egl_display_t const* dp = 0;
+    int i=0, index=0;
+    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+    if (cnx) {
+        EGLContext context = cnx->hooks->egl.eglCreateContext(
+                dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
+        if (context != EGL_NO_CONTEXT) {
+            egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
+            return c;
+        }
+    }
+    return EGL_NO_CONTEXT;
+}
+
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
+{
+    if (!validate_display_context(dpy, ctx))
+        return EGL_FALSE;
+    egl_display_t const * const dp = get_display(dpy);
+    egl_context_t * const c = get_context(ctx);
+    EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
+            dp->dpys[c->impl], c->context);
+    delete c;
+    return result;
+}
+
+EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
+                            EGLSurface read, EGLContext ctx)
+{
+    egl_display_t const * const dp = get_display(dpy);
+    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+    if (read == EGL_NO_SURFACE && draw  == EGL_NO_SURFACE &&
+            ctx == EGL_NO_CONTEXT) 
+    {
+        EGLBoolean result = EGL_TRUE;
+        ctx = getContext();
+        if (ctx) {
+            egl_context_t * const c = get_context(ctx);
+            result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
+            if (result == EGL_TRUE) {
+                setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
+                setContext(EGL_NO_CONTEXT);
+            }
+        }
+        return result;
+    }
+
+    if (!validate_display_context(dpy, ctx))
+        return EGL_FALSE;    
+    
+    egl_context_t * const c = get_context(ctx);
+    if (draw != EGL_NO_SURFACE) {
+        egl_surface_t const * d = get_surface(draw);
+        if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+        if (d->impl != c->impl)
+            return setError(EGL_BAD_MATCH, EGL_FALSE);
+        draw = d->surface;
+    }
+    if (read != EGL_NO_SURFACE) {
+        egl_surface_t const * r = get_surface(read);
+        if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+        if (r->impl != c->impl)
+            return setError(EGL_BAD_MATCH, EGL_FALSE);
+        read = r->surface;
+    }
+    EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
+            dp->dpys[c->impl], draw, read, c->context);
+
+    if (result == EGL_TRUE) {
+        setGlThreadSpecific(c->cnx->hooks);
+        setContext(ctx);
+        c->read = read;
+        c->draw = draw;
+    }
+    return result;
+}
+
+
+EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
+                            EGLint attribute, EGLint *value)
+{
+    if (!validate_display_context(dpy, ctx))
+        return EGL_FALSE;    
+    
+    egl_display_t const * const dp = get_display(dpy);
+    egl_context_t * const c = get_context(ctx);
+
+    return c->cnx->hooks->egl.eglQueryContext(
+            dp->dpys[c->impl], c->context, attribute, value);
+}
+
+EGLContext eglGetCurrentContext(void)
+{
+    EGLContext ctx = getContext();
+    return ctx;
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw)
+{
+    EGLContext ctx = getContext();
+    if (ctx) {
+        egl_context_t const * const c = get_context(ctx);
+        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
+        switch (readdraw) {
+            case EGL_READ: return c->read;
+            case EGL_DRAW: return c->draw;            
+            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+        }
+    }
+    return EGL_NO_SURFACE;
+}
+
+EGLDisplay eglGetCurrentDisplay(void)
+{
+    EGLContext ctx = getContext();
+    if (ctx) {
+        egl_context_t const * const c = get_context(ctx);
+        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
+        return c->dpy;
+    }
+    return EGL_NO_DISPLAY;
+}
+
+EGLBoolean eglWaitGL(void)
+{
+    EGLBoolean res = EGL_TRUE;
+    EGLContext ctx = getContext();
+    if (ctx) {
+        egl_context_t const * const c = get_context(ctx);
+        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+        if (uint32_t(c->impl)>=2)
+            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+        egl_connection_t* const cnx = &gEGLImpl[c->impl];
+        if (!cnx->dso) 
+            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+        res = cnx->hooks->egl.eglWaitGL();
+    }
+    return res;
+}
+
+EGLBoolean eglWaitNative(EGLint engine)
+{
+    EGLBoolean res = EGL_TRUE;
+    EGLContext ctx = getContext();
+    if (ctx) {
+        egl_context_t const * const c = get_context(ctx);
+        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+        if (uint32_t(c->impl)>=2)
+            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+        egl_connection_t* const cnx = &gEGLImpl[c->impl];
+        if (!cnx->dso) 
+            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+        res = cnx->hooks->egl.eglWaitNative(engine);
+    }
+    return res;
+}
+
+EGLint eglGetError(void)
+{
+    EGLint result = EGL_SUCCESS;
+    for (int i=0 ; i<2 ; i++) {
+        EGLint err = EGL_SUCCESS;
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        if (cnx->dso)
+            err = cnx->hooks->egl.eglGetError();
+        if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
+            result = err;
+    }
+    if (result == EGL_SUCCESS)
+        result = getError();
+    return result;
+}
+
+void (*eglGetProcAddress(const char *procname))()
+{
+    __eglMustCastToProperFunctionPointerType addr;
+    addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
+    if (addr) return addr;
+
+    return NULL; // TODO: finish implementation below
+
+    addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
+    if (addr) return addr;
+    
+    addr = 0;
+    int slot = -1;
+    for (int i=0 ; i<2 ; i++) {
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        if (cnx->dso) {
+            if (cnx->hooks->egl.eglGetProcAddress) {
+                addr = cnx->hooks->egl.eglGetProcAddress(procname);
+                if (addr) {
+                    if (slot == -1) {
+                        slot = 0; // XXX: find free slot
+                        if (slot == -1) {
+                            addr = 0;
+                            break;
+                        }
+                    }
+                    cnx->hooks->ext.extensions[slot] = addr;
+                }
+            }
+        }
+    }
+    
+    if (slot >= 0) {
+        addr = 0; // XXX: address of stub 'slot'
+        gGLExtentionMap[slot].name = strdup(procname);
+        gGLExtentionMap[slot].address = addr;
+    }
+    
+    return addr;
+
+    
+    /*
+     *  TODO: For OpenGL ES extensions, we must generate a stub
+     *  that looks like
+     *      mov     r12, #0xFFFF0FFF
+     *      ldr     r12, [r12, #-15]
+     *      ldr     r12, [r12, #TLS_SLOT_OPENGL_API*4]
+     *      mov     r12, [r12, #api_offset]
+     *      ldrne   pc, r12
+     *      mov     pc, #unsupported_extension
+     * 
+     *  and write the address of the extension in *all*
+     *  gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
+     * 
+     */
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
+{
+    if (!validate_display_surface(dpy, draw))
+        return EGL_FALSE;    
+    egl_display_t const * const dp = get_display(dpy);
+    egl_surface_t const * const s = get_surface(draw);
+    return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
+}
+
+EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
+                            NativePixmapType target)
+{
+    if (!validate_display_surface(dpy, surface))
+        return EGL_FALSE;    
+    egl_display_t const * const dp = get_display(dpy);
+    egl_surface_t const * const s = get_surface(surface);
+    return s->cnx->hooks->egl.eglCopyBuffers(
+            dp->dpys[s->impl], s->surface, target);
+}
+
+const char* eglQueryString(EGLDisplay dpy, EGLint name)
+{
+    egl_display_t const * const dp = get_display(dpy);
+    switch (name) {
+        case EGL_VENDOR:
+            return gVendorString;
+        case EGL_VERSION:
+            return gVersionString;
+        case EGL_EXTENSIONS:
+            return gExtensionString;
+        case EGL_CLIENT_APIS:
+            return gClientApiString;
+    }
+    return setError(EGL_BAD_PARAMETER, (const char *)0);
+}
+
+
+// ----------------------------------------------------------------------------
+// EGL 1.1
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSurfaceAttrib(
+        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
+{
+    if (!validate_display_surface(dpy, surface))
+        return EGL_FALSE;    
+    egl_display_t const * const dp = get_display(dpy);
+    egl_surface_t const * const s = get_surface(surface);
+    if (s->cnx->hooks->egl.eglSurfaceAttrib) {
+        return s->cnx->hooks->egl.eglSurfaceAttrib(
+                dp->dpys[s->impl], s->surface, attribute, value);
+    }
+    return setError(EGL_BAD_SURFACE, EGL_FALSE);
+}
+
+EGLBoolean eglBindTexImage(
+        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+    if (!validate_display_surface(dpy, surface))
+        return EGL_FALSE;    
+    egl_display_t const * const dp = get_display(dpy);
+    egl_surface_t const * const s = get_surface(surface);
+    if (s->cnx->hooks->egl.eglBindTexImage) {
+        return s->cnx->hooks->egl.eglBindTexImage(
+                dp->dpys[s->impl], s->surface, buffer);
+    }
+    return setError(EGL_BAD_SURFACE, EGL_FALSE);
+}
+
+EGLBoolean eglReleaseTexImage(
+        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+    if (!validate_display_surface(dpy, surface))
+        return EGL_FALSE;    
+    egl_display_t const * const dp = get_display(dpy);
+    egl_surface_t const * const s = get_surface(surface);
+    if (s->cnx->hooks->egl.eglReleaseTexImage) {
+        return s->cnx->hooks->egl.eglReleaseTexImage(
+                dp->dpys[s->impl], s->surface, buffer);
+    }
+    return setError(EGL_BAD_SURFACE, EGL_FALSE);
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
+{
+    egl_display_t * const dp = get_display(dpy);
+    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+    EGLBoolean res = EGL_TRUE;
+    for (int i=0 ; i<2 ; i++) {
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        if (cnx->dso) {
+            if (cnx->hooks->egl.eglSwapInterval) {
+                if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
+                    res = EGL_FALSE;
+                }
+            }
+        }
+    }
+    return res;
+}
+
+
+// ----------------------------------------------------------------------------
+// EGL 1.2
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglWaitClient(void)
+{
+    EGLBoolean res = EGL_TRUE;
+    EGLContext ctx = getContext();
+    if (ctx) {
+        egl_context_t const * const c = get_context(ctx);
+        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+        if (uint32_t(c->impl)>=2)
+            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+        egl_connection_t* const cnx = &gEGLImpl[c->impl];
+        if (!cnx->dso) 
+            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+        if (cnx->hooks->egl.eglWaitClient) {
+            res = cnx->hooks->egl.eglWaitClient();
+        } else {
+            res = cnx->hooks->egl.eglWaitGL();
+        }
+    }
+    return res;
+}
+
+EGLBoolean eglBindAPI(EGLenum api)
+{
+    // bind this API on all EGLs
+    EGLBoolean res = EGL_TRUE;
+    for (int i=0 ; i<2 ; i++) {
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        if (cnx->dso) {
+            if (cnx->hooks->egl.eglBindAPI) {
+                if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
+                    res = EGL_FALSE;
+                }
+            }
+        }
+    }
+    return res;
+}
+
+EGLenum eglQueryAPI(void)
+{
+    for (int i=0 ; i<2 ; i++) {
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        if (cnx->dso) {
+            if (cnx->hooks->egl.eglQueryAPI) {
+                // the first one we find is okay, because they all
+                // should be the same
+                return cnx->hooks->egl.eglQueryAPI();
+            }
+        }
+    }
+    // or, it can only be OpenGL ES
+    return EGL_OPENGL_ES_API;
+}
+
+EGLBoolean eglReleaseThread(void)
+{
+    for (int i=0 ; i<2 ; i++) {
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        if (cnx->dso) {
+            if (cnx->hooks->egl.eglReleaseThread) {
+                cnx->hooks->egl.eglReleaseThread();
+            }
+        }
+    }
+    clearTLS();    
+    return EGL_TRUE;
+}
+
+EGLSurface eglCreatePbufferFromClientBuffer(
+          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+          EGLConfig config, const EGLint *attrib_list)
+{
+    egl_display_t const* dp = 0;
+    int i=0, index=0;
+    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+    if (!cnx) return EGL_FALSE;
+    if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
+        return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
+                dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
+    }
+    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
+}
diff --git a/opengl/libs/EGL/gpu.cpp b/opengl/libs/EGL/gpu.cpp
new file mode 100644
index 0000000..3f9fd63
--- /dev/null
+++ b/opengl/libs/EGL/gpu.cpp
@@ -0,0 +1,212 @@
+/* 
+ ** Copyright 2007, 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.
+ */
+
+#define LOG_TAG "EGL"
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/IMemory.h>
+#include <utils/threads.h>
+#include <utils/IServiceManager.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Parcel.h>
+
+#include <ui/EGLDisplaySurface.h>
+#include <ui/ISurfaceComposer.h>
+
+#include "hooks.h"
+#include "egl_impl.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+/*
+ * we provide our own allocators for the GPU regions, these
+ * allocators go through surfaceflinger 
+ */
+
+static Mutex                            gRegionsLock;
+static request_gpu_t                    gRegions;
+static sp<ISurfaceComposer>             gSurfaceManager;
+ISurfaceComposer*                       GLES_localSurfaceManager = 0;
+
+extern egl_connection_t gEGLImpl[2];
+
+const sp<ISurfaceComposer>& getSurfaceFlinger()
+{
+    Mutex::Autolock _l(gRegionsLock);
+
+    /*
+     * There is a little bit of voodoo magic here. We want to access
+     * surfaceflinger for allocating GPU regions, however, when we are
+     * running as part of surfaceflinger, we want to bypass the
+     * service manager because surfaceflinger might not be registered yet.
+     * SurfaceFlinger will populate "GLES_localSurfaceManager" with its
+     * own address, so we can just use that.
+     */
+    if (gSurfaceManager == 0) {
+        if (GLES_localSurfaceManager) {
+            // we're running in SurfaceFlinger's context
+            gSurfaceManager =  GLES_localSurfaceManager;
+        } else {
+            // we're a remote process or not part of surfaceflinger,
+            // go through the service manager
+            sp<IServiceManager> sm = defaultServiceManager();
+            if (sm != NULL) {
+                sp<IBinder> binder = sm->getService(String16("SurfaceFlinger"));
+                gSurfaceManager = interface_cast<ISurfaceComposer>(binder);
+            }
+        }
+    }
+    return gSurfaceManager;
+}
+
+class GPURevokeRequester : public BnGPUCallback
+{
+public:
+    virtual void gpuLost() {
+        LOGD("CONTEXT_LOST: Releasing GPU upon request from SurfaceFlinger.");
+        gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
+    }
+};
+
+static sp<GPURevokeRequester> gRevokerCallback;
+
+
+request_gpu_t* gpu_acquire(void* user)
+{
+    sp<ISurfaceComposer> server( getSurfaceFlinger() );
+
+    Mutex::Autolock _l(gRegionsLock);
+    if (server == NULL) {
+        return 0;
+    }
+    
+    ISurfaceComposer::gpu_info_t info;
+    
+    if (gRevokerCallback == 0)
+        gRevokerCallback = new GPURevokeRequester();
+
+    status_t err = server->requestGPU(gRevokerCallback, &info);
+    if (err != NO_ERROR) {
+        LOGD("requestGPU returned %d", err);
+        return 0;
+    }
+
+    bool failed = false;
+    request_gpu_t* gpu = &gRegions;
+    memset(gpu, 0, sizeof(*gpu));
+    
+    if (info.regs != 0) {
+        sp<IMemoryHeap> heap(info.regs->getMemory());
+        if (heap != 0) {
+            int fd = heap->heapID();
+            gpu->regs.fd = fd;
+            gpu->regs.base = info.regs->pointer(); 
+            gpu->regs.size = info.regs->size(); 
+            gpu->regs.user = info.regs.get();
+#if HAVE_ANDROID_OS
+            struct pmem_region region;
+            if (ioctl(fd, PMEM_GET_PHYS, &region) >= 0)
+                gpu->regs.phys = (void*)region.offset;
+#endif
+            info.regs->incStrong(gpu);
+        } else {
+            LOGE("GPU register handle %p is invalid!", info.regs.get());
+            failed = true;
+        }
+    }
+
+    for (size_t i=0 ; i<info.count && !failed ; i++) {
+        sp<IMemory>& region(info.regions[i].region);
+        if (region != 0) {
+            sp<IMemoryHeap> heap(region->getMemory());
+            if (heap != 0) {
+                const int fd = heap->heapID();
+                gpu->gpu[i].fd = fd;
+                gpu->gpu[i].base = region->pointer(); 
+                gpu->gpu[i].size = region->size(); 
+                gpu->gpu[i].user = region.get();
+                gpu->gpu[i].offset = info.regions[i].reserved;
+#if HAVE_ANDROID_OS
+                struct pmem_region reg;
+                if (ioctl(fd, PMEM_GET_PHYS, &reg) >= 0)
+                    gpu->gpu[i].phys = (void*)reg.offset;
+#endif
+                region->incStrong(gpu);
+            } else {
+                LOGE("GPU region handle [%d, %p] is invalid!", i, region.get());
+                failed = true;
+            }
+        }
+    }
+    
+    if (failed) {
+        // something went wrong, clean up everything!
+        if (gpu->regs.user) {
+            static_cast<IMemory*>(gpu->regs.user)->decStrong(gpu);
+            for (size_t i=0 ; i<info.count ; i++) {
+                if (gpu->gpu[i].user) {
+                    static_cast<IMemory*>(gpu->gpu[i].user)->decStrong(gpu);
+                }
+            }
+        }
+    }
+    
+    gpu->count = info.count;
+    return gpu;
+}
+
+int gpu_release(void*, request_gpu_t* gpu)
+{
+    sp<IMemory> regs;
+
+    { // scope for lock
+        Mutex::Autolock _l(gRegionsLock);
+        regs = static_cast<IMemory*>(gpu->regs.user);   
+        gpu->regs.user = 0;
+        if (regs != 0) regs->decStrong(gpu);
+        
+        for (int i=0 ; i<gpu->count ; i++) {
+            sp<IMemory> r(static_cast<IMemory*>(gpu->gpu[i].user));
+            gpu->gpu[i].user = 0;
+            if (r != 0) r->decStrong(gpu);
+        }
+    }
+    
+    // there is a special transaction to relinquish the GPU
+    // (it will happen automatically anyway if we don't do this)
+    Parcel data, reply;
+    // NOTE: this transaction does not require an interface token
+    regs->asBinder()->transact(1000, data, &reply);
+    return 1;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
new file mode 100644
index 0000000..865cf44
--- /dev/null
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -0,0 +1,116 @@
+/* 
+ ** Copyright 2007, 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.
+ */
+
+#define LOG_TAG "GLES_CM"
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "hooks.h"
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+// extensions for the framework
+// ----------------------------------------------------------------------------
+
+void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+        const GLvoid *ptr, GLsizei count) {
+    glColorPointer(size, type, stride, ptr);
+}
+void glNormalPointerBounds(GLenum type, GLsizei stride,
+        const GLvoid *pointer, GLsizei count) {
+    glNormalPointer(type, stride, pointer);
+}
+void glTexCoordPointerBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count) {
+    glTexCoordPointer(size, type, stride, pointer);
+}
+void glVertexPointerBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count) {
+    glVertexPointer(size, type, stride, pointer);
+}
+
+// ----------------------------------------------------------------------------
+// Actual GL entry-points
+// ----------------------------------------------------------------------------
+
+#if GL_LOGGER
+#   include "gl_logger.h"
+#   define GL_LOGGER_IMPL(_x) _x
+#else
+#   define GL_LOGGER_IMPL(_x)
+#endif
+
+#undef API_ENTRY
+#undef CALL_GL_API
+#undef CALL_GL_API_RETURN
+
+#if USE_FAST_TLS_KEY
+
+    #define API_ENTRY(_api) __attribute__((naked)) _api
+
+    #define CALL_GL_API(_api, ...)                              \
+         asm volatile(                                          \
+            "mov   r12, #0xFFFF0FFF   \n"                       \
+            "ldr   r12, [r12, #-15]   \n"                       \
+            "ldr   r12, [r12, %[tls]] \n"                       \
+            "cmp   r12, #0            \n"                       \
+            "ldrne pc,  [r12, %[api]] \n"                       \
+            "bx    lr                 \n"                       \
+            :                                                   \
+            : [tls] "J"(TLS_SLOT_OPENGL_API*4),                 \
+              [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api))    \
+            :                                                   \
+            );
+    
+    #define CALL_GL_API_RETURN(_api, ...) \
+        CALL_GL_API(_api, __VA_ARGS__) \
+        return 0; // placate gcc's warnings. never reached.
+
+#else
+
+    #define API_ENTRY(_api) _api
+
+    #define CALL_GL_API(_api, ...)                                      \
+        gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
+        GL_LOGGER_IMPL( log_##_api(__VA_ARGS__); )                      \
+        _c->_api(__VA_ARGS__)
+    
+    #define CALL_GL_API_RETURN(_api, ...)                               \
+        gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
+        GL_LOGGER_IMPL( log_##_api(__VA_ARGS__); )                      \
+        return _c->_api(__VA_ARGS__)
+
+#endif
+
+extern "C" {
+#include "gl_api.in"
+}
+
+#undef API_ENTRY
+#undef CALL_GL_API
+#undef CALL_GL_API_RETURN
+
diff --git a/opengl/libs/GLES_CM/gl_api.in b/opengl/libs/GLES_CM/gl_api.in
new file mode 100644
index 0000000..9234ef2
--- /dev/null
+++ b/opengl/libs/GLES_CM/gl_api.in
@@ -0,0 +1,606 @@
+void API_ENTRY(glActiveTexture)(GLenum texture) {
+    CALL_GL_API(glActiveTexture, texture);
+}
+
+void API_ENTRY(glAlphaFunc)(GLenum func, GLclampf ref) {
+    CALL_GL_API(glAlphaFunc, func, ref);
+}
+
+void API_ENTRY(glAlphaFuncx)(GLenum func, GLclampx ref) {
+    CALL_GL_API(glAlphaFuncx, func, ref);
+}
+
+void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
+    CALL_GL_API(glBindTexture, target, texture);
+}
+
+void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
+    CALL_GL_API(glBlendFunc, sfactor, dfactor);
+}
+
+void API_ENTRY(glClear)(GLbitfield mask) {
+    CALL_GL_API(glClear, mask);
+}
+
+void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+    CALL_GL_API(glClearColor, red, green, blue, alpha);
+}
+
+void API_ENTRY(glClearColorx)(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) {
+    CALL_GL_API(glClearColorx, red, green, blue, alpha);
+}
+
+void API_ENTRY(glClearDepthf)(GLclampf depth) {
+    CALL_GL_API(glClearDepthf, depth);
+}
+
+void API_ENTRY(glClearDepthx)(GLclampx depth) {
+    CALL_GL_API(glClearDepthx, depth);
+}
+
+void API_ENTRY(glClearStencil)(GLint s) {
+    CALL_GL_API(glClearStencil, s);
+}
+
+void API_ENTRY(glClientActiveTexture)(GLenum texture) {
+    CALL_GL_API(glClientActiveTexture, texture);
+}
+
+void API_ENTRY(glColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
+    CALL_GL_API(glColor4f, red, green, blue, alpha);
+}
+
+void API_ENTRY(glColor4x)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) {
+    CALL_GL_API(glColor4x, red, green, blue, alpha);
+}
+
+void API_ENTRY(glColorMask)(GLboolean r, GLboolean g, GLboolean b, GLboolean a) {
+    CALL_GL_API(glColorMask, r, g, b, a);
+}
+
+void API_ENTRY(glColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
+{
+    CALL_GL_API(glColorPointer, size, type, stride, ptr);
+}
+
+void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat,
+                            GLsizei width, GLsizei height, GLint border,
+                            GLsizei imageSize, const GLvoid *data) {
+    CALL_GL_API(glCompressedTexImage2D, target, level, internalformat,
+            width, height, border, imageSize, data);
+}
+
+void API_ENTRY(glCompressedTexSubImage2D)( GLenum target, GLint level, GLint xoffset,
+                                GLint yoffset, GLsizei width, GLsizei height,
+                                GLenum format, GLsizei imageSize,
+                                const GLvoid *data) {
+    CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset,
+            width, height, format, imageSize, data);
+}
+
+void API_ENTRY(glCopyTexImage2D)(  GLenum target, GLint level, GLenum internalformat,
+                        GLint x, GLint y, GLsizei width, GLsizei height,
+                        GLint border) {
+    CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y,
+            width, height, border);
+}
+
+void API_ENTRY(glCopyTexSubImage2D)(   GLenum target, GLint level, GLint xoffset,
+                            GLint yoffset, GLint x, GLint y, GLsizei width,
+                            GLsizei height) {
+    CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y,
+            width, height);
+}
+
+void API_ENTRY(glCullFace)(GLenum mode) {
+    CALL_GL_API(glCullFace, mode);
+}
+
+void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint *textures) {
+    CALL_GL_API(glDeleteTextures, n, textures);
+}
+
+void API_ENTRY(glDepthFunc)(GLenum func) {
+    CALL_GL_API(glDepthFunc, func);
+}
+
+void API_ENTRY(glDepthMask)(GLboolean flag) {
+    CALL_GL_API(glDepthMask, flag);
+}
+
+void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
+    CALL_GL_API(glDepthRangef, zNear, zFar);
+}
+
+void API_ENTRY(glDepthRangex)(GLclampx zNear, GLclampx zFar) {
+    CALL_GL_API(glDepthRangex, zNear, zFar);
+}
+
+void API_ENTRY(glDisable)(GLenum cap) {
+    CALL_GL_API(glDisable, cap);
+}
+
+void API_ENTRY(glDisableClientState)(GLenum array) {
+    CALL_GL_API(glDisableClientState, array);
+}
+
+void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
+    CALL_GL_API(glDrawArrays, mode, first, count);
+}
+
+void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count,
+                    GLenum type, const GLvoid *indices) {
+    CALL_GL_API(glDrawElements, mode, count, type, indices);
+}
+
+void API_ENTRY(glEnable)(GLenum cap) {
+    CALL_GL_API(glEnable, cap);
+}
+
+void API_ENTRY(glEnableClientState)(GLenum array) {
+    CALL_GL_API(glEnableClientState, array);
+}
+
+void API_ENTRY(glFinish)(void) {
+    CALL_GL_API(glFinish);
+}
+
+void API_ENTRY(glFlush)(void) {
+    CALL_GL_API(glFlush);
+}
+
+void API_ENTRY(glFogf)(GLenum pname, GLfloat param) {
+    CALL_GL_API(glFogf, pname, param);
+}
+
+void API_ENTRY(glFogfv)(GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glFogfv, pname, params);
+}
+
+void API_ENTRY(glFogx)(GLenum pname, GLfixed param) {
+    CALL_GL_API(glFogx, pname, param);
+}
+
+void API_ENTRY(glFogxv)(GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glFogxv, pname, params);
+}
+
+void API_ENTRY(glFrontFace)(GLenum mode) {
+    CALL_GL_API(glFrontFace, mode);
+}
+
+void API_ENTRY(glFrustumf)(GLfloat left, GLfloat right,
+                GLfloat bottom, GLfloat top,
+                GLfloat zNear, GLfloat zFar) {
+    CALL_GL_API(glFrustumf, left, right, bottom, top, zNear, zFar);
+}
+
+void API_ENTRY(glFrustumx)(GLfixed left, GLfixed right,
+                GLfixed bottom, GLfixed top,
+                GLfixed zNear, GLfixed zFar) {
+    CALL_GL_API(glFrustumx, left, right, bottom, top, zNear, zFar);
+}
+
+void API_ENTRY(glGenTextures)(GLsizei n, GLuint *textures) {
+    CALL_GL_API(glGenTextures, n, textures);
+}
+
+GLenum API_ENTRY(glGetError)(void) {
+    CALL_GL_API_RETURN(glGetError);
+}
+
+void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *params) {
+    CALL_GL_API(glGetIntegerv, pname, params);
+}
+
+const GLubyte * API_ENTRY(glGetString)(GLenum name) {
+    CALL_GL_API_RETURN(glGetString, name);
+}
+
+void API_ENTRY(glHint)(GLenum target, GLenum mode) {
+    CALL_GL_API(glHint, target, mode);
+}
+
+void API_ENTRY(glLightModelf)(GLenum pname, GLfloat param) {
+    CALL_GL_API(glLightModelf, pname, param);
+}
+
+void API_ENTRY(glLightModelfv)(GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glLightModelfv, pname, params);
+}
+
+void API_ENTRY(glLightModelx)(GLenum pname, GLfixed param) {
+    CALL_GL_API(glLightModelx, pname, param);
+}
+
+void API_ENTRY(glLightModelxv)(GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glLightModelxv, pname, params);
+}
+
+void API_ENTRY(glLightf)(GLenum light, GLenum pname, GLfloat param) {
+    CALL_GL_API(glLightf, light, pname, param);
+}
+
+void API_ENTRY(glLightfv)(GLenum light, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glLightfv, light, pname, params);
+}
+
+void API_ENTRY(glLightx)(GLenum light, GLenum pname, GLfixed param) {
+    CALL_GL_API(glLightx, light, pname, param);
+}
+
+void API_ENTRY(glLightxv)(GLenum light, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glLightxv, light, pname, params);
+}
+
+void API_ENTRY(glLineWidth)(GLfloat width) {
+    CALL_GL_API(glLineWidth, width);
+}
+
+void API_ENTRY(glLineWidthx)(GLfixed width) {
+    CALL_GL_API(glLineWidthx, width);
+}
+
+void API_ENTRY(glLoadIdentity)(void) {
+    CALL_GL_API(glLoadIdentity);
+}
+
+void API_ENTRY(glLoadMatrixf)(const GLfloat *m) {
+    CALL_GL_API(glLoadMatrixf, m);
+}
+
+void API_ENTRY(glLoadMatrixx)(const GLfixed *m) {
+    CALL_GL_API(glLoadMatrixx, m);
+}
+
+void API_ENTRY(glLogicOp)(GLenum opcode) {
+    CALL_GL_API(glLogicOp, opcode);
+}
+
+void API_ENTRY(glMaterialf)(GLenum face, GLenum pname, GLfloat param) {
+    CALL_GL_API(glMaterialf, face, pname, param);
+}
+
+void API_ENTRY(glMaterialfv)(GLenum face, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glMaterialfv, face, pname, params);
+}
+
+void API_ENTRY(glMaterialx)(GLenum face, GLenum pname, GLfixed param) {
+    CALL_GL_API(glMaterialx, face, pname, param);
+}
+
+void API_ENTRY(glMaterialxv)(GLenum face, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glMaterialxv, face, pname, params);
+}
+
+void API_ENTRY(glMatrixMode)(GLenum mode) {
+    CALL_GL_API(glMatrixMode, mode);
+}
+
+void API_ENTRY(glMultMatrixf)(const GLfloat *m) {
+    CALL_GL_API(glMultMatrixf, m);
+}
+
+void API_ENTRY(glMultMatrixx)(const GLfixed *m) {
+    CALL_GL_API(glMultMatrixx, m);
+}
+
+void API_ENTRY(glMultiTexCoord4f)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) {
+    CALL_GL_API(glMultiTexCoord4f, target, s, t, r, q);
+}
+
+void API_ENTRY(glMultiTexCoord4x)(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) {
+    CALL_GL_API(glMultiTexCoord4x, target, s, t, r, q);
+}
+
+void API_ENTRY(glNormal3f)(GLfloat nx, GLfloat ny, GLfloat nz) {
+    CALL_GL_API(glNormal3f, nx, ny, nz);
+}
+
+void API_ENTRY(glNormal3x)(GLfixed nx, GLfixed ny, GLfixed nz) {
+    CALL_GL_API(glNormal3x, nx, ny, nz);
+}
+
+void API_ENTRY(glNormalPointer)(GLenum type, GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glNormalPointer, type, stride, pointer);
+}
+
+void API_ENTRY(glOrthof)(  GLfloat left, GLfloat right,
+                GLfloat bottom, GLfloat top,
+                GLfloat zNear, GLfloat zFar) {
+    CALL_GL_API(glOrthof, left, right, bottom, top, zNear, zFar);
+}
+
+void API_ENTRY(glOrthox)(  GLfixed left, GLfixed right,
+                GLfixed bottom, GLfixed top,
+                GLfixed zNear, GLfixed zFar) {
+    CALL_GL_API(glOrthox, left, right, bottom, top, zNear, zFar);
+}
+
+void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
+    CALL_GL_API(glPixelStorei, pname, param);
+}
+
+void API_ENTRY(glPointSize)(GLfloat size) {
+    CALL_GL_API(glPointSize, size);
+}
+
+void API_ENTRY(glPointSizex)(GLfixed size) {
+    CALL_GL_API(glPointSizex, size);
+}
+
+void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
+    CALL_GL_API(glPolygonOffset, factor, units);
+}
+
+void API_ENTRY(glPolygonOffsetx)(GLfixed factor, GLfixed units) {
+    CALL_GL_API(glPolygonOffsetx, factor, units);
+}
+
+void API_ENTRY(glPopMatrix)(void) {
+    CALL_GL_API(glPopMatrix);
+}
+
+void API_ENTRY(glPushMatrix)(void) {
+    CALL_GL_API(glPushMatrix);
+}
+
+void API_ENTRY(glReadPixels)(  GLint x, GLint y, GLsizei width, GLsizei height,
+                    GLenum format, GLenum type, GLvoid *pixels) {
+    CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
+}
+
+void API_ENTRY(glRotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glRotatef, angle, x, y, z);
+}
+
+void API_ENTRY(glRotatex)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) {
+    CALL_GL_API(glRotatex, angle, x, y, z);
+}
+
+void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
+    CALL_GL_API(glSampleCoverage, value, invert);
+}
+
+void API_ENTRY(glSampleCoveragex)(GLclampx value, GLboolean invert) {
+    CALL_GL_API(glSampleCoveragex, value, invert);
+}
+
+void API_ENTRY(glScalef)(GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glScalef, x, y, z);
+}
+
+void API_ENTRY(glScalex)(GLfixed x, GLfixed y, GLfixed z) {
+    CALL_GL_API(glScalex, x, y, z);
+}
+
+void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
+    CALL_GL_API(glScissor, x, y, width, height);
+}
+
+void API_ENTRY(glShadeModel)(GLenum mode) {
+    CALL_GL_API(glShadeModel, mode);
+}
+
+void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
+    CALL_GL_API(glStencilFunc, func, ref, mask);
+}
+
+void API_ENTRY(glStencilMask)(GLuint mask) {
+    CALL_GL_API(glStencilMask, mask);
+}
+
+void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
+    CALL_GL_API(glStencilOp, fail, zfail, zpass);
+}
+
+void API_ENTRY(glTexCoordPointer)( GLint size, GLenum type,
+                        GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glTexCoordPointer, size, type, stride, pointer);
+}
+
+void API_ENTRY(glTexEnvf)(GLenum target, GLenum pname, GLfloat param) {
+    CALL_GL_API(glTexEnvf, target, pname, param);
+}
+
+void API_ENTRY(glTexEnvfv)(GLenum target, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glTexEnvfv, target, pname, params);
+}
+
+void API_ENTRY(glTexEnvx)(GLenum target, GLenum pname, GLfixed param) {
+    CALL_GL_API(glTexEnvx, target, pname, param);
+}
+
+void API_ENTRY(glTexEnvxv)(GLenum target, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glTexEnvxv, target, pname, params);
+}
+
+void API_ENTRY(glTexImage2D)(  GLenum target, GLint level, GLint internalformat,
+                    GLsizei width, GLsizei height, GLint border, GLenum format,
+                    GLenum type, const GLvoid *pixels) {
+    CALL_GL_API(glTexImage2D, target, level, internalformat, width, height,
+            border, format, type, pixels);
+}
+
+void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
+    CALL_GL_API(glTexParameterf, target, pname, param);
+}
+
+void API_ENTRY(glTexParameterx)(GLenum target, GLenum pname, GLfixed param) {
+    CALL_GL_API(glTexParameterx, target, pname, param);
+}
+
+void API_ENTRY(glTexSubImage2D)(   GLenum target, GLint level, GLint xoffset,
+                        GLint yoffset, GLsizei width, GLsizei height,
+                        GLenum format, GLenum type, const GLvoid *pixels) {
+    CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset,
+            width, height, format, type, pixels);
+}
+
+void API_ENTRY(glTranslatef)(GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glTranslatef, x, y, z);
+}
+
+void API_ENTRY(glTranslatex)(GLfixed x, GLfixed y, GLfixed z) {
+    CALL_GL_API(glTranslatex, x, y, z);
+}
+
+void API_ENTRY(glVertexPointer)(   GLint size, GLenum type,
+                        GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glVertexPointer, size, type, stride, pointer);
+}
+
+void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
+    CALL_GL_API(glViewport, x, y, width, height);
+}
+
+// ES 1.1
+void API_ENTRY(glClipPlanef)(GLenum plane, const GLfloat *equation) {
+    CALL_GL_API(glClipPlanef, plane, equation);
+}
+void API_ENTRY(glClipPlanex)(GLenum plane, const GLfixed *equation) {
+    CALL_GL_API(glClipPlanex, plane, equation);
+}
+void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
+    CALL_GL_API(glBindBuffer, target, buffer);
+}
+void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) {
+    CALL_GL_API(glBufferData, target, size, data, usage);
+}
+void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) {
+    CALL_GL_API(glBufferSubData, target, offset, size, data);
+}
+void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint* buffers) {
+    CALL_GL_API(glDeleteBuffers, n, buffers);
+}
+void API_ENTRY(glGenBuffers)(GLsizei n, GLuint* buffers) {
+    CALL_GL_API(glGenBuffers, n, buffers);
+}
+void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *params) {
+    CALL_GL_API(glGetBooleanv, pname, params);
+}
+void API_ENTRY(glGetFixedv)(GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetFixedv, pname, params);
+}
+void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetFloatv, pname, params);
+}
+void API_ENTRY(glGetPointerv)(GLenum pname, void **params) {
+    CALL_GL_API(glGetPointerv, pname, params);
+}
+void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) {
+    CALL_GL_API(glGetBufferParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetClipPlanef)(GLenum pname, GLfloat eqn[4]) {
+    CALL_GL_API(glGetClipPlanef, pname, eqn);
+}
+void API_ENTRY(glGetClipPlanex)(GLenum pname, GLfixed eqn[4]) {
+    CALL_GL_API(glGetClipPlanex, pname, eqn);
+}
+void API_ENTRY(glGetLightxv)(GLenum light, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetLightxv, light, pname, params);
+}
+void API_ENTRY(glGetLightfv)(GLenum light, GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetLightfv, light, pname, params);
+}
+void API_ENTRY(glGetMaterialxv)(GLenum face, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetMaterialxv, face, pname, params);
+}
+void API_ENTRY(glGetMaterialfv)(GLenum face, GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetMaterialfv, face, pname, params);
+}
+void API_ENTRY(glGetTexEnvfv)(GLenum env, GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetTexEnvfv, env, pname, params);
+}
+void API_ENTRY(glGetTexEnviv)(GLenum env, GLenum pname, GLint *params) {
+    CALL_GL_API(glGetTexEnviv, env, pname, params);
+}
+void API_ENTRY(glGetTexEnvxv)(GLenum env, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetTexEnvxv, env, pname, params);
+}
+void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint *params) {
+    CALL_GL_API(glGetTexParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetTexParameterxv)(GLenum target, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetTexParameterxv, target, pname, params);
+}
+GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) {
+    CALL_GL_API_RETURN(glIsBuffer, buffer);
+}
+GLboolean API_ENTRY(glIsEnabled)(GLenum cap) {
+    CALL_GL_API_RETURN(glIsEnabled, cap);
+}
+GLboolean API_ENTRY(glIsTexture)(GLuint texture) {
+    CALL_GL_API_RETURN(glIsTexture, texture);
+}
+void API_ENTRY(glPointParameterf)(GLenum pname, GLfloat param) {
+    CALL_GL_API(glPointParameterf, pname, param);
+}
+void API_ENTRY(glPointParameterfv)(GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glPointParameterfv, pname, params);
+}
+void API_ENTRY(glPointParameterx)(GLenum pname, GLfixed param) {
+    CALL_GL_API(glPointParameterx, pname, param);
+}
+void API_ENTRY(glPointParameterxv)(GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glPointParameterxv, pname, params);
+}
+void API_ENTRY(glColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) {
+    CALL_GL_API(glColor4ub, red, green, blue, alpha);
+}
+void API_ENTRY(glTexEnvi)(GLenum target, GLenum pname, GLint param) {
+    CALL_GL_API(glTexEnvi, target, pname, param);
+}
+void API_ENTRY(glTexEnviv)(GLenum target, GLenum pname, const GLint *params) {
+    CALL_GL_API(glTexEnviv, target, pname, params);
+}
+
+void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glTexParameterfv, target, pname, params);
+}
+
+void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) {
+    CALL_GL_API(glTexParameteriv, target, pname, params);
+}
+
+void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {
+    CALL_GL_API(glTexParameteri, target, pname, param);
+}
+void API_ENTRY(glTexParameterxv)(GLenum target, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glTexParameterxv, target, pname, params);
+}
+void API_ENTRY(glPointSizePointerOES)(GLenum type, GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glPointSizePointerOES, type, stride, pointer);
+}
+
+// Extensions
+void API_ENTRY(glDrawTexsOES)(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
+    CALL_GL_API(glDrawTexsOES, x, y, z, w, h);
+}
+void API_ENTRY(glDrawTexiOES)(GLint x, GLint y, GLint z, GLint w, GLint h) {
+    CALL_GL_API(glDrawTexiOES, x, y, z, w, h);
+}
+void API_ENTRY(glDrawTexfOES)(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h) {
+    CALL_GL_API(glDrawTexfOES, x, y, z, w, h);
+}
+void API_ENTRY(glDrawTexxOES)(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
+    CALL_GL_API(glDrawTexxOES, x, y, z, w, h);
+}
+void API_ENTRY(glDrawTexsvOES)(const GLshort* coords) {
+    CALL_GL_API(glDrawTexsvOES, coords);
+}
+void API_ENTRY(glDrawTexivOES)(const GLint* coords) {
+    CALL_GL_API(glDrawTexivOES, coords);
+}
+void API_ENTRY(glDrawTexfvOES)(const GLfloat* coords) {
+    CALL_GL_API(glDrawTexfvOES, coords);
+}
+void API_ENTRY(glDrawTexxvOES)(const GLfixed* coords) {
+    CALL_GL_API(glDrawTexxvOES, coords);
+}
+GLbitfield API_ENTRY(glQueryMatrixxOES)(GLfixed* mantissa, GLint* exponent) {
+    CALL_GL_API_RETURN(glQueryMatrixxOES, mantissa, exponent);
+}
diff --git a/opengl/libs/GLES_CM/gl_logger.cpp b/opengl/libs/GLES_CM/gl_logger.cpp
new file mode 100644
index 0000000..27be5c9
--- /dev/null
+++ b/opengl/libs/GLES_CM/gl_logger.cpp
@@ -0,0 +1,1060 @@
+/*
+ ** Copyright 2007, 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.
+ */
+
+#define LOG_TAG "GLLogger"
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+
+#include <sys/ioctl.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <cutils/properties.h>
+
+#include <utils/String8.h>
+
+#include "gl_logger.h"
+
+#undef NELEM
+#define NELEM(x) (sizeof(x)/sizeof(*(x)))
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+template<typename T>
+static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
+{
+   while (first <= last) {
+       int mid = (first + last) / 2;
+       if (key > sortedArray[mid].key) {
+           first = mid + 1;
+       } else if (key < sortedArray[mid].key) {
+           last = mid - 1;
+       } else {
+           return mid;
+       }
+   }
+   return -1;
+}
+
+struct pair_t {
+    const char* name;
+    int         key;
+};
+
+static const pair_t gEnumMap[] = {
+    #define GLENUM(NAME, VALUE) { #NAME, VALUE },
+    #include "gl_enums.in"
+    #undef GLENUM
+};
+
+// ----------------------------------------------------------------------------
+
+template<typename TYPE>
+class GLLogValue {
+public:
+    GLLogValue(TYPE value) : mValue(value) { }
+    const TYPE& getValue() const { return mValue; }
+    String8 toString() const {
+        return convertToString(mValue);
+    }
+private:
+    const TYPE& mValue;
+    String8 convertToString(unsigned int v) const {
+        char buf[16];
+        snprintf(buf, 16, "%u", v);
+        return String8(buf);
+    }
+    String8 convertToString(unsigned long v) const {
+        char buf[16];
+        snprintf(buf, 16, "%lu", v);
+        return String8(buf);
+    }
+    String8 convertToString(int v) const {
+        char buf[16];
+        snprintf(buf, 16, "%d", v);
+        return String8(buf);
+    }
+    String8 convertToString(long v) const {
+        char buf[16];
+        snprintf(buf, 16, "%ld", v);
+        return String8(buf);
+    }
+    String8 convertToString(float v) const {
+        char buf[16];
+        snprintf(buf, 16, "%f", v);
+        return String8(buf);
+    }
+    String8 convertToString(void const* v) const {
+        char buf[16];
+        snprintf(buf, 16, "%p", v);
+        return String8(buf);
+    }
+};
+
+class GLLogEnum : public GLLogValue<GLenum> {
+public:
+    GLLogEnum(GLenum v) : GLLogValue<GLenum>(v) { }
+    String8 toString() const {
+        GLenum v = getValue();
+        int i = binarySearch<pair_t>(gEnumMap, 0, NELEM(gEnumMap)-1, v);
+        if (i >= 0) {
+            return String8(gEnumMap[i].name);
+        } else {
+            char buf[16];
+            snprintf(buf, 16, "0x%04x", v);
+            return String8(buf);
+        }
+    }
+};
+
+class GLLogClearBitfield : public GLLogValue<GLbitfield> {
+public:
+    GLLogClearBitfield(GLbitfield v) : GLLogValue<GLbitfield>(v) { }
+    String8 toString() const {
+        char buf[16];
+        snprintf(buf, 16, "0x%08x", getValue());
+        return String8(buf);
+    }
+};
+
+class GLLogBool : public GLLogValue<GLboolean> {
+public:
+    GLLogBool(GLboolean v) : GLLogValue<GLboolean>(v) { }
+    String8 toString() const {
+        GLboolean v = getValue();
+        if (v == GL_TRUE)   return String8("GL_TRUE");
+        if (v == GL_FALSE)  return String8("GL_FALSE");
+        return GLLogValue<GLboolean>::toString();
+    }
+};
+
+class GLLogFixed : public GLLogValue<GLfixed> {
+public:
+    GLLogFixed(GLfixed v) : GLLogValue<GLfixed>(v) { }
+    String8 toString() const {
+        char buf[16];
+        snprintf(buf, 16, "0x%08x", getValue());
+        return String8(buf);
+    }
+};
+
+
+template <typename TYPE>
+class GLLogBuffer : public GLLogValue<TYPE *> {
+public:
+    GLLogBuffer(TYPE* buffer, size_t count = -1)
+        : GLLogValue<TYPE*>(buffer)
+    { // output buffer
+    }
+    GLLogBuffer(TYPE const* buffer, size_t count = -1)
+    : GLLogValue<TYPE*>(const_cast<TYPE*>(buffer))
+    { // input buffer
+    }
+};
+
+class GLLog
+{
+public:
+    GLLog(const char* name) : mNumParams(0) {
+        mString.append(name);
+        mString.append("(");
+    }
+
+    ~GLLog() {
+        LOGD("%s);", mString.string());
+    }
+
+    GLLog& operator << (unsigned char v) {
+        return *this << GLLogValue<unsigned int>(v);
+    }
+    GLLog& operator << (short v) {
+        return *this << GLLogValue<unsigned int>(v);
+    }
+    GLLog& operator << (unsigned int v) {
+        return *this << GLLogValue<unsigned int>(v);
+    }
+    GLLog& operator << (int v) {
+        return *this << GLLogValue<int>(v);
+    }
+    GLLog& operator << (long v) {
+        return *this << GLLogValue<long>(v);
+    }
+    GLLog& operator << (unsigned long v) {
+        return *this << GLLogValue<unsigned long>(v);
+    }
+    GLLog& operator << (float v) {
+        return *this << GLLogValue<float>(v);
+    }
+    GLLog& operator << (const void* v) {
+        return *this << GLLogValue<const void* >(v);
+    }
+
+    template <typename TYPE>
+    GLLog& operator << (const TYPE& rhs) {
+        if (mNumParams > 0)
+            mString.append(", ");
+        mString.append(rhs.toString());
+        mNumParams++;
+        return *this;
+    }
+
+    const String8& string() const { return mString; }
+private:
+    GLLog(const GLLog&);
+
+    String8 mString;
+    int mNumParams;
+};
+
+#define API_ENTRY(api)                      log_##api
+#define CALL_GL_API(_x, ...)
+#define CALL_GL_API_RETURN(_x, ...)         return(0);
+
+void API_ENTRY(glActiveTexture)(GLenum texture) {
+    CALL_GL_API(glActiveTexture, texture);
+    GLLog("glActiveTexture") << GLLogEnum(texture);
+}
+
+void API_ENTRY(glAlphaFunc)(GLenum func, GLclampf ref) {
+    CALL_GL_API(glAlphaFunc, func, ref);
+    GLLog("glAlphaFunc") << GLLogEnum(func) << ref;
+}
+
+void API_ENTRY(glAlphaFuncx)(GLenum func, GLclampx ref) {
+    CALL_GL_API(glAlphaFuncx, func, ref);
+    GLLog("glAlphaFuncx") << GLLogEnum(func) << GLLogFixed(ref);
+}
+
+void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
+    CALL_GL_API(glBindTexture, target, texture);
+    GLLog("glBindTexture") << GLLogEnum(target) << texture;
+}
+
+void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
+    CALL_GL_API(glBlendFunc, sfactor, dfactor);
+    GLLog("glBlendFunc") << GLLogEnum(sfactor) << GLLogEnum(dfactor);
+}
+
+void API_ENTRY(glClear)(GLbitfield mask) {
+    CALL_GL_API(glClear, mask);
+    GLLog("glClear") << GLLogClearBitfield(mask);
+}
+
+void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+    CALL_GL_API(glClearColor, red, green, blue, alpha);
+    GLLog("glClearColor") << red << green << blue << alpha;
+}
+
+void API_ENTRY(glClearColorx)(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) {
+    CALL_GL_API(glClearColorx, red, green, blue, alpha);
+    GLLog("glClearColorx") << GLLogFixed(red) << GLLogFixed(green) << GLLogFixed(blue) << GLLogFixed(alpha);
+}
+
+void API_ENTRY(glClearDepthf)(GLclampf depth) {
+    CALL_GL_API(glClearDepthf, depth);
+    GLLog("glClearDepthf") << depth;
+}
+
+void API_ENTRY(glClearDepthx)(GLclampx depth) {
+    CALL_GL_API(glClearDepthx, depth);
+    GLLog("glClearDepthx") << GLLogFixed(depth);
+}
+
+void API_ENTRY(glClearStencil)(GLint s) {
+    CALL_GL_API(glClearStencil, s);
+    GLLog("glClearStencil") << s;
+}
+
+void API_ENTRY(glClientActiveTexture)(GLenum texture) {
+    CALL_GL_API(glClientActiveTexture, texture);
+    GLLog("glClientActiveTexture") << GLLogEnum(texture);
+}
+
+void API_ENTRY(glColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
+    CALL_GL_API(glColor4f, red, green, blue, alpha);
+    GLLog("glColor4f") << red << green << blue << alpha;
+}
+
+void API_ENTRY(glColor4x)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) {
+    CALL_GL_API(glColor4x, red, green, blue, alpha);
+    GLLog("glColor4x") << GLLogFixed(red) << GLLogFixed(green) << GLLogFixed(blue) << GLLogFixed(alpha);
+}
+
+void API_ENTRY(glColorMask)(GLboolean r, GLboolean g, GLboolean b, GLboolean a) {
+    CALL_GL_API(glColorMask, r, g, b, a);
+    GLLog("glColorMask") << GLLogBool(r) << GLLogBool(g) << GLLogBool(b) << GLLogBool(a);
+}
+
+void API_ENTRY(glColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
+{
+    CALL_GL_API(glColorPointer, size, type, stride, ptr);
+    GLLog("glColorPointer") << size << GLLogEnum(type) << stride << ptr;
+}
+
+void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat,
+                            GLsizei width, GLsizei height, GLint border,
+                            GLsizei imageSize, const GLvoid *data) {
+    CALL_GL_API(glCompressedTexImage2D, target, level, internalformat,
+            width, height, border, imageSize, data);
+    GLLog("glCompressedTexImage2D")
+                << GLLogEnum(target) << level << GLLogEnum(internalformat)
+                << width << height << border << imageSize << data;
+}
+
+void API_ENTRY(glCompressedTexSubImage2D)( GLenum target, GLint level, GLint xoffset,
+                                GLint yoffset, GLsizei width, GLsizei height,
+                                GLenum format, GLsizei imageSize,
+                                const GLvoid *data) {
+    CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset,
+            width, height, format, imageSize, data);
+    GLLog("glCompressedTexSubImage2D")
+            << GLLogEnum(target) << level << xoffset << yoffset
+            << width << height << GLLogEnum(format) << imageSize << data;
+}
+
+void API_ENTRY(glCopyTexImage2D)(  GLenum target, GLint level, GLenum internalformat,
+                        GLint x, GLint y, GLsizei width, GLsizei height,
+                        GLint border) {
+    CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y,
+            width, height, border);
+    GLLog("glCopyTexImage2D")
+            << GLLogEnum(target) << level << GLLogEnum(internalformat)
+            << x << y << width << height << border;
+}
+
+void API_ENTRY(glCopyTexSubImage2D)(   GLenum target, GLint level, GLint xoffset,
+                            GLint yoffset, GLint x, GLint y, GLsizei width,
+                            GLsizei height) {
+    CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y,
+            width, height);
+    GLLog("glCopyTexSubImage2D")
+            << GLLogEnum(target) << level << xoffset << yoffset
+            << x << y << width << height;
+}
+
+void API_ENTRY(glCullFace)(GLenum mode) {
+    CALL_GL_API(glCullFace, mode);
+    GLLog("glCullFace") << GLLogEnum(mode);
+}
+
+void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint *textures) {
+    CALL_GL_API(glDeleteTextures, n, textures);
+    GLLog("glDeleteTextures") << n << GLLogBuffer<GLuint>(textures, n);
+}
+
+void API_ENTRY(glDepthFunc)(GLenum func) {
+    CALL_GL_API(glDepthFunc, func);
+    GLLog("glDepthFunc") << GLLogEnum(func);
+}
+
+void API_ENTRY(glDepthMask)(GLboolean flag) {
+    CALL_GL_API(glDepthMask, flag);
+    GLLog("glDepthMask") << GLLogBool(flag);
+}
+
+void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
+    CALL_GL_API(glDepthRangef, zNear, zFar);
+    GLLog("glDepthRangef") << zNear << zFar;
+}
+
+void API_ENTRY(glDepthRangex)(GLclampx zNear, GLclampx zFar) {
+    CALL_GL_API(glDepthRangex, zNear, zFar);
+    GLLog("glDepthRangex") << GLLogFixed(zNear) << GLLogFixed(zFar);
+}
+
+void API_ENTRY(glDisable)(GLenum cap) {
+    CALL_GL_API(glDisable, cap);
+    GLLog("glDisable") << GLLogEnum(cap);
+}
+
+void API_ENTRY(glDisableClientState)(GLenum array) {
+    CALL_GL_API(glDisableClientState, array);
+    GLLog("glDisableClientState") << GLLogEnum(array);
+}
+
+void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
+    CALL_GL_API(glDrawArrays, mode, first, count);
+    GLLog("glDrawArrays") << GLLogEnum(mode) << first << count;
+}
+
+void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count,
+                    GLenum type, const GLvoid *indices) {
+    CALL_GL_API(glDrawElements, mode, count, type, indices);
+    GLLog log("glDrawElements");
+    log << GLLogEnum(mode) << count << GLLogEnum(type);
+    if (type == GL_UNSIGNED_BYTE) {
+        log << GLLogBuffer<GLubyte>(static_cast<const GLubyte*>(indices), count);
+    } else {
+        log << GLLogBuffer<GLushort>(static_cast<const GLushort*>(indices), count);
+    }
+    log;
+}
+
+void API_ENTRY(glEnable)(GLenum cap) {
+    CALL_GL_API(glEnable, cap);
+    GLLog("glEnable") << GLLogEnum(cap);
+}
+
+void API_ENTRY(glEnableClientState)(GLenum array) {
+    CALL_GL_API(glEnableClientState, array);
+    GLLog("glEnableClientState") << GLLogEnum(array);
+}
+
+void API_ENTRY(glFinish)(void) {
+    CALL_GL_API(glFinish);
+    GLLog("glFinish");
+}
+
+void API_ENTRY(glFlush)(void) {
+    CALL_GL_API(glFlush);
+    GLLog("glFlush");
+}
+
+void API_ENTRY(glFogf)(GLenum pname, GLfloat param) {
+    CALL_GL_API(glFogf, pname, param);
+    GLLog("glFogf") << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glFogfv)(GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glFogfv, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glFogfv") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+
+void API_ENTRY(glFogx)(GLenum pname, GLfixed param) {
+    CALL_GL_API(glFogx, pname, param);
+    GLLog("glFogx") << GLLogEnum(pname) << GLLogFixed(param);
+}
+
+void API_ENTRY(glFogxv)(GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glFogxv, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glFogfx") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+
+void API_ENTRY(glFrontFace)(GLenum mode) {
+    CALL_GL_API(glFrontFace, mode);
+    GLLog("glFrontFace") << GLLogEnum(mode);
+ }
+
+void API_ENTRY(glFrustumf)(GLfloat left, GLfloat right,
+                GLfloat bottom, GLfloat top,
+                GLfloat zNear, GLfloat zFar) {
+    CALL_GL_API(glFrustumf, left, right, bottom, top, zNear, zFar);
+    GLLog("glFrustumf") << left << right << bottom << top << zNear << zFar;
+}
+
+void API_ENTRY(glFrustumx)(GLfixed left, GLfixed right,
+                GLfixed bottom, GLfixed top,
+                GLfixed zNear, GLfixed zFar) {
+    CALL_GL_API(glFrustumx, left, right, bottom, top, zNear, zFar);
+    GLLog("glFrustumx")
+            << GLLogFixed(left) << GLLogFixed(right)
+            << GLLogFixed(bottom) << GLLogFixed(top)
+            << GLLogFixed(zNear) << GLLogFixed(zFar);
+}
+
+void API_ENTRY(glGenTextures)(GLsizei n, GLuint *textures) {
+    CALL_GL_API(glGenTextures, n, textures);
+    GLLog("glGenTextures") << n << GLLogBuffer<GLuint>(textures, n);
+}
+
+GLenum API_ENTRY(glGetError)(void) {
+    GLLog("glGetError");
+    CALL_GL_API_RETURN(glGetError);
+}
+
+void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *params) {
+    CALL_GL_API(glGetIntegerv, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetIntegerv") << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
+}
+
+const GLubyte * API_ENTRY(glGetString)(GLenum name) {
+    GLLog("glGetString") << GLLogEnum(name);
+    CALL_GL_API_RETURN(glGetString, name);
+}
+
+void API_ENTRY(glHint)(GLenum target, GLenum mode) {
+    CALL_GL_API(glHint, target, mode);
+    GLLog("GLenum") << GLLogEnum(target) << GLLogEnum(mode);
+}
+
+void API_ENTRY(glLightModelf)(GLenum pname, GLfloat param) {
+    CALL_GL_API(glLightModelf, pname, param);
+    GLLog("glLightModelf") << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glLightModelfv)(GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glLightModelfv, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glLightModelfv") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+
+void API_ENTRY(glLightModelx)(GLenum pname, GLfixed param) {
+    CALL_GL_API(glLightModelx, pname, param);
+    GLLog("glLightModelx") << GLLogEnum(pname) << GLLogFixed(param);
+}
+
+void API_ENTRY(glLightModelxv)(GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glLightModelxv, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glLightModelxv") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+
+void API_ENTRY(glLightf)(GLenum light, GLenum pname, GLfloat param) {
+    CALL_GL_API(glLightf, light, pname, param);
+    GLLog("glLightf") << GLLogEnum(light) << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glLightfv)(GLenum light, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glLightfv, light, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glLightfv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+
+void API_ENTRY(glLightx)(GLenum light, GLenum pname, GLfixed param) {
+   CALL_GL_API(glLightx, light, pname, param);
+   GLLog("glLightx") << GLLogEnum(light) << GLLogEnum(pname) << GLLogFixed(param);
+}
+
+void API_ENTRY(glLightxv)(GLenum light, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glLightxv, light, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glLightxv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+
+void API_ENTRY(glLineWidth)(GLfloat width) {
+    CALL_GL_API(glLineWidth, width);
+    GLLog("glLineWidth") << width;
+}
+
+void API_ENTRY(glLineWidthx)(GLfixed width) {
+    CALL_GL_API(glLineWidthx, width);
+    GLLog("glLineWidth") << GLLogFixed(width);
+}
+
+void API_ENTRY(glLoadIdentity)(void) {
+    CALL_GL_API(glLoadIdentity);
+    GLLog("glLoadIdentity");
+}
+
+void API_ENTRY(glLoadMatrixf)(const GLfloat *m) {
+    CALL_GL_API(glLoadMatrixf, m);
+    GLLog("glLoadMatrixf") << GLLogBuffer<GLfloat>(m, 16);
+}
+
+void API_ENTRY(glLoadMatrixx)(const GLfixed *m) {
+    CALL_GL_API(glLoadMatrixx, m);
+    GLLog("glLoadMatrixx") << GLLogBuffer<GLfixed>(m, 16);
+}
+
+void API_ENTRY(glLogicOp)(GLenum opcode) {
+    CALL_GL_API(glLogicOp, opcode);
+    GLLog("glLogicOp") << GLLogEnum(opcode);
+}
+
+void API_ENTRY(glMaterialf)(GLenum face, GLenum pname, GLfloat param) {
+    CALL_GL_API(glMaterialf, face, pname, param);
+    GLLog("glMaterialf") << GLLogEnum(face) << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glMaterialfv)(GLenum face, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glMaterialfv, face, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glMaterialfv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+
+void API_ENTRY(glMaterialx)(GLenum face, GLenum pname, GLfixed param) {
+    CALL_GL_API(glMaterialx, face, pname, param);
+    GLLog("glMaterialx") << GLLogEnum(face) << GLLogEnum(pname) << GLLogFixed(param);
+}
+
+void API_ENTRY(glMaterialxv)(GLenum face, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glMaterialxv, face, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glMaterialxv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+
+void API_ENTRY(glMatrixMode)(GLenum mode) {
+    CALL_GL_API(glMatrixMode, mode);
+    GLLog("glMatrixMode") << GLLogEnum(mode);
+}
+
+void API_ENTRY(glMultMatrixf)(const GLfloat *m) {
+    CALL_GL_API(glMultMatrixf, m);
+    GLLog("glMultMatrixf") << GLLogBuffer<GLfloat>(m, 16);
+}
+
+void API_ENTRY(glMultMatrixx)(const GLfixed *m) {
+    CALL_GL_API(glMultMatrixx, m);
+    GLLog("glMultMatrixx") << GLLogBuffer<GLfixed>(m, 16);
+}
+
+void API_ENTRY(glMultiTexCoord4f)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) {
+    CALL_GL_API(glMultiTexCoord4f, target, s, t, r, q);
+    GLLog("glMultiTexCoord4f") << GLLogEnum(target) << s << t << r << q;
+}
+
+void API_ENTRY(glMultiTexCoord4x)(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) {
+    CALL_GL_API(glMultiTexCoord4x, target, s, t, r, q);
+    GLLog("glMultiTexCoord4x") << GLLogEnum(target)
+        << GLLogFixed(s) << GLLogFixed(t) << GLLogFixed(r) << GLLogFixed(q);
+}
+
+void API_ENTRY(glNormal3f)(GLfloat nx, GLfloat ny, GLfloat nz) {
+    CALL_GL_API(glNormal3f, nx, ny, nz);
+    GLLog("glNormal3f") << nx << ny << nz;
+}
+
+void API_ENTRY(glNormal3x)(GLfixed nx, GLfixed ny, GLfixed nz) {
+    CALL_GL_API(glNormal3x, nx, ny, nz);
+    GLLog("glNormal3x") << GLLogFixed(nx) << GLLogFixed(ny) << GLLogFixed(nz);
+}
+
+void API_ENTRY(glNormalPointer)(GLenum type, GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glNormalPointer, type, stride, pointer);
+    GLLog("glNormalPointer") << GLLogEnum(type) << stride << pointer;
+}
+
+void API_ENTRY(glOrthof)(  GLfloat left, GLfloat right,
+                GLfloat bottom, GLfloat top,
+                GLfloat zNear, GLfloat zFar) {
+    CALL_GL_API(glOrthof, left, right, bottom, top, zNear, zFar);
+    GLLog("glOrthof") << left << right << bottom << top << zNear << zFar;
+}
+
+void API_ENTRY(glOrthox)(  GLfixed left, GLfixed right,
+                GLfixed bottom, GLfixed top,
+                GLfixed zNear, GLfixed zFar) {
+    CALL_GL_API(glOrthox, left, right, bottom, top, zNear, zFar);
+    GLLog("glOrthox") << GLLogFixed(left) << GLLogFixed(right)
+            << GLLogFixed(bottom) << GLLogFixed(top)
+            << GLLogFixed(zNear) << GLLogFixed(zFar);
+}
+
+void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
+    CALL_GL_API(glPixelStorei, pname, param);
+    GLLog("glPixelStorei") << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glPointSize)(GLfloat size) {
+    CALL_GL_API(glPointSize, size);
+    GLLog("glPointSize") << size;
+}
+
+void API_ENTRY(glPointSizex)(GLfixed size) {
+    CALL_GL_API(glPointSizex, size);
+    GLLog("glPointSizex") << GLLogFixed(size);
+}
+
+void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
+    CALL_GL_API(glPolygonOffset, factor, units);
+    GLLog("glPolygonOffset") << factor << units;
+}
+
+void API_ENTRY(glPolygonOffsetx)(GLfixed factor, GLfixed units) {
+    CALL_GL_API(glPolygonOffsetx, factor, units);
+    GLLog("glPolygonOffsetx") << GLLogFixed(factor) << GLLogFixed(units);
+}
+
+void API_ENTRY(glPopMatrix)(void) {
+    CALL_GL_API(glPopMatrix);
+    GLLog("glPopMatrix");
+}
+
+void API_ENTRY(glPushMatrix)(void) {
+    CALL_GL_API(glPushMatrix);
+    GLLog("glPushMatrix");
+}
+
+void API_ENTRY(glReadPixels)(  GLint x, GLint y, GLsizei width, GLsizei height,
+                    GLenum format, GLenum type, GLvoid *pixels) {
+    CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glReadPixels") << x << y << width << height << GLLogEnum(format) << GLLogEnum(type)
+            << GLLogBuffer<unsigned char>(static_cast<unsigned char *>(pixels));
+}
+
+void API_ENTRY(glRotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glRotatef, angle, x, y, z);
+    GLLog("glRotatef") << angle << x << y << z;
+}
+
+void API_ENTRY(glRotatex)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) {
+    CALL_GL_API(glRotatex, angle, x, y, z);
+    GLLog("glRotatex") << GLLogFixed(angle) << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z);
+}
+
+void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
+    CALL_GL_API(glSampleCoverage, value, invert);
+    GLLog("glSampleCoverage") << value << GLLogBool(invert);
+}
+
+void API_ENTRY(glSampleCoveragex)(GLclampx value, GLboolean invert) {
+    CALL_GL_API(glSampleCoveragex, value, invert);
+    GLLog("glSampleCoveragex") << GLLogFixed(value) << GLLogBool(invert);
+}
+
+void API_ENTRY(glScalef)(GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glScalef, x, y, z);
+    GLLog("glScalef") << x << y << z;
+}
+
+void API_ENTRY(glScalex)(GLfixed x, GLfixed y, GLfixed z) {
+    CALL_GL_API(glScalex, x, y, z);
+    GLLog("glScalex") << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z);
+}
+
+void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
+    CALL_GL_API(glScissor, x, y, width, height);
+    GLLog("glScissor") << x << y << width << height;
+}
+
+void API_ENTRY(glShadeModel)(GLenum mode) {
+    CALL_GL_API(glShadeModel, mode);
+    GLLog("glShadeModel") << GLLogEnum(mode);
+}
+
+void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
+    CALL_GL_API(glStencilFunc, func, ref, mask);
+    GLLog("glStencilFunc") << GLLogEnum(func) << ref << mask;
+}
+
+void API_ENTRY(glStencilMask)(GLuint mask) {
+    CALL_GL_API(glStencilMask, mask);
+    GLLog("glStencilMask") << mask;
+}
+
+void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
+    CALL_GL_API(glStencilOp, fail, zfail, zpass);
+    GLLog("glStencilOp") << GLLogEnum(fail) << GLLogEnum(zfail) << GLLogEnum(zpass);
+}
+
+void API_ENTRY(glTexCoordPointer)( GLint size, GLenum type,
+                        GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glTexCoordPointer, size, type, stride, pointer);
+    GLLog("glTexCoordPointer") << size << GLLogEnum(type) << stride << pointer;
+}
+
+void API_ENTRY(glTexEnvf)(GLenum target, GLenum pname, GLfloat param) {
+    CALL_GL_API(glTexEnvf, target, pname, param);
+    GLLog("glTexEnvf") << GLLogEnum(target) << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glTexEnvfv)(GLenum target, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glTexEnvfv, target, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glTexEnvx") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+
+void API_ENTRY(glTexEnvx)(GLenum target, GLenum pname, GLfixed param) {
+    CALL_GL_API(glTexEnvx, target, pname, param);
+    GLLog("glTexEnvx") << GLLogEnum(target) << GLLogEnum(pname) << GLLogFixed(param);
+}
+
+void API_ENTRY(glTexEnvxv)(GLenum target, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glTexEnvxv, target, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glTexEnvxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+
+void API_ENTRY(glTexImage2D)(  GLenum target, GLint level, GLint internalformat,
+                    GLsizei width, GLsizei height, GLint border, GLenum format,
+                    GLenum type, const GLvoid *pixels) {
+    CALL_GL_API(glTexImage2D, target, level, internalformat, width, height,
+            border, format, type, pixels);
+    GLLog("glTexImage2D") << GLLogEnum(target) << level << GLLogEnum(internalformat)
+            << width << height << border << GLLogEnum(format) << GLLogEnum(type)
+            << GLLogBuffer<unsigned char>( static_cast<const unsigned char *>(pixels));
+}
+
+void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
+    CALL_GL_API(glTexParameterf, target, pname, param);
+    GLLog("glTexParameterf") << GLLogEnum(target) << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glTexParameterx)(GLenum target, GLenum pname, GLfixed param) {
+    CALL_GL_API(glTexParameterx, target, pname, param);
+    GLLog("glTexParameterx") << GLLogEnum(target) << GLLogEnum(pname) << GLLogFixed(param);
+}
+
+void API_ENTRY(glTexSubImage2D)(   GLenum target, GLint level, GLint xoffset,
+                        GLint yoffset, GLsizei width, GLsizei height,
+                        GLenum format, GLenum type, const GLvoid *pixels) {
+    CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset,
+            width, height, format, type, pixels);
+    GLLog("glTexSubImage2D") << GLLogEnum(target) << level << xoffset << yoffset
+            << width << height << GLLogEnum(format) << GLLogEnum(type)
+            << GLLogBuffer<unsigned char>( static_cast<const unsigned char *>(pixels));
+}
+
+void API_ENTRY(glTranslatef)(GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glTranslatef, x, y, z);
+    GLLog("glTranslatef") << x << y << z;
+}
+
+void API_ENTRY(glTranslatex)(GLfixed x, GLfixed y, GLfixed z) {
+    CALL_GL_API(glTranslatex, x, y, z);
+    GLLog("glTranslatex") << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z);
+}
+
+void API_ENTRY(glVertexPointer)(   GLint size, GLenum type,
+                        GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glVertexPointer, size, type, stride, pointer);
+    GLLog("glVertexPointer") << size << GLLogEnum(type) << stride << pointer;
+}
+
+void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
+    CALL_GL_API(glViewport, x, y, width, height);
+    GLLog("glViewport") << x << y << width << height;
+}
+
+// ES 1.1
+void API_ENTRY(glClipPlanef)(GLenum plane, const GLfloat *equation) {
+    CALL_GL_API(glClipPlanef, plane, equation);
+    GLLog("glClipPlanef") << GLLogEnum(plane) << GLLogBuffer<GLfloat>(equation, 4);
+}
+void API_ENTRY(glClipPlanex)(GLenum plane, const GLfixed *equation) {
+    CALL_GL_API(glClipPlanex, plane, equation);
+    GLLog("glClipPlanex") << GLLogEnum(plane) << GLLogBuffer<GLfixed>(equation, 4);
+}
+void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
+    CALL_GL_API(glBindBuffer, target, buffer);
+    GLLog("glBindBuffer") << GLLogEnum(target) << buffer;
+}
+void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) {
+    CALL_GL_API(glBufferData, target, size, data, usage);
+    GLLog("glBufferData") << GLLogEnum(target) << size
+        << GLLogBuffer<unsigned char>(static_cast<const unsigned char*>(data), size);
+}
+void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) {
+    CALL_GL_API(glBufferSubData, target, offset, size, data);
+    GLLog("glBufferSubData") << GLLogEnum(target) << offset << size
+        << GLLogBuffer<unsigned char>(static_cast<const unsigned char*>(data), size);
+}
+void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint* buffers) {
+    CALL_GL_API(glDeleteBuffers, n, buffers);
+    GLLog("glDeleteBuffers") << n << GLLogBuffer<GLuint>(buffers, n);
+}
+void API_ENTRY(glGenBuffers)(GLsizei n, GLuint* buffers) {
+    CALL_GL_API(glGenBuffers, n, buffers);
+    GLLog("glGenBuffers") << n << GLLogBuffer<GLuint>(buffers, n);
+}
+void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *params) {
+    CALL_GL_API(glGetBooleanv, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetBooleanv") << GLLogEnum(pname) << GLLogBuffer<GLboolean>(params);
+}
+void API_ENTRY(glGetFixedv)(GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetFixedv, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetFixedv") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetFloatv, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetFloatv") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+void API_ENTRY(glGetPointerv)(GLenum pname, void **params) {
+    CALL_GL_API(glGetPointerv, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetPointerv") << GLLogEnum(pname) << GLLogBuffer<void*>(params);
+}
+void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) {
+    // XXX: we need to compute the size of this buffer
+    CALL_GL_API(glGetBufferParameteriv, target, pname, params);
+    GLLog("glGetBufferParameteriv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
+}
+void API_ENTRY(glGetClipPlanef)(GLenum pname, GLfloat eqn[4]) {
+    CALL_GL_API(glGetClipPlanef, pname, eqn);
+    GLLog("glGetClipPlanef") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(eqn, 4);
+}
+void API_ENTRY(glGetClipPlanex)(GLenum pname, GLfixed eqn[4]) {
+    CALL_GL_API(glGetClipPlanex, pname, eqn);
+    GLLog("glGetClipPlanex") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(eqn, 4);
+}
+void API_ENTRY(glGetLightxv)(GLenum light, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetLightxv, light, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetLightxv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+void API_ENTRY(glGetLightfv)(GLenum light, GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetLightfv, light, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetLightfv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+void API_ENTRY(glGetMaterialxv)(GLenum face, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetMaterialxv, face, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetMaterialxv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+void API_ENTRY(glGetMaterialfv)(GLenum face, GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetMaterialfv, face, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetMaterialfv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+void API_ENTRY(glGetTexEnvfv)(GLenum env, GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetTexEnvfv, env, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetTexEnvfv") << GLLogEnum(env) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+void API_ENTRY(glGetTexEnviv)(GLenum env, GLenum pname, GLint *params) {
+    CALL_GL_API(glGetTexEnviv, env, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetTexEnviv") << GLLogEnum(env) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
+}
+void API_ENTRY(glGetTexEnvxv)(GLenum env, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetTexEnvxv, env, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetTexEnvxv") << GLLogEnum(env) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetTexParameterfv, target, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetTexParameterfv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint *params) {
+    CALL_GL_API(glGetTexParameteriv, target, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetTexParameteriv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
+}
+void API_ENTRY(glGetTexParameterxv)(GLenum target, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetTexParameterxv, target, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glGetTexParameterxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) {
+    GLLog("glIsBuffer") << buffer;
+    CALL_GL_API_RETURN(glIsBuffer, buffer);
+}
+GLboolean API_ENTRY(glIsEnabled)(GLenum cap) {
+    GLLog("glIsEnabled") << GLLogEnum(cap);
+    CALL_GL_API_RETURN(glIsEnabled, cap);
+}
+GLboolean API_ENTRY(glIsTexture)(GLuint texture) {
+    GLLog("glIsTexture") << texture;
+    CALL_GL_API_RETURN(glIsTexture, texture);
+}
+void API_ENTRY(glPointParameterf)(GLenum pname, GLfloat param) {
+    CALL_GL_API(glPointParameterf, pname, param);
+    GLLog("glPointParameterf") << GLLogEnum(pname) << param;
+}
+void API_ENTRY(glPointParameterfv)(GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glPointParameterfv, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glPointParameterfv") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+void API_ENTRY(glPointParameterx)(GLenum pname, GLfixed param) {
+    CALL_GL_API(glPointParameterx, pname, param);
+    GLLog("glPointParameterx") << GLLogEnum(pname) << GLLogFixed(param);
+}
+void API_ENTRY(glPointParameterxv)(GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glPointParameterxv, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glPointParameterxv") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+void API_ENTRY(glColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) {
+    CALL_GL_API(glColor4ub, red, green, blue, alpha);
+    GLLog("glColor4ub") << red << green << blue << alpha;
+}
+void API_ENTRY(glTexEnvi)(GLenum target, GLenum pname, GLint param) {
+    CALL_GL_API(glTexEnvi, target, pname, param);
+    GLLog("glTexEnvi") << GLLogEnum(target) << GLLogEnum(pname) << param;
+}
+void API_ENTRY(glTexEnviv)(GLenum target, GLenum pname, const GLint *params) {
+    CALL_GL_API(glTexEnviv, target, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glTexEnviv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
+}
+
+void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glTexParameterfv, target, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glTexParameterfv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+
+void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) {
+    CALL_GL_API(glTexParameteriv, target, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glTexParameteriv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
+}
+
+void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {
+    CALL_GL_API(glTexParameteri, target, pname, param);
+    GLLog("glTexParameteri") << GLLogEnum(target) << GLLogEnum(pname) << param;
+}
+void API_ENTRY(glTexParameterxv)(GLenum target, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glTexParameterxv, target, pname, params);
+    // XXX: we need to compute the size of this buffer
+    GLLog("glTexParameterxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+void API_ENTRY(glPointSizePointerOES)(GLenum type, GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glPointSizePointerOES, type, stride, pointer);
+    GLLog("glPointSizePointerOES") << GLLogEnum(type) << stride << pointer;
+}
+
+// Extensions
+void API_ENTRY(glDrawTexsOES)(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
+    CALL_GL_API(glDrawTexsOES, x, y, z, w, h);
+    GLLog("glDrawTexsOES") << x << y << z << w << h;
+}
+void API_ENTRY(glDrawTexiOES)(GLint x, GLint y, GLint z, GLint w, GLint h) {
+    CALL_GL_API(glDrawTexiOES, x, y, z, w, h);
+    GLLog("glDrawTexiOES") << x << y << z << w << h;
+}
+void API_ENTRY(glDrawTexfOES)(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h) {
+    CALL_GL_API(glDrawTexfOES, x, y, z, w, h);
+    GLLog("glDrawTexfOES") << x << y << z << w << h;
+}
+void API_ENTRY(glDrawTexxOES)(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
+    CALL_GL_API(glDrawTexxOES, x, y, z, w, h);
+    GLLog("glDrawTexfOES") << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z) << GLLogFixed(w) << GLLogFixed(h);
+}
+void API_ENTRY(glDrawTexsvOES)(const GLshort* coords) {
+    CALL_GL_API(glDrawTexsvOES, coords);
+    GLLog("glDrawTexsvOES") << GLLogBuffer<GLshort>(coords, 5);
+}
+void API_ENTRY(glDrawTexivOES)(const GLint* coords) {
+    CALL_GL_API(glDrawTexivOES, coords);
+    GLLog("glDrawTexivOES") << GLLogBuffer<GLint>(coords, 5);
+}
+void API_ENTRY(glDrawTexfvOES)(const GLfloat* coords) {
+    CALL_GL_API(glDrawTexfvOES, coords);
+    GLLog("glDrawTexfvOES") << GLLogBuffer<GLfloat>(coords, 5);
+}
+void API_ENTRY(glDrawTexxvOES)(const GLfixed* coords) {
+    CALL_GL_API(glDrawTexxvOES, coords);
+    GLLog("glDrawTexxvOES") << GLLogBuffer<GLfixed>(coords, 5);
+}
+GLbitfield API_ENTRY(glQueryMatrixxOES)(GLfixed* mantissa, GLint* exponent) {
+    GLLog("glQueryMatrixxOES") << GLLogBuffer<GLfixed>(mantissa, 16) << GLLogBuffer<GLfixed>(exponent, 16);
+    CALL_GL_API_RETURN(glQueryMatrixxOES, mantissa, exponent);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/opengl/libs/egl_entries.in b/opengl/libs/egl_entries.in
new file mode 100644
index 0000000..33b4c65
--- /dev/null
+++ b/opengl/libs/egl_entries.in
@@ -0,0 +1,45 @@
+EGL_ENTRY(EGLDisplay, eglGetDisplay, NativeDisplayType)
+EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*)
+EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay)
+EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*)
+EGL_ENTRY(EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)
+
+EGL_ENTRY(EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint *)
+EGL_ENTRY(EGLSurface, eglCreateWindowSurface, EGLDisplay, EGLConfig, NativeWindowType, const EGLint *)
+EGL_ENTRY(EGLSurface, eglCreatePixmapSurface, EGLDisplay, EGLConfig, NativePixmapType, const EGLint *)
+EGL_ENTRY(EGLSurface, eglCreatePbufferSurface,  EGLDisplay, EGLConfig, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroySurface, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLBoolean, eglQuerySurface,  EGLDisplay, EGLSurface, EGLint, EGLint *)
+EGL_ENTRY(EGLContext, eglCreateContext, EGLDisplay, EGLConfig, EGLContext, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroyContext, EGLDisplay, EGLContext)
+EGL_ENTRY(EGLBoolean, eglMakeCurrent, EGLDisplay, EGLSurface, EGLSurface, EGLContext)
+EGL_ENTRY(EGLContext, eglGetCurrentContext, void)
+EGL_ENTRY(EGLSurface, eglGetCurrentSurface, EGLint)
+EGL_ENTRY(EGLDisplay, eglGetCurrentDisplay, void)
+EGL_ENTRY(EGLBoolean, eglQueryContext,  EGLDisplay, EGLContext, EGLint, EGLint *)
+EGL_ENTRY(EGLBoolean, eglWaitGL, void)
+EGL_ENTRY(EGLBoolean, eglWaitNative, EGLint)
+EGL_ENTRY(EGLBoolean, eglSwapBuffers, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLBoolean, eglCopyBuffers, EGLDisplay, EGLSurface, NativePixmapType)
+EGL_ENTRY(EGLint, eglGetError, void)
+EGL_ENTRY(const char*, eglQueryString, EGLDisplay, EGLint)
+EGL_ENTRY(__eglMustCastToProperFunctionPointerType, eglGetProcAddress, const char *)
+
+/* EGL 1.1 */
+
+EGL_ENTRY(EGLBoolean, eglSurfaceAttrib, EGLDisplay, EGLSurface, EGLint, EGLint)
+EGL_ENTRY(EGLBoolean, eglBindTexImage, EGLDisplay, EGLSurface, EGLint)
+EGL_ENTRY(EGLBoolean, eglReleaseTexImage, EGLDisplay, EGLSurface, EGLint)
+EGL_ENTRY(EGLBoolean, eglSwapInterval, EGLDisplay, EGLint)
+
+/* EGL 1.2 */
+
+EGL_ENTRY(EGLBoolean, eglBindAPI, EGLenum)
+EGL_ENTRY(EGLenum, eglQueryAPI, void)
+EGL_ENTRY(EGLBoolean, eglWaitClient, void)
+EGL_ENTRY(EGLBoolean, eglReleaseThread, void)
+EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGLClientBuffer, EGLConfig, const EGLint *)
+
+/* EGL 1.3 */
+
+/* EGL 1.4 */
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
new file mode 100644
index 0000000..62ce3fc
--- /dev/null
+++ b/opengl/libs/egl_impl.h
@@ -0,0 +1,43 @@
+/* 
+ ** Copyright 2007, 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.
+ */
+
+#ifndef ANDROID_EGL_IMPL_H
+#define ANDROID_EGL_IMPL_H
+
+#include <ctype.h>
+
+#include <EGL/egl.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+struct gl_hooks_t;
+
+struct egl_connection_t
+{
+    void volatile *     dso;
+    gl_hooks_t *        hooks;
+    EGLint              major;
+    EGLint              minor;
+    int                 unavailable;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_EGL_IMPL_H */
diff --git a/opengl/libs/gl_entries.in b/opengl/libs/gl_entries.in
new file mode 100644
index 0000000..b97e8fe
--- /dev/null
+++ b/opengl/libs/gl_entries.in
@@ -0,0 +1,159 @@
+GL_ENTRY(void, glColor4f, GLfloat, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glColor4x, GLfixed, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glNormal3f, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glNormal3x, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glCullFace, GLenum)
+GL_ENTRY(void, glFrontFace, GLenum)
+GL_ENTRY(void, glDisable, GLenum)
+GL_ENTRY(void, glEnable, GLenum)
+GL_ENTRY(void, glFinish, void)
+GL_ENTRY(void, glFlush, void)
+GL_ENTRY(GLenum, glGetError, void)
+GL_ENTRY(const GLubyte*, glGetString, GLenum)
+GL_ENTRY(void, glGetIntegerv, GLenum, GLint *)
+GL_ENTRY(void, glColorMask, GLboolean, GLboolean, GLboolean, GLboolean)
+GL_ENTRY(void, glDepthMask, GLboolean)
+GL_ENTRY(void, glStencilMask, GLuint)
+GL_ENTRY(void, glDepthFunc, GLenum)
+GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glDepthRangex, GLclampx zNear, GLclampx zFar)
+GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
+GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glLogicOp, GLenum opcode)
+GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref)
+GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref)
+GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
+GL_ENTRY(void, glClear, GLbitfield mask)
+GL_ENTRY(void, glClearColor, GLclampf r, GLclampf g, GLclampf b, GLclampf a)
+GL_ENTRY(void, glClearColorx, GLclampx r, GLclampx g, GLclampx b, GLclampx a)
+GL_ENTRY(void, glClearDepthf, GLclampf depth)
+GL_ENTRY(void, glClearDepthx, GLclampx depth)
+GL_ENTRY(void, glClearStencil, GLint s)
+GL_ENTRY(void, glPointSize, GLfloat)
+GL_ENTRY(void, glPointSizex, GLfixed)
+GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert)
+GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glHint, GLenum, GLenum mode)
+GL_ENTRY(void, glLineWidth, GLfloat width)
+GL_ENTRY(void, glLineWidthx, GLfixed width)
+GL_ENTRY(void, glShadeModel, GLenum)
+GL_ENTRY(void, glLightModelf, GLenum, GLfloat)
+GL_ENTRY(void, glLightModelfv, GLenum, const GLfloat *)
+GL_ENTRY(void, glLightModelx, GLenum, GLfixed)
+GL_ENTRY(void, glLightModelxv, GLenum, const GLfixed *)
+GL_ENTRY(void, glLightf, GLenum, GLenum, GLfloat)
+GL_ENTRY(void, glLightfv, GLenum, GLenum, const GLfloat *)
+GL_ENTRY(void, glLightx, GLenum, GLenum, GLfixed)
+GL_ENTRY(void, glLightxv, GLenum, GLenum, const GLfixed *)
+GL_ENTRY(void, glMaterialf, GLenum, GLenum, GLfloat)
+GL_ENTRY(void, glMaterialfv, GLenum, GLenum, const GLfloat *)
+GL_ENTRY(void, glMaterialx, GLenum, GLenum, GLfixed)
+GL_ENTRY(void, glMaterialxv, GLenum, GLenum, const GLfixed *)
+GL_ENTRY(void, glFogf, GLenum, GLfloat)
+GL_ENTRY(void, glFogfv, GLenum, const GLfloat *)
+GL_ENTRY(void, glFogx, GLenum, GLfixed)
+GL_ENTRY(void, glFogxv, GLenum, const GLfixed *)
+GL_ENTRY(void, glVertexPointer, GLint, GLenum, GLsizei, const GLvoid *)
+GL_ENTRY(void, glColorPointer, GLint, GLenum, GLsizei, const GLvoid *)
+GL_ENTRY(void, glNormalPointer, GLenum, GLsizei, const GLvoid *)
+GL_ENTRY(void, glTexCoordPointer, GLint, GLenum, GLsizei, const GLvoid *)
+GL_ENTRY(void, glEnableClientState, GLenum)
+GL_ENTRY(void, glDisableClientState, GLenum)
+GL_ENTRY(void, glClientActiveTexture, GLenum)
+GL_ENTRY(void, glDrawArrays, GLenum, GLint first, GLsizei)
+GL_ENTRY(void, glDrawElements, GLenum, GLsizei, GLenum, const GLvoid *)
+GL_ENTRY(void, glLoadIdentity, void)
+GL_ENTRY(void, glLoadMatrixf, const GLfloat*)
+GL_ENTRY(void, glLoadMatrixx, const GLfixed*)
+GL_ENTRY(void, glMatrixMode, GLenum mode)
+GL_ENTRY(void, glMultMatrixf, const GLfloat*)
+GL_ENTRY(void, glMultMatrixx, const GLfixed*)
+GL_ENTRY(void, glPopMatrix, void)
+GL_ENTRY(void, glPushMatrix, void)
+GL_ENTRY(void, glFrustumf, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glFrustumx, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glOrthof, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glOrthox, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glRotatef, GLfloat, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glRotatex, GLfixed, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glScalef, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glScalex, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glTranslatef, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glTranslatex, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glViewport, GLint, GLint, GLsizei, GLsizei)
+GL_ENTRY(void, glActiveTexture, GLenum)
+GL_ENTRY(void, glBindTexture, GLenum, GLuint)
+GL_ENTRY(void, glGenTextures, GLsizei, GLuint*)
+GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *)
+GL_ENTRY(void, glMultiTexCoord4f, GLenum, GLfloat, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glMultiTexCoord4x, GLenum, GLfixed, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glPixelStorei, GLenum, GLint)
+GL_ENTRY(void, glTexEnvf, GLenum, GLenum, GLfloat)
+GL_ENTRY(void, glTexEnvfv, GLenum, GLenum, const GLfloat*)
+GL_ENTRY(void, glTexEnvx, GLenum, GLenum, GLfixed)
+GL_ENTRY(void, glTexEnvxv, GLenum, GLenum, const GLfixed*)
+GL_ENTRY(void, glTexParameterf, GLenum, GLenum, GLfloat)
+GL_ENTRY(void, glTexParameterx, GLenum, GLenum, GLfixed)
+GL_ENTRY(void, glCompressedTexImage2D,    GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)
+GL_ENTRY(void, glCompressedTexSubImage2D, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)
+GL_ENTRY(void, glCopyTexImage2D, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint)
+GL_ENTRY(void, glCopyTexSubImage2D, GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)
+GL_ENTRY(void, glTexImage2D, GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)
+GL_ENTRY(void, glTexSubImage2D, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)
+GL_ENTRY(void, glReadPixels, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid *)
+
+// 1.1 additions
+GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat*)
+GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed*)
+GL_ENTRY(void, glBindBuffer, GLenum, GLuint)
+GL_ENTRY(void, glBufferData, GLenum, GLsizeiptr, const GLvoid*, GLenum)
+GL_ENTRY(void, glBufferSubData, GLenum, GLintptr, GLsizeiptr, const GLvoid*)
+GL_ENTRY(void, glDeleteBuffers, GLsizei, const GLuint*)
+GL_ENTRY(void, glGenBuffers, GLsizei, GLuint*)
+GL_ENTRY(void, glGetBooleanv, GLenum, GLboolean *)
+GL_ENTRY(void, glGetFixedv, GLenum, GLfixed *)
+GL_ENTRY(void, glGetFloatv, GLenum, GLfloat *)
+GL_ENTRY(void, glGetPointerv, GLenum, void **)
+GL_ENTRY(void, glGetBufferParameteriv, GLenum, GLenum, GLint *)
+GL_ENTRY(void, glGetClipPlanef, GLenum, GLfloat[4])
+GL_ENTRY(void, glGetClipPlanex, GLenum, GLfixed[4])
+GL_ENTRY(void, glGetLightxv, GLenum, GLenum, GLfixed *)
+GL_ENTRY(void, glGetLightfv, GLenum, GLenum, GLfloat *)
+GL_ENTRY(void, glGetMaterialxv, GLenum, GLenum, GLfixed *)
+GL_ENTRY(void, glGetMaterialfv, GLenum, GLenum, GLfloat *)
+GL_ENTRY(void, glGetTexEnvfv, GLenum, GLenum, GLfloat *)
+GL_ENTRY(void, glGetTexEnviv, GLenum, GLenum, GLint *)
+GL_ENTRY(void, glGetTexEnvxv, GLenum, GLenum, GLfixed *)
+GL_ENTRY(void, glGetTexParameterfv, GLenum, GLenum, GLfloat *)
+GL_ENTRY(void, glGetTexParameteriv, GLenum, GLenum, GLint *)
+GL_ENTRY(void, glGetTexParameterxv, GLenum, GLenum, GLfixed *)
+GL_ENTRY(GLboolean, glIsBuffer, GLuint)
+GL_ENTRY(GLboolean, glIsEnabled, GLenum)
+GL_ENTRY(GLboolean, glIsTexture, GLuint)
+GL_ENTRY(void, glPointParameterf, GLenum, GLfloat)
+GL_ENTRY(void, glPointParameterfv, GLenum, const GLfloat *)
+GL_ENTRY(void, glPointParameterx, GLenum, GLfixed)
+GL_ENTRY(void, glPointParameterxv, GLenum, const GLfixed *)
+GL_ENTRY(void, glColor4ub, GLubyte, GLubyte, GLubyte, GLubyte)
+GL_ENTRY(void, glTexEnvi, GLenum, GLenum, GLint)
+GL_ENTRY(void, glTexEnviv, GLenum, GLenum, const GLint *)
+GL_ENTRY(void, glTexParameterfv, GLenum, GLenum, const GLfloat *)
+GL_ENTRY(void, glTexParameteriv, GLenum, GLenum, const GLint *)
+GL_ENTRY(void, glTexParameteri, GLenum, GLenum, GLint)
+GL_ENTRY(void, glTexParameterxv, GLenum, GLenum, const GLfixed *)
+GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const GLvoid*)
+
+// Extensions
+GL_ENTRY(void, glDrawTexsOES, GLshort, GLshort, GLshort, GLshort, GLshort)
+GL_ENTRY(void, glDrawTexiOES, GLint, GLint, GLint, GLint, GLint)
+GL_ENTRY(void, glDrawTexfOES, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glDrawTexxOES, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glDrawTexsvOES, const GLshort*)
+GL_ENTRY(void, glDrawTexivOES, const GLint*)
+GL_ENTRY(void, glDrawTexfvOES, const GLfloat*)
+GL_ENTRY(void, glDrawTexxvOES, const GLfixed*)
+GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed* mantissa, GLint* exponent)
+
diff --git a/opengl/libs/gl_enums.in b/opengl/libs/gl_enums.in
new file mode 100644
index 0000000..ffc2fad
--- /dev/null
+++ b/opengl/libs/gl_enums.in
@@ -0,0 +1,261 @@
+GLENUM(GL_POINTS, 0x0000)
+GLENUM(GL_LINES, 0x0001)
+GLENUM(GL_LINE_LOOP, 0x0002)
+GLENUM(GL_LINE_STRIP, 0x0003)
+GLENUM(GL_TRIANGLES, 0x0004)
+GLENUM(GL_TRIANGLE_STRIP, 0x0005)
+GLENUM(GL_TRIANGLE_FAN, 0x0006)
+GLENUM(GL_ADD, 0x0104)
+GLENUM(GL_NEVER, 0x0200)
+GLENUM(GL_LESS, 0x0201)
+GLENUM(GL_EQUAL, 0x0202)
+GLENUM(GL_LEQUAL, 0x0203)
+GLENUM(GL_GREATER, 0x0204)
+GLENUM(GL_NOTEQUAL, 0x0205)
+GLENUM(GL_GEQUAL, 0x0206)
+GLENUM(GL_ALWAYS, 0x0207)
+GLENUM(GL_SRC_COLOR, 0x0300)
+GLENUM(GL_ONE_MINUS_SRC_COLOR, 0x0301)
+GLENUM(GL_SRC_ALPHA, 0x0302)
+GLENUM(GL_ONE_MINUS_SRC_ALPHA, 0x0303)
+GLENUM(GL_DST_ALPHA, 0x0304)
+GLENUM(GL_ONE_MINUS_DST_ALPHA, 0x0305)
+GLENUM(GL_DST_COLOR, 0x0306)
+GLENUM(GL_ONE_MINUS_DST_COLOR, 0x0307)
+GLENUM(GL_SRC_ALPHA_SATURATE, 0x0308)
+GLENUM(GL_FRONT, 0x0404)
+GLENUM(GL_BACK, 0x0405)
+GLENUM(GL_FRONT_AND_BACK, 0x0408)
+GLENUM(GL_INVALID_ENUM, 0x0500)
+GLENUM(GL_INVALID_VALUE, 0x0501)
+GLENUM(GL_INVALID_OPERATION, 0x0502)
+GLENUM(GL_STACK_OVERFLOW, 0x0503)
+GLENUM(GL_STACK_UNDERFLOW, 0x0504)
+GLENUM(GL_OUT_OF_MEMORY, 0x0505)
+GLENUM(GL_EXP, 0x0800)
+GLENUM(GL_EXP2, 0x0801)
+GLENUM(GL_CW, 0x0900)
+GLENUM(GL_CCW, 0x0901)
+GLENUM(GL_POINT_SMOOTH, 0x0B10)
+GLENUM(GL_SMOOTH_POINT_SIZE_RANGE, 0x0B12)
+GLENUM(GL_LINE_SMOOTH, 0x0B20)
+GLENUM(GL_SMOOTH_LINE_WIDTH_RANGE, 0x0B22)
+GLENUM(GL_CULL_FACE, 0x0B44)
+GLENUM(GL_LIGHTING, 0x0B50)
+GLENUM(GL_LIGHT_MODEL_TWO_SIDE, 0x0B52)
+GLENUM(GL_LIGHT_MODEL_AMBIENT, 0x0B53)
+GLENUM(GL_COLOR_MATERIAL, 0x0B57)
+GLENUM(GL_FOG, 0x0B60)
+GLENUM(GL_FOG_DENSITY, 0x0B62)
+GLENUM(GL_FOG_START, 0x0B63)
+GLENUM(GL_FOG_END, 0x0B64)
+GLENUM(GL_FOG_MODE, 0x0B65)
+GLENUM(GL_FOG_COLOR, 0x0B66)
+GLENUM(GL_DEPTH_TEST, 0x0B71)
+GLENUM(GL_STENCIL_TEST, 0x0B90)
+GLENUM(GL_NORMALIZE, 0x0BA1)
+GLENUM(GL_ALPHA_TEST, 0x0BC0)
+GLENUM(GL_DITHER, 0x0BD0)
+GLENUM(GL_BLEND, 0x0BE2)
+GLENUM(GL_COLOR_LOGIC_OP, 0x0BF2)
+GLENUM(GL_SCISSOR_TEST, 0x0C11)
+GLENUM(GL_PERSPECTIVE_CORRECTION_HINT, 0x0C50)
+GLENUM(GL_POINT_SMOOTH_HINT, 0x0C51)
+GLENUM(GL_LINE_SMOOTH_HINT, 0x0C52)
+GLENUM(GL_POLYGON_SMOOTH_HINT, 0x0C53)
+GLENUM(GL_FOG_HINT, 0x0C54)
+GLENUM(GL_UNPACK_ALIGNMENT, 0x0CF5)
+GLENUM(GL_PACK_ALIGNMENT, 0x0D05)
+GLENUM(GL_MAX_LIGHTS, 0x0D31)
+GLENUM(GL_MAX_CLIP_PLANES, 0x0D32)
+GLENUM(GL_MAX_TEXTURE_SIZE, 0x0D33)
+GLENUM(GL_MAX_MODELVIEW_STACK_DEPTH, 0x0D36)
+GLENUM(GL_MAX_PROJECTION_STACK_DEPTH, 0x0D38)
+GLENUM(GL_MAX_TEXTURE_STACK_DEPTH, 0x0D39)
+GLENUM(GL_MAX_VIEWPORT_DIMS, 0x0D3A)
+GLENUM(GL_RED_BITS, 0x0D52)
+GLENUM(GL_GREEN_BITS, 0x0D53)
+GLENUM(GL_BLUE_BITS, 0x0D54)
+GLENUM(GL_ALPHA_BITS, 0x0D55)
+GLENUM(GL_DEPTH_BITS, 0x0D56)
+GLENUM(GL_STENCIL_BITS, 0x0D57)
+GLENUM(GL_TEXTURE_2D, 0x0DE1)
+GLENUM(GL_DONT_CARE, 0x1100)
+GLENUM(GL_FASTEST, 0x1101)
+GLENUM(GL_NICEST, 0x1102)
+GLENUM(GL_AMBIENT, 0x1200)
+GLENUM(GL_DIFFUSE, 0x1201)
+GLENUM(GL_SPECULAR, 0x1202)
+GLENUM(GL_POSITION, 0x1203)
+GLENUM(GL_SPOT_DIRECTION, 0x1204)
+GLENUM(GL_SPOT_EXPONENT, 0x1205)
+GLENUM(GL_SPOT_CUTOFF, 0x1206)
+GLENUM(GL_CONSTANT_ATTENUATION, 0x1207)
+GLENUM(GL_LINEAR_ATTENUATION, 0x1208)
+GLENUM(GL_QUADRATIC_ATTENUATION, 0x1209)
+GLENUM(GL_BYTE, 0x1400)
+GLENUM(GL_UNSIGNED_BYTE, 0x1401)
+GLENUM(GL_SHORT, 0x1402)
+GLENUM(GL_UNSIGNED_SHORT, 0x1403)
+GLENUM(GL_FLOAT, 0x1406)
+GLENUM(GL_FIXED, 0x140C)
+GLENUM(GL_CLEAR, 0x1500)
+GLENUM(GL_AND, 0x1501)
+GLENUM(GL_AND_REVERSE, 0x1502)
+GLENUM(GL_COPY, 0x1503)
+GLENUM(GL_AND_INVERTED, 0x1504)
+GLENUM(GL_NOOP, 0x1505)
+GLENUM(GL_XOR, 0x1506)
+GLENUM(GL_OR, 0x1507)
+GLENUM(GL_NOR, 0x1508)
+GLENUM(GL_EQUIV, 0x1509)
+GLENUM(GL_INVERT, 0x150A)
+GLENUM(GL_OR_REVERSE, 0x150B)
+GLENUM(GL_COPY_INVERTED, 0x150C)
+GLENUM(GL_OR_INVERTED, 0x150D)
+GLENUM(GL_NAND, 0x150E)
+GLENUM(GL_SET, 0x150F)
+GLENUM(GL_EMISSION, 0x1600)
+GLENUM(GL_SHININESS, 0x1601)
+GLENUM(GL_AMBIENT_AND_DIFFUSE, 0x1602)
+GLENUM(GL_MODELVIEW, 0x1700)
+GLENUM(GL_PROJECTION, 0x1701)
+GLENUM(GL_TEXTURE, 0x1702)
+GLENUM(GL_ALPHA, 0x1906)
+GLENUM(GL_RGB, 0x1907)
+GLENUM(GL_RGBA, 0x1908)
+GLENUM(GL_LUMINANCE, 0x1909)
+GLENUM(GL_LUMINANCE_ALPHA, 0x190A)
+GLENUM(GL_FLAT, 0x1D00)
+GLENUM(GL_SMOOTH, 0x1D01)
+GLENUM(GL_KEEP, 0x1E00)
+GLENUM(GL_REPLACE, 0x1E01)
+GLENUM(GL_REPLACE, 0x1E01)
+GLENUM(GL_INCR, 0x1E02)
+GLENUM(GL_DECR, 0x1E03)
+GLENUM(GL_VENDOR, 0x1F00)
+GLENUM(GL_RENDERER, 0x1F01)
+GLENUM(GL_VERSION, 0x1F02)
+GLENUM(GL_EXTENSIONS, 0x1F03)
+GLENUM(GL_MODULATE, 0x2100)
+GLENUM(GL_DECAL, 0x2101)
+GLENUM(GL_TEXTURE_ENV_MODE, 0x2200)
+GLENUM(GL_TEXTURE_ENV_COLOR, 0x2201)
+GLENUM(GL_TEXTURE_ENV, 0x2300)
+GLENUM(GL_NEAREST, 0x2600)
+GLENUM(GL_LINEAR, 0x2601)
+GLENUM(GL_NEAREST_MIPMAP_NEAREST, 0x2700)
+GLENUM(GL_LINEAR_MIPMAP_NEAREST, 0x2701)
+GLENUM(GL_NEAREST_MIPMAP_LINEAR, 0x2702)
+GLENUM(GL_LINEAR_MIPMAP_LINEAR, 0x2703)
+GLENUM(GL_TEXTURE_MAG_FILTER, 0x2800)
+GLENUM(GL_TEXTURE_MIN_FILTER, 0x2801)
+GLENUM(GL_TEXTURE_WRAP_S, 0x2802)
+GLENUM(GL_TEXTURE_WRAP_T, 0x2803)
+GLENUM(GL_CLAMP, 0x2900)
+GLENUM(GL_REPEAT, 0x2901)
+GLENUM(GL_CLIP_PLANE0, 0x3000)
+GLENUM(GL_CLIP_PLANE1, 0x3001)
+GLENUM(GL_CLIP_PLANE2, 0x3002)
+GLENUM(GL_CLIP_PLANE3, 0x3003)
+GLENUM(GL_CLIP_PLANE4, 0x3004)
+GLENUM(GL_CLIP_PLANE5, 0x3005)
+GLENUM(GL_LIGHT0, 0x4000)
+GLENUM(GL_LIGHT1, 0x4001)
+GLENUM(GL_LIGHT2, 0x4002)
+GLENUM(GL_LIGHT3, 0x4003)
+GLENUM(GL_LIGHT4, 0x4004)
+GLENUM(GL_LIGHT5, 0x4005)
+GLENUM(GL_LIGHT6, 0x4006)
+GLENUM(GL_LIGHT7, 0x4007)
+GLENUM(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0x7E80)
+GLENUM(GL_UNSIGNED_SHORT_4_4_4_4, 0x8033)
+GLENUM(GL_UNSIGNED_SHORT_5_5_5_1, 0x8034)
+GLENUM(GL_POLYGON_OFFSET_FILL, 0x8037)
+GLENUM(GL_RESCALE_NORMAL, 0x803A)
+GLENUM(GL_VERTEX_ARRAY, 0x8074)
+GLENUM(GL_NORMAL_ARRAY, 0x8075)
+GLENUM(GL_COLOR_ARRAY, 0x8076)
+GLENUM(GL_TEXTURE_COORD_ARRAY, 0x8078)
+GLENUM(GL_MULTISAMPLE, 0x809D)
+GLENUM(GL_SAMPLE_ALPHA_TO_COVERAGE, 0x809E)
+GLENUM(GL_SAMPLE_ALPHA_TO_ONE, 0x809F)
+GLENUM(GL_SAMPLE_COVERAGE, 0x80A0)
+GLENUM(GL_MAX_ELEMENTS_VERTICES, 0x80E8)
+GLENUM(GL_MAX_ELEMENTS_INDICES, 0x80E9)
+GLENUM(GL_CLAMP_TO_EDGE, 0x812F)
+GLENUM(GL_GENERATE_MIPMAP, 0x8191)
+GLENUM(GL_GENERATE_MIPMAP_HINT, 0x8192)
+GLENUM(GL_UNSIGNED_SHORT_5_6_5, 0x8363)
+GLENUM(GL_ALIASED_POINT_SIZE_RANGE, 0x846D)
+GLENUM(GL_ALIASED_LINE_WIDTH_RANGE, 0x846E)
+GLENUM(GL_TEXTURE0, 0x84C0)
+GLENUM(GL_TEXTURE1, 0x84C1)
+GLENUM(GL_TEXTURE2, 0x84C2)
+GLENUM(GL_TEXTURE3, 0x84C3)
+GLENUM(GL_TEXTURE4, 0x84C4)
+GLENUM(GL_TEXTURE5, 0x84C5)
+GLENUM(GL_TEXTURE6, 0x84C6)
+GLENUM(GL_TEXTURE7, 0x84C7)
+GLENUM(GL_TEXTURE8, 0x84C8)
+GLENUM(GL_TEXTURE9, 0x84C9)
+GLENUM(GL_TEXTURE10, 0x84CA)
+GLENUM(GL_TEXTURE11, 0x84CB)
+GLENUM(GL_TEXTURE12, 0x84CC)
+GLENUM(GL_TEXTURE13, 0x84CD)
+GLENUM(GL_TEXTURE14, 0x84CE)
+GLENUM(GL_TEXTURE15, 0x84CF)
+GLENUM(GL_TEXTURE16, 0x84D0)
+GLENUM(GL_TEXTURE17, 0x84D1)
+GLENUM(GL_TEXTURE18, 0x84D2)
+GLENUM(GL_TEXTURE19, 0x84D3)
+GLENUM(GL_TEXTURE20, 0x84D4)
+GLENUM(GL_TEXTURE21, 0x84D5)
+GLENUM(GL_TEXTURE22, 0x84D6)
+GLENUM(GL_TEXTURE23, 0x84D7)
+GLENUM(GL_TEXTURE24, 0x84D8)
+GLENUM(GL_TEXTURE25, 0x84D9)
+GLENUM(GL_TEXTURE26, 0x84DA)
+GLENUM(GL_TEXTURE27, 0x84DB)
+GLENUM(GL_TEXTURE28, 0x84DC)
+GLENUM(GL_TEXTURE29, 0x84DD)
+GLENUM(GL_TEXTURE30, 0x84DE)
+GLENUM(GL_TEXTURE31, 0x84DF)
+GLENUM(GL_MAX_TEXTURE_UNITS, 0x84E2)
+GLENUM(GL_NUM_COMPRESSED_TEXTURE_FORMATS, 0x86A2)
+GLENUM(GL_COMPRESSED_TEXTURE_FORMATS, 0x86A3)
+GLENUM(GL_BUFFER_SIZE, 0x8764)
+GLENUM(GL_BUFFER_USAGE, 0x8765)
+GLENUM(GL_POINT_SPRITE_OES, 0x8861)
+GLENUM(GL_COORD_REPLACE_OES, 0x8862)
+GLENUM(GL_ARRAY_BUFFER, 0x8892)
+GLENUM(GL_ELEMENT_ARRAY_BUFFER, 0x8893)
+GLENUM(GL_ARRAY_BUFFER_BINDING, 0x8894)
+GLENUM(GL_ELEMENT_ARRAY_BUFFER_BINDING, 0x8895)
+GLENUM(GL_VERTEX_ARRAY_BUFFER_BINDING, 0x8896)
+GLENUM(GL_NORMAL_ARRAY_BUFFER_BINDING, 0x8897)
+GLENUM(GL_COLOR_ARRAY_BUFFER_BINDING, 0x8898)
+GLENUM(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, 0x889A)
+GLENUM(GL_STATIC_DRAW, 0x88E4)
+GLENUM(GL_DYNAMIC_DRAW, 0x88E8)
+GLENUM(GL_POINT_SIZE_ARRAY_TYPE_OES, 0x898A)
+GLENUM(GL_POINT_SIZE_ARRAY_STRIDE_OES, 0x898B)
+GLENUM(GL_POINT_SIZE_ARRAY_POINTER_OES, 0x898C)
+GLENUM(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898D)
+GLENUM(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898E)
+GLENUM(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898F)
+GLENUM(GL_PALETTE4_RGB8_OES, 0x8B90)
+GLENUM(GL_PALETTE4_RGBA8_OES, 0x8B91)
+GLENUM(GL_PALETTE4_R5_G6_B5_OES, 0x8B92)
+GLENUM(GL_PALETTE4_RGBA4_OES, 0x8B93)
+GLENUM(GL_PALETTE4_RGB5_A1_OES, 0x8B94)
+GLENUM(GL_PALETTE8_RGB8_OES, 0x8B95)
+GLENUM(GL_PALETTE8_RGBA8_OES, 0x8B96)
+GLENUM(GL_PALETTE8_R5_G6_B5_OES, 0x8B97)
+GLENUM(GL_PALETTE8_RGBA4_OES, 0x8B98)
+GLENUM(GL_PALETTE8_RGB5_A1_OES, 0x8B99)
+GLENUM(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, 0x8B9A)
+GLENUM(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, 0x8B9B)
+GLENUM(GL_POINT_SIZE_ARRAY_OES, 0x8B9C)
+GLENUM(GL_TEXTURE_CROP_RECT_OES, 0x8B9D)
+GLENUM(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES, 0x8B9F)
diff --git a/opengl/libs/gl_logger.h b/opengl/libs/gl_logger.h
new file mode 100644
index 0000000..ce85dd1
--- /dev/null
+++ b/opengl/libs/gl_logger.h
@@ -0,0 +1,26 @@
+/* 
+ ** Copyright 2007, 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.
+ */
+
+#ifndef ANDROID_GL_LOGGER_H
+#define ANDROID_GL_LOGGER_H
+
+namespace android {
+#define GL_ENTRY(r, api, ...) r log_##api(__VA_ARGS__);
+#include "gl_entries.in"
+#undef GL_ENTRY
+}; // namespace android
+
+#endif /* ANDROID_GL_LOGGER_H */
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
new file mode 100644
index 0000000..63fb017
--- /dev/null
+++ b/opengl/libs/hooks.h
@@ -0,0 +1,134 @@
+/* 
+ ** Copyright 2007, 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.
+ */
+
+#ifndef ANDROID_GLES_CM_HOOKS_H
+#define ANDROID_GLES_CM_HOOKS_H
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+
+#define GL_LOGGER                   0
+#if !defined(__arm__)
+#define USE_SLOW_BINDING            1
+#else
+#define USE_SLOW_BINDING            0
+#endif
+#undef NELEM
+#define NELEM(x)                    (sizeof(x)/sizeof(*(x)))
+#define MAX_NUMBER_OF_GL_EXTENSIONS 32
+
+
+#if defined(HAVE_ANDROID_OS) && !USE_SLOW_BINDING && !GL_LOGGER && __OPTIMIZE__
+#define USE_FAST_TLS_KEY            1
+#else
+#define USE_FAST_TLS_KEY            0
+#endif
+
+#if USE_FAST_TLS_KEY
+#   include <bionic_tls.h>  /* special private C library header */
+#endif
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+//  EGLDisplay are global, not attached to a given thread
+const unsigned int NUM_DISPLAYS = 1;
+
+enum {
+    IMPL_HARDWARE = 0,
+    IMPL_SOFTWARE,
+    IMPL_CONTEXT_LOST,
+    IMPL_NO_CONTEXT,
+    
+    IMPL_NUM_IMPLEMENTATIONS
+};
+
+// ----------------------------------------------------------------------------
+
+// GL / EGL hooks
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+#define GL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
+#define EGL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
+
+struct gl_hooks_t {
+    struct gl_t {
+        #include "gl_entries.in"
+    } gl;
+    struct egl_t {
+        #include "egl_entries.in"
+    } egl;
+    struct gl_ext_t {
+        void (*extensions[MAX_NUMBER_OF_GL_EXTENSIONS])(void);
+    } ext;
+};
+#undef GL_ENTRY
+#undef EGL_ENTRY
+
+
+// ----------------------------------------------------------------------------
+
+extern gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
+extern pthread_key_t gGLWrapperKey;
+
+#if USE_FAST_TLS_KEY
+
+// We have a dedicated TLS slot in bionic
+static inline gl_hooks_t const * volatile * get_tls_hooks() {
+    volatile void *tls_base = __get_tls();
+    gl_hooks_t const * volatile * tls_hooks = 
+            reinterpret_cast<gl_hooks_t const * volatile *>(tls_base);
+    return tls_hooks;
+}
+
+static inline void setGlThreadSpecific(gl_hooks_t const *value) {
+    gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
+    tls_hooks[TLS_SLOT_OPENGL_API] = value;
+}
+
+static gl_hooks_t const* getGlThreadSpecific() {
+    gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
+    gl_hooks_t const* hooks = tls_hooks[TLS_SLOT_OPENGL_API];
+    if (hooks) return hooks;
+    return &gHooks[IMPL_NO_CONTEXT];
+}
+
+#else
+
+static inline void setGlThreadSpecific(gl_hooks_t const *value) {
+    pthread_setspecific(gGLWrapperKey, value);
+}
+
+static gl_hooks_t const* getGlThreadSpecific() {
+    gl_hooks_t const* hooks =  static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
+    if (hooks) return hooks;
+    return &gHooks[IMPL_NO_CONTEXT];
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_GLES_CM_HOOKS_H */
diff --git a/opengl/libs/tools/enumextract.sh b/opengl/libs/tools/enumextract.sh
new file mode 100644
index 0000000..5707302
--- /dev/null
+++ b/opengl/libs/tools/enumextract.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+awk '
+/^#define GL_/ {
+    names[count] = $2;
+    values[count] = $3;
+    sort[count] = $3 + 0;
+    count++;
+}
+END {
+    for (i = 1; i < count; i++) {
+        for (j = 0; j < i; j++) {
+            if (sort[i] < sort[j]) {
+                tn = names[i];
+                tv = values[i];
+                ts = sort[i];
+                names[i] = names[j];
+                values[i] = values[j];
+                sort[i] = sort[j];
+                names[j] = tn;
+                values[j] = tv;
+                sort[j] = ts;
+            }
+        }
+    }
+ 
+    for (i = 0; i < count; i++) {
+        printf("GLENUM(%s, %s)\n", names[i], values[i]);
+    }
+}
+' < $1
+
diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/opengl/tests/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk
new file mode 100644
index 0000000..46958d3
--- /dev/null
+++ b/opengl/tests/angeles/Android.mk
@@ -0,0 +1,17 @@
+# Copyright 2006 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= app-linux.c demo.c.arm
+LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui
+LOCAL_MODULE:= angeles
+LOCAL_MODULE_TAGS := tests
+include $(BUILD_EXECUTABLE)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= gpustate.c
+LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM
+LOCAL_MODULE:= gpustate
+LOCAL_MODULE_TAGS := tests
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/angeles/MODULE_LICENSE_BSD_OR_LGPL b/opengl/tests/angeles/MODULE_LICENSE_BSD_OR_LGPL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/opengl/tests/angeles/MODULE_LICENSE_BSD_OR_LGPL
diff --git a/opengl/tests/angeles/README.txt b/opengl/tests/angeles/README.txt
new file mode 100644
index 0000000..38b8a4a
--- /dev/null
+++ b/opengl/tests/angeles/README.txt
@@ -0,0 +1,77 @@
+------------------------------------------------------------------------

+San Angeles Observation OpenGL ES version example

+Copyright 2004-2005 Jetro Lauha

+Web: http://iki.fi/jetro/

+See file license.txt for licensing information.

+------------------------------------------------------------------------

+

+This is an OpenGL ES port of the small self-running demonstration

+called "San Angeles Observation", which was first presented in the

+Assembly'2004 event. It won the first place in the 4 KB intro

+competition category.

+

+The demonstration features a sightseeing of a futuristic city

+having many different kind of buildings and items. Everything is

+flat shaded with three different lights.

+

+The original version was made for desktop with OpenGL. It was

+naturally heavily size optimized in order to fit it in the size

+limit. For this OpenGL ES version example much of the code is

+cleaned up and the sound is removed. Also detail level is lowered,

+although it still contains over 60000 faces.

+

+The Win32 (2000/XP) binary package of original version is

+available from this address: http://jet.ro/files/angeles.zip

+

+First version of this OpenGL ES port was submitted to the Khronos

+OpenGL ES Coding Challenge held in 2004-2005.

+

+As a code example, this source shows the following:

+  * How to create a minimal and portable ad hoc framework

+    for small testing/demonstration programs. This framework

+    compiles for both desktop and PocketPC Win32 environment,

+    and a separate source is included for Linux with X11.

+  * How to dynamically find and use the OpenGL ES DLL or

+    shared object, so that the library is not needed at

+    the compile/link stage.

+  * How to use the basic features of OpenGL ES 1.0/1.1

+    Common Lite, such as vertex arrays, color arrays and

+    lighting.

+  * How to create a self contained small demonstration

+    application with objects generated using procedural

+    algorithms.

+

+As the original version was optimized for size instead of

+performance, that holds true for this OpenGL ES version as

+well. Thus the performance could be significantly increased,

+for example by changing the code to use glDrawElements

+instead of glDrawArrays. The code uses only OpenGL ES 1.0

+Common Lite -level function calls without any extensions.

+

+The reference OpenGL ES implementations used for this application:

+  * Hybrid's OpenGL ES API Implementation (Gerbera) version 2.0.4

+    Prebuilt Win32 PC executable: SanOGLES-Gerbera.exe

+  * PowerVR MBX SDK, OpenGL ES Windows PC Emulation version 1.04.14.0170

+    Prebuilt Win32 PC executable: SanOGLES-PVRSDK.exe

+

+Note that DISABLE_IMPORTGL preprocessor macro can be used

+to specify not to use dynamic runtime binding of the library.

+You also need to define preprocessor macro PVRSDK to compile

+the source with PowerVR OpenGL ES SDK.

+

+The demo application is briefly tested with a few other OpenGL ES

+implementations as well (e.g. Vincent, GLESonGL on Linux, Dell

+Axim X50v). Most of these other implementations rendered the demo

+erroneously in some aspect. This may indicate that the demo source

+could still have some work to do with compatibility and correct

+API usage, although the non-conforming implementations are most

+probably unfinished as well.

+

+Thanks and Acknowledgements:

+

+* Toni Lönnberg (!Cube) created the music for original version, which

+  is not featured in this OpenGL ES port.

+* Sara Kapli (st Rana) for additional camera work.

+* Paul Bourke for information about the supershapes.

+

+------------------------------------------------------------------------

diff --git a/opengl/tests/angeles/app-linux.c b/opengl/tests/angeles/app-linux.c
new file mode 100644
index 0000000..7d0d320
--- /dev/null
+++ b/opengl/tests/angeles/app-linux.c
@@ -0,0 +1,223 @@
+/* San Angeles Observation OpenGL ES version example
+ * Copyright 2004-2005 Jetro Lauha
+ * All rights reserved.
+ * Web: http://iki.fi/jetro/
+ *
+ * This source is free software; you can redistribute it and/or
+ * modify it under the terms of EITHER:
+ *   (1) The GNU Lesser General Public License as published by the Free
+ *       Software Foundation; either version 2.1 of the License, or (at
+ *       your option) any later version. The text of the GNU Lesser
+ *       General Public License is included with this source in the
+ *       file LICENSE-LGPL.txt.
+ *   (2) The BSD-style license that is included with this source in
+ *       the file LICENSE-BSD.txt.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
+ * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
+ *
+ * $Id: app-linux.c,v 1.4 2005/02/08 18:42:48 tonic Exp $
+ * $Revision: 1.4 $
+ *
+ * Parts of this source file is based on test/example code from
+ * GLESonGL implementation by David Blythe. Here is copy of the
+ * license notice from that source:
+ *
+ * Copyright (C) 2003  David Blythe   All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * DAVID BLYTHE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+
+#include "app.h"
+
+
+int gAppAlive = 1;
+
+static const char sAppName[] =
+    "San Angeles Observation OpenGL ES version example (Linux)";
+
+static int sWindowWidth = WINDOW_DEFAULT_WIDTH;
+static int sWindowHeight = WINDOW_DEFAULT_HEIGHT;
+static EGLDisplay sEglDisplay = EGL_NO_DISPLAY;
+static EGLContext sEglContext = EGL_NO_CONTEXT;
+static EGLSurface sEglSurface = EGL_NO_SURFACE;
+
+const char *egl_strerror(unsigned err)
+{
+    switch(err){
+    case EGL_SUCCESS: return "SUCCESS";
+    case EGL_NOT_INITIALIZED: return "NOT INITIALIZED";
+    case EGL_BAD_ACCESS: return "BAD ACCESS";
+    case EGL_BAD_ALLOC: return "BAD ALLOC";
+    case EGL_BAD_ATTRIBUTE: return "BAD_ATTRIBUTE";
+    case EGL_BAD_CONFIG: return "BAD CONFIG";
+    case EGL_BAD_CONTEXT: return "BAD CONTEXT";
+    case EGL_BAD_CURRENT_SURFACE: return "BAD CURRENT SURFACE";
+    case EGL_BAD_DISPLAY: return "BAD DISPLAY";
+    case EGL_BAD_MATCH: return "BAD MATCH";
+    case EGL_BAD_NATIVE_PIXMAP: return "BAD NATIVE PIXMAP";
+    case EGL_BAD_NATIVE_WINDOW: return "BAD NATIVE WINDOW";
+    case EGL_BAD_PARAMETER: return "BAD PARAMETER";
+    case EGL_BAD_SURFACE: return "BAD_SURFACE";
+//    case EGL_CONTEXT_LOST: return "CONTEXT LOST";
+    default: return "UNKNOWN";
+    }
+}
+
+void egl_error(const char *name)
+{
+    unsigned err = eglGetError();
+    if(err != EGL_SUCCESS) {
+        fprintf(stderr,"%s(): egl error 0x%x (%s)\n", 
+                name, err, egl_strerror(err));
+    }
+}
+
+static void checkGLErrors()
+{
+    GLenum error = glGetError();
+    if (error != GL_NO_ERROR)
+        fprintf(stderr, "GL Error: 0x%04x\n", (int)error);
+}
+
+
+static void checkEGLErrors()
+{
+    EGLint error = eglGetError();
+    // GLESonGL seems to be returning 0 when there is no errors?
+    if (error && error != EGL_SUCCESS)
+        fprintf(stderr, "EGL Error: 0x%04x\n", (int)error);
+}
+
+static int initGraphics()
+{
+    EGLint s_configAttribs[] = {
+         EGL_RED_SIZE,       5,
+         EGL_GREEN_SIZE,     6,
+         EGL_BLUE_SIZE,      5,
+ #if 1
+         EGL_DEPTH_SIZE,     16,
+         EGL_STENCIL_SIZE,   0,
+ #else
+         EGL_ALPHA_SIZE,     EGL_DONT_CARE,
+         EGL_DEPTH_SIZE,     EGL_DONT_CARE,
+         EGL_STENCIL_SIZE,   EGL_DONT_CARE,
+         EGL_SURFACE_TYPE,   EGL_DONT_CARE,
+ #endif
+         EGL_NONE
+     };
+     
+     EGLint numConfigs = -1;
+     EGLint majorVersion;
+     EGLint minorVersion;
+     EGLConfig config;
+     EGLContext context;
+     EGLSurface surface;
+     
+     EGLDisplay dpy;
+
+     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+     egl_error("eglGetDisplay");
+     fprintf(stderr,"dpy = 0x%08x\n", (unsigned) dpy);
+     
+     eglInitialize(dpy, &majorVersion, &minorVersion);
+     egl_error("eglInitialize");
+
+     eglGetConfigs(dpy, NULL, 0, &numConfigs);
+     egl_error("eglGetConfigs");
+     fprintf(stderr,"num configs %d\n", numConfigs);
+     
+     eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
+     egl_error("eglChooseConfig");
+
+     surface = eglCreateWindowSurface(dpy, config,
+             android_createDisplaySurface(), NULL);
+     egl_error("eglMapWindowSurface");
+
+     fprintf(stderr,"surface = %p\n", surface);
+
+     context = eglCreateContext(dpy, config, NULL, NULL);
+     egl_error("eglCreateContext");
+     fprintf(stderr,"context = %p\n", context);
+     
+     eglMakeCurrent(dpy, surface, surface, context);   
+     egl_error("eglMakeCurrent");
+
+     eglQuerySurface(dpy, surface, EGL_WIDTH, &sWindowWidth);
+     eglQuerySurface(dpy, surface, EGL_HEIGHT, &sWindowHeight);
+
+    sEglDisplay = dpy;
+    sEglSurface = surface;
+    sEglContext = context;
+
+    return EGL_TRUE;
+}
+
+
+static void deinitGraphics()
+{
+    eglMakeCurrent(sEglDisplay, NULL, NULL, NULL);
+    eglDestroyContext(sEglDisplay, sEglContext);
+    eglDestroySurface(sEglDisplay, sEglSurface);
+    eglTerminate(sEglDisplay);
+}
+
+
+int main(int argc, char *argv[])
+{
+    // not referenced:
+    argc = argc;
+    argv = argv;
+
+    if (!initGraphics())
+    {
+        fprintf(stderr, "Graphics initialization failed.\n");
+        return EXIT_FAILURE;
+    }
+
+    appInit();
+    
+    while (gAppAlive)
+    {
+        struct timeval timeNow;
+
+        if (gAppAlive)
+        {
+            gettimeofday(&timeNow, NULL);
+            appRender(timeNow.tv_sec * 1000 + timeNow.tv_usec / 1000,
+                      sWindowWidth, sWindowHeight);
+            checkGLErrors();
+            eglSwapBuffers(sEglDisplay, sEglSurface);
+            checkEGLErrors();
+        }
+    }
+
+    appDeinit();
+    deinitGraphics();
+
+    return EXIT_SUCCESS;
+}
diff --git a/opengl/tests/angeles/app.h b/opengl/tests/angeles/app.h
new file mode 100644
index 0000000..70ebd35
--- /dev/null
+++ b/opengl/tests/angeles/app.h
@@ -0,0 +1,56 @@
+/* San Angeles Observation OpenGL ES version example
+ * Copyright 2004-2005 Jetro Lauha
+ * All rights reserved.
+ * Web: http://iki.fi/jetro/
+ *
+ * This source is free software; you can redistribute it and/or
+ * modify it under the terms of EITHER:
+ *   (1) The GNU Lesser General Public License as published by the Free
+ *       Software Foundation; either version 2.1 of the License, or (at
+ *       your option) any later version. The text of the GNU Lesser
+ *       General Public License is included with this source in the
+ *       file LICENSE-LGPL.txt.
+ *   (2) The BSD-style license that is included with this source in
+ *       the file LICENSE-BSD.txt.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
+ * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
+ *
+ * $Id: app.h,v 1.14 2005/02/06 21:13:54 tonic Exp $
+ * $Revision: 1.14 $
+ */
+
+#ifndef APP_H_INCLUDED
+#define APP_H_INCLUDED
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define WINDOW_DEFAULT_WIDTH    640
+#define WINDOW_DEFAULT_HEIGHT   480
+
+#define WINDOW_BPP              16
+
+
+// The simple framework expects the application code to define these functions.
+extern void appInit();
+extern void appDeinit();
+extern void appRender(long tick, int width, int height);
+
+/* Value is non-zero when application is alive, and 0 when it is closing.
+ * Defined by the application framework.
+ */
+extern int gAppAlive;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // !APP_H_INCLUDED
diff --git a/opengl/tests/angeles/cams.h b/opengl/tests/angeles/cams.h
new file mode 100644
index 0000000..2b1acb3
--- /dev/null
+++ b/opengl/tests/angeles/cams.h
@@ -0,0 +1,65 @@
+/* San Angeles Observation OpenGL ES version example
+ * Copyright 2004-2005 Jetro Lauha
+ * All rights reserved.
+ * Web: http://iki.fi/jetro/
+ *
+ * This source is free software; you can redistribute it and/or
+ * modify it under the terms of EITHER:
+ *   (1) The GNU Lesser General Public License as published by the Free
+ *       Software Foundation; either version 2.1 of the License, or (at
+ *       your option) any later version. The text of the GNU Lesser
+ *       General Public License is included with this source in the
+ *       file LICENSE-LGPL.txt.
+ *   (2) The BSD-style license that is included with this source in
+ *       the file LICENSE-BSD.txt.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
+ * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
+ *
+ * $Id: cams.h,v 1.7 2005/01/31 22:15:15 tonic Exp $
+ * $Revision: 1.7 $
+ */
+
+#ifndef CAMS_H_INCLUDED
+#define CAMS_H_INCLUDED
+
+
+/* Length in milliseconds of one camera track base unit.
+ * The value originates from the music synchronization.
+ */
+#define CAMTRACK_LEN    5442
+
+
+// Camera track definition for one camera trucking shot.
+typedef struct
+{
+    /* Five parameters of src[5] and dest[5]:
+     * eyeX, eyeY, eyeZ, viewAngle, viewHeightOffs
+     */
+    short src[5], dest[5];
+    unsigned char dist;     // if >0, cam rotates around eye xy on dist * 0.1
+    unsigned char len;      // length multiplier
+} CAMTRACK;
+
+static CAMTRACK sCamTracks[] =
+{
+    { { 4500, 2700, 100, 70, -30 }, { 50, 50, -90, -100, 0 }, 20, 1 },
+    { { -1448, 4294, 25, 363, 0 }, { -136, 202, 125, -98, 100 }, 0, 1 },
+    { { 1437, 4930, 200, -275, -20 }, { 1684, 0, 0, 9, 0 }, 0, 1 },
+    { { 1800, 3609, 200, 0, 675 }, { 0, 0, 0, 300, 0 }, 0, 1 },
+    { { 923, 996, 50, 2336, -80 }, { 0, -20, -50, 0, 170 }, 0, 1 },
+    { { -1663, -43, 600, 2170, 0 }, { 20, 0, -600, 0, 100 }, 0, 1 },
+    { { 1049, -1420, 175, 2111, -17 }, { 0, 0, 0, -334, 0 }, 0, 2 },
+    { { 0, 0, 50, 300, 25 }, { 0, 0, 0, 300, 0 }, 70, 2 },
+    { { -473, -953, 3500, -353, -350 }, { 0, 0, -2800, 0, 0 }, 0, 2 },
+    { { 191, 1938, 35, 1139, -17 }, { 1205, -2909, 0, 0, 0 }, 0, 2 },
+    { { -1449, -2700, 150, 0, 0 }, { 0, 2000, 0, 0, 0 }, 0, 2 },
+    { { 5273, 4992, 650, 373, -50 }, { -4598, -3072, 0, 0, 0 }, 0, 2 },
+    { { 3223, -3282, 1075, -393, -25 }, { 1649, -1649, 0, 0, 0 }, 0, 2 }
+};
+#define CAMTRACK_COUNT (sizeof(camTracks) / sizeof(camTracks[0]))
+
+
+#endif // !CAMS_H_INCLUDED
diff --git a/opengl/tests/angeles/demo.c b/opengl/tests/angeles/demo.c
new file mode 100644
index 0000000..802f398
--- /dev/null
+++ b/opengl/tests/angeles/demo.c
@@ -0,0 +1,792 @@
+/* San Angeles Observation OpenGL ES version example
+ * Copyright 2004-2005 Jetro Lauha
+ * All rights reserved.
+ * Web: http://iki.fi/jetro/
+ *
+ * This source is free software; you can redistribute it and/or
+ * modify it under the terms of EITHER:
+ *   (1) The GNU Lesser General Public License as published by the Free
+ *       Software Foundation; either version 2.1 of the License, or (at
+ *       your option) any later version. The text of the GNU Lesser
+ *       General Public License is included with this source in the
+ *       file LICENSE-LGPL.txt.
+ *   (2) The BSD-style license that is included with this source in
+ *       the file LICENSE-BSD.txt.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
+ * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
+ *
+ * $Id: demo.c,v 1.10 2005/02/08 20:54:39 tonic Exp $
+ * $Revision: 1.10 $
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <float.h>
+#include <assert.h>
+
+#include <GLES/gl.h>
+
+#include "app.h"
+#include "shapes.h"
+#include "cams.h"
+
+
+// Total run length is 20 * camera track base unit length (see cams.h).
+#define RUN_LENGTH  (20 * CAMTRACK_LEN)
+#undef PI
+#define PI 3.1415926535897932f
+#define RANDOM_UINT_MAX 65535
+
+
+static unsigned long sRandomSeed = 0;
+
+static void seedRandom(unsigned long seed)
+{
+    sRandomSeed = seed;
+}
+
+static unsigned long randomUInt()
+{
+    sRandomSeed = sRandomSeed * 0x343fd + 0x269ec3;
+    return sRandomSeed >> 16;
+}
+
+
+// Capped conversion from float to fixed.
+static long floatToFixed(float value)
+{
+    if (value < -32768) value = -32768;
+    if (value > 32767) value = 32767;
+    return (long)(value * 65536);
+}
+
+#define FIXED(value) floatToFixed(value)
+
+
+// Definition of one GL object in this demo.
+typedef struct {
+    /* Vertex array and color array are enabled for all objects, so their
+     * pointers must always be valid and non-NULL. Normal array is not
+     * used by the ground plane, so when its pointer is NULL then normal
+     * array usage is disabled.
+     *
+     * Vertex array is supposed to use GL_FIXED datatype and stride 0
+     * (i.e. tightly packed array). Color array is supposed to have 4
+     * components per color with GL_UNSIGNED_BYTE datatype and stride 0.
+     * Normal array is supposed to use GL_FIXED datatype and stride 0.
+     */
+    GLfixed *vertexArray;
+    GLubyte *colorArray;
+    GLfixed *normalArray;
+    GLint vertexComponents;
+    GLsizei count;
+} GLOBJECT;
+
+
+static long sStartTick = 0;
+static long sTick = 0;
+
+static int sCurrentCamTrack = 0;
+static long sCurrentCamTrackStartTick = 0;
+static long sNextCamTrackStartTick = 0x7fffffff;
+
+static GLOBJECT *sSuperShapeObjects[SUPERSHAPE_COUNT] = { NULL };
+static GLOBJECT *sGroundPlane = NULL;
+
+
+typedef struct {
+    float x, y, z;
+} VECTOR3;
+
+
+static void freeGLObject(GLOBJECT *object)
+{
+    if (object == NULL)
+        return;
+    free(object->normalArray);
+    free(object->colorArray);
+    free(object->vertexArray);
+    free(object);
+}
+
+
+static GLOBJECT * newGLObject(long vertices, int vertexComponents,
+                              int useNormalArray)
+{
+    GLOBJECT *result;
+    result = (GLOBJECT *)malloc(sizeof(GLOBJECT));
+    if (result == NULL)
+        return NULL;
+    result->count = vertices;
+    result->vertexComponents = vertexComponents;
+    result->vertexArray = (GLfixed *)malloc(vertices * vertexComponents *
+                                            sizeof(GLfixed));
+    result->colorArray = (GLubyte *)malloc(vertices * 4 * sizeof(GLubyte));
+    if (useNormalArray)
+    {
+        result->normalArray = (GLfixed *)malloc(vertices * 3 *
+                                                sizeof(GLfixed));
+    }
+    else
+        result->normalArray = NULL;
+    if (result->vertexArray == NULL ||
+        result->colorArray == NULL ||
+        (useNormalArray && result->normalArray == NULL))
+    {
+        freeGLObject(result);
+        return NULL;
+    }
+    return result;
+}
+
+
+static void drawGLObject(GLOBJECT *object)
+{
+    assert(object != NULL);
+
+    glVertexPointer(object->vertexComponents, GL_FIXED,
+                    0, object->vertexArray);
+    glColorPointer(4, GL_UNSIGNED_BYTE, 0, object->colorArray);
+
+    // Already done in initialization:
+    //glEnableClientState(GL_VERTEX_ARRAY);
+    //glEnableClientState(GL_COLOR_ARRAY);
+
+    if (object->normalArray)
+    {
+        glNormalPointer(GL_FIXED, 0, object->normalArray);
+        glEnableClientState(GL_NORMAL_ARRAY);
+    }
+    else
+        glDisableClientState(GL_NORMAL_ARRAY);
+    glDrawArrays(GL_TRIANGLES, 0, object->count);
+}
+
+
+static void vector3Sub(VECTOR3 *dest, VECTOR3 *v1, VECTOR3 *v2)
+{
+    dest->x = v1->x - v2->x;
+    dest->y = v1->y - v2->y;
+    dest->z = v1->z - v2->z;
+}
+
+
+static void superShapeMap(VECTOR3 *point, float r1, float r2, float t, float p)
+{
+    // sphere-mapping of supershape parameters
+    point->x = (float)(cos(t) * cos(p) / r1 / r2);
+    point->y = (float)(sin(t) * cos(p) / r1 / r2);
+    point->z = (float)(sin(p) / r2);
+}
+
+
+static float ssFunc(const float t, const float *p)
+{
+    return (float)(pow(pow(fabs(cos(p[0] * t / 4)) / p[1], p[4]) +
+                       pow(fabs(sin(p[0] * t / 4)) / p[2], p[5]), 1 / p[3]));
+}
+
+
+// Creates and returns a supershape object.
+// Based on Paul Bourke's POV-Ray implementation.
+// http://astronomy.swin.edu.au/~pbourke/povray/supershape/
+static GLOBJECT * createSuperShape(const float *params)
+{
+    const int resol1 = (int)params[SUPERSHAPE_PARAMS - 3];
+    const int resol2 = (int)params[SUPERSHAPE_PARAMS - 2];
+    // latitude 0 to pi/2 for no mirrored bottom
+    // (latitudeBegin==0 for -pi/2 to pi/2 originally)
+    const int latitudeBegin = resol2 / 4;
+    const int latitudeEnd = resol2 / 2;    // non-inclusive
+    const int longitudeCount = resol1;
+    const int latitudeCount = latitudeEnd - latitudeBegin;
+    const long triangleCount = longitudeCount * latitudeCount * 2;
+    const long vertices = triangleCount * 3;
+    GLOBJECT *result;
+    float baseColor[3];
+    int a, longitude, latitude;
+    long currentVertex, currentQuad;
+
+    result = newGLObject(vertices, 3, 1);
+    if (result == NULL)
+        return NULL;
+
+    for (a = 0; a < 3; ++a)
+        baseColor[a] = ((randomUInt() % 155) + 100) / 255.f;
+
+    currentQuad = 0;
+    currentVertex = 0;
+
+    // longitude -pi to pi
+    for (longitude = 0; longitude < longitudeCount; ++longitude)
+    {
+
+        // latitude 0 to pi/2
+        for (latitude = latitudeBegin; latitude < latitudeEnd; ++latitude)
+        {
+            float t1 = -PI + longitude * 2 * PI / resol1;
+            float t2 = -PI + (longitude + 1) * 2 * PI / resol1;
+            float p1 = -PI / 2 + latitude * 2 * PI / resol2;
+            float p2 = -PI / 2 + (latitude + 1) * 2 * PI / resol2;
+            float r0, r1, r2, r3;
+
+            r0 = ssFunc(t1, params);
+            r1 = ssFunc(p1, &params[6]);
+            r2 = ssFunc(t2, params);
+            r3 = ssFunc(p2, &params[6]);
+
+            if (r0 != 0 && r1 != 0 && r2 != 0 && r3 != 0)
+            {
+                VECTOR3 pa, pb, pc, pd;
+                VECTOR3 v1, v2, n;
+                float ca;
+                int i;
+                //float lenSq, invLenSq;
+
+                superShapeMap(&pa, r0, r1, t1, p1);
+                superShapeMap(&pb, r2, r1, t2, p1);
+                superShapeMap(&pc, r2, r3, t2, p2);
+                superShapeMap(&pd, r0, r3, t1, p2);
+
+                // kludge to set lower edge of the object to fixed level
+                if (latitude == latitudeBegin + 1)
+                    pa.z = pb.z = 0;
+
+                vector3Sub(&v1, &pb, &pa);
+                vector3Sub(&v2, &pd, &pa);
+
+                // Calculate normal with cross product.
+                /*   i    j    k      i    j
+                 * v1.x v1.y v1.z | v1.x v1.y
+                 * v2.x v2.y v2.z | v2.x v2.y
+                 */
+
+                n.x = v1.y * v2.z - v1.z * v2.y;
+                n.y = v1.z * v2.x - v1.x * v2.z;
+                n.z = v1.x * v2.y - v1.y * v2.x;
+
+                /* Pre-normalization of the normals is disabled here because
+                 * they will be normalized anyway later due to automatic
+                 * normalization (GL_NORMALIZE). It is enabled because the
+                 * objects are scaled with glScale.
+                 */
+                /*
+                lenSq = n.x * n.x + n.y * n.y + n.z * n.z;
+                invLenSq = (float)(1 / sqrt(lenSq));
+                n.x *= invLenSq;
+                n.y *= invLenSq;
+                n.z *= invLenSq;
+                */
+
+                ca = pa.z + 0.5f;
+
+                for (i = currentVertex * 3;
+                     i < (currentVertex + 6) * 3;
+                     i += 3)
+                {
+                    result->normalArray[i] = FIXED(n.x);
+                    result->normalArray[i + 1] = FIXED(n.y);
+                    result->normalArray[i + 2] = FIXED(n.z);
+                }
+                for (i = currentVertex * 4;
+                     i < (currentVertex + 6) * 4;
+                     i += 4)
+                {
+                    int a, color[3];
+                    for (a = 0; a < 3; ++a)
+                    {
+                        color[a] = (int)(ca * baseColor[a] * 255);
+                        if (color[a] > 255) color[a] = 255;
+                    }
+                    result->colorArray[i] = (GLubyte)color[0];
+                    result->colorArray[i + 1] = (GLubyte)color[1];
+                    result->colorArray[i + 2] = (GLubyte)color[2];
+                    result->colorArray[i + 3] = 0;
+                }
+                result->vertexArray[currentVertex * 3] = FIXED(pa.x);
+                result->vertexArray[currentVertex * 3 + 1] = FIXED(pa.y);
+                result->vertexArray[currentVertex * 3 + 2] = FIXED(pa.z);
+                ++currentVertex;
+                result->vertexArray[currentVertex * 3] = FIXED(pb.x);
+                result->vertexArray[currentVertex * 3 + 1] = FIXED(pb.y);
+                result->vertexArray[currentVertex * 3 + 2] = FIXED(pb.z);
+                ++currentVertex;
+                result->vertexArray[currentVertex * 3] = FIXED(pd.x);
+                result->vertexArray[currentVertex * 3 + 1] = FIXED(pd.y);
+                result->vertexArray[currentVertex * 3 + 2] = FIXED(pd.z);
+                ++currentVertex;
+                result->vertexArray[currentVertex * 3] = FIXED(pb.x);
+                result->vertexArray[currentVertex * 3 + 1] = FIXED(pb.y);
+                result->vertexArray[currentVertex * 3 + 2] = FIXED(pb.z);
+                ++currentVertex;
+                result->vertexArray[currentVertex * 3] = FIXED(pc.x);
+                result->vertexArray[currentVertex * 3 + 1] = FIXED(pc.y);
+                result->vertexArray[currentVertex * 3 + 2] = FIXED(pc.z);
+                ++currentVertex;
+                result->vertexArray[currentVertex * 3] = FIXED(pd.x);
+                result->vertexArray[currentVertex * 3 + 1] = FIXED(pd.y);
+                result->vertexArray[currentVertex * 3 + 2] = FIXED(pd.z);
+                ++currentVertex;
+            } // r0 && r1 && r2 && r3
+            ++currentQuad;
+        } // latitude
+    } // longitude
+
+    // Set number of vertices in object to the actual amount created.
+    result->count = currentVertex;
+
+    return result;
+}
+
+
+static GLOBJECT * createGroundPlane()
+{
+    const int scale = 4;
+    const int yBegin = -15, yEnd = 15;    // ends are non-inclusive
+    const int xBegin = -15, xEnd = 15;
+    const long triangleCount = (yEnd - yBegin) * (xEnd - xBegin) * 2;
+    const long vertices = triangleCount * 3;
+    GLOBJECT *result;
+    int x, y;
+    long currentVertex, currentQuad;
+
+    result = newGLObject(vertices, 2, 0);
+    if (result == NULL)
+        return NULL;
+
+    currentQuad = 0;
+    currentVertex = 0;
+
+    for (y = yBegin; y < yEnd; ++y)
+    {
+        for (x = xBegin; x < xEnd; ++x)
+        {
+            GLubyte color;
+            int i, a;
+            color = (GLubyte)((randomUInt() & 0x5f) + 81);  // 101 1111
+            for (i = currentVertex * 4; i < (currentVertex + 6) * 4; i += 4)
+            {
+                result->colorArray[i] = color;
+                result->colorArray[i + 1] = color;
+                result->colorArray[i + 2] = color;
+                result->colorArray[i + 3] = 0;
+            }
+
+            // Axis bits for quad triangles:
+            // x: 011100 (0x1c), y: 110001 (0x31)  (clockwise)
+            // x: 001110 (0x0e), y: 100011 (0x23)  (counter-clockwise)
+            for (a = 0; a < 6; ++a)
+            {
+                const int xm = x + ((0x1c >> a) & 1);
+                const int ym = y + ((0x31 >> a) & 1);
+                const float m = (float)(cos(xm * 2) * sin(ym * 4) * 0.75f);
+                result->vertexArray[currentVertex * 2] =
+                    FIXED(xm * scale + m);
+                result->vertexArray[currentVertex * 2 + 1] =
+                    FIXED(ym * scale + m);
+                ++currentVertex;
+            }
+            ++currentQuad;
+        }
+    }
+    return result;
+}
+
+
+static void drawGroundPlane()
+{
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_ZERO, GL_SRC_COLOR);
+    glDisable(GL_LIGHTING);
+
+    drawGLObject(sGroundPlane);
+
+    glEnable(GL_LIGHTING);
+    glDisable(GL_BLEND);
+    glEnable(GL_DEPTH_TEST);
+}
+
+
+static void drawFadeQuad()
+{
+    static const GLfixed quadVertices[] = {
+        -0x10000, -0x10000,
+         0x10000, -0x10000,
+        -0x10000,  0x10000,
+         0x10000, -0x10000,
+         0x10000,  0x10000,
+        -0x10000,  0x10000
+    };
+
+    const int beginFade = sTick - sCurrentCamTrackStartTick;
+    const int endFade = sNextCamTrackStartTick - sTick;
+    const int minFade = beginFade < endFade ? beginFade : endFade;
+
+    if (minFade < 1024)
+    {
+        const GLfixed fadeColor = minFade << 6;
+        glColor4x(fadeColor, fadeColor, fadeColor, 0);
+
+        glDisable(GL_DEPTH_TEST);
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_ZERO, GL_SRC_COLOR);
+        glDisable(GL_LIGHTING);
+
+        glMatrixMode(GL_MODELVIEW);
+        glLoadIdentity();
+
+        glMatrixMode(GL_PROJECTION);
+        glLoadIdentity();
+
+        glDisableClientState(GL_COLOR_ARRAY);
+        glDisableClientState(GL_NORMAL_ARRAY);
+        glVertexPointer(2, GL_FIXED, 0, quadVertices);
+        glDrawArrays(GL_TRIANGLES, 0, 6);
+
+        glEnableClientState(GL_COLOR_ARRAY);
+
+        glMatrixMode(GL_MODELVIEW);
+
+        glEnable(GL_LIGHTING);
+        glDisable(GL_BLEND);
+        glEnable(GL_DEPTH_TEST);
+    }
+}
+
+
+// Called from the app framework.
+void appInit()
+{
+    int a;
+
+    glEnable(GL_NORMALIZE);
+    glEnable(GL_DEPTH_TEST);
+    glDisable(GL_CULL_FACE);
+    glShadeModel(GL_FLAT);
+
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+    glEnable(GL_LIGHT1);
+    glEnable(GL_LIGHT2);
+
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glEnableClientState(GL_COLOR_ARRAY);
+
+    seedRandom(15);
+
+    for (a = 0; a < SUPERSHAPE_COUNT; ++a)
+    {
+        sSuperShapeObjects[a] = createSuperShape(sSuperShapeParams[a]);
+        assert(sSuperShapeObjects[a] != NULL);
+    }
+    sGroundPlane = createGroundPlane();
+    assert(sGroundPlane != NULL);
+}
+
+
+// Called from the app framework.
+void appDeinit()
+{
+    int a;
+    for (a = 0; a < SUPERSHAPE_COUNT; ++a)
+        freeGLObject(sSuperShapeObjects[a]);
+    freeGLObject(sGroundPlane);
+}
+
+
+static void gluPerspective(GLfloat fovy, GLfloat aspect,
+                           GLfloat zNear, GLfloat zFar)
+{
+    GLfloat xmin, xmax, ymin, ymax;
+
+    ymax = zNear * (GLfloat)tan(fovy * PI / 360);
+    ymin = -ymax;
+    xmin = ymin * aspect;
+    xmax = ymax * aspect;
+
+    glFrustumx((GLfixed)(xmin * 65536), (GLfixed)(xmax * 65536),
+               (GLfixed)(ymin * 65536), (GLfixed)(ymax * 65536),
+               (GLfixed)(zNear * 65536), (GLfixed)(zFar * 65536));
+}
+
+
+static void prepareFrame(int width, int height)
+{
+    glViewport(0, 0, width, height);
+
+    glClearColorx((GLfixed)(0.1f * 65536),
+                  (GLfixed)(0.2f * 65536),
+                  (GLfixed)(0.3f * 65536), 0x10000);
+    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    gluPerspective(45, (float)width / height, 0.5f, 150);
+
+    glMatrixMode(GL_MODELVIEW);
+
+    glLoadIdentity();
+}
+
+
+static void configureLightAndMaterial()
+{
+    static GLfixed light0Position[] = { -0x40000, 0x10000, 0x10000, 0 };
+    static GLfixed light0Diffuse[] = { 0x10000, 0x6666, 0, 0x10000 };
+    static GLfixed light1Position[] = { 0x10000, -0x20000, -0x10000, 0 };
+    static GLfixed light1Diffuse[] = { 0x11eb, 0x23d7, 0x5999, 0x10000 };
+    static GLfixed light2Position[] = { -0x10000, 0, -0x40000, 0 };
+    static GLfixed light2Diffuse[] = { 0x11eb, 0x2b85, 0x23d7, 0x10000 };
+    static GLfixed materialSpecular[] = { 0x10000, 0x10000, 0x10000, 0x10000 };
+
+    glLightxv(GL_LIGHT0, GL_POSITION, light0Position);
+    glLightxv(GL_LIGHT0, GL_DIFFUSE, light0Diffuse);
+    glLightxv(GL_LIGHT1, GL_POSITION, light1Position);
+    glLightxv(GL_LIGHT1, GL_DIFFUSE, light1Diffuse);
+    glLightxv(GL_LIGHT2, GL_POSITION, light2Position);
+    glLightxv(GL_LIGHT2, GL_DIFFUSE, light2Diffuse);
+    glMaterialxv(GL_FRONT_AND_BACK, GL_SPECULAR, materialSpecular);
+
+    glMaterialx(GL_FRONT_AND_BACK, GL_SHININESS, 60 << 16);
+    glEnable(GL_COLOR_MATERIAL);
+}
+
+
+static void drawModels(float zScale)
+{
+    const int translationScale = 9;
+    int x, y;
+
+    seedRandom(9);
+
+    glScalex(1 << 16, 1 << 16, (GLfixed)(zScale * 65536));
+
+    for (y = -5; y <= 5; ++y)
+    {
+        for (x = -5; x <= 5; ++x)
+        {
+            float buildingScale;
+            GLfixed fixedScale;
+
+            int curShape = randomUInt() % SUPERSHAPE_COUNT;
+            buildingScale = sSuperShapeParams[curShape][SUPERSHAPE_PARAMS - 1];
+            fixedScale = (GLfixed)(buildingScale * 65536);
+
+            glPushMatrix();
+            glTranslatex((x * translationScale) * 65536,
+                         (y * translationScale) * 65536,
+                         0);
+            glRotatex((GLfixed)((randomUInt() % 360) << 16), 0, 0, 1 << 16);
+            glScalex(fixedScale, fixedScale, fixedScale);
+
+            drawGLObject(sSuperShapeObjects[curShape]);
+            glPopMatrix();
+        }
+    }
+
+    for (x = -2; x <= 2; ++x)
+    {
+        const int shipScale100 = translationScale * 500;
+        const int offs100 = x * shipScale100 + (sTick % shipScale100);
+        float offs = offs100 * 0.01f;
+        GLfixed fixedOffs = (GLfixed)(offs * 65536);
+        glPushMatrix();
+        glTranslatex(fixedOffs, -4 * 65536, 2 << 16);
+        drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]);
+        glPopMatrix();
+        glPushMatrix();
+        glTranslatex(-4 * 65536, fixedOffs, 4 << 16);
+        glRotatex(90 << 16, 0, 0, 1 << 16);
+        drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]);
+        glPopMatrix();
+    }
+}
+
+
+/* Following gluLookAt implementation is adapted from the
+ * Mesa 3D Graphics library. http://www.mesa3d.org
+ */
+static void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez,
+	              GLfloat centerx, GLfloat centery, GLfloat centerz,
+	              GLfloat upx, GLfloat upy, GLfloat upz)
+{
+    GLfloat m[16];
+    GLfloat x[3], y[3], z[3];
+    GLfloat mag;
+
+    /* Make rotation matrix */
+
+    /* Z vector */
+    z[0] = eyex - centerx;
+    z[1] = eyey - centery;
+    z[2] = eyez - centerz;
+    mag = (float)sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
+    if (mag) {			/* mpichler, 19950515 */
+        z[0] /= mag;
+        z[1] /= mag;
+        z[2] /= mag;
+    }
+
+    /* Y vector */
+    y[0] = upx;
+    y[1] = upy;
+    y[2] = upz;
+
+    /* X vector = Y cross Z */
+    x[0] = y[1] * z[2] - y[2] * z[1];
+    x[1] = -y[0] * z[2] + y[2] * z[0];
+    x[2] = y[0] * z[1] - y[1] * z[0];
+
+    /* Recompute Y = Z cross X */
+    y[0] = z[1] * x[2] - z[2] * x[1];
+    y[1] = -z[0] * x[2] + z[2] * x[0];
+    y[2] = z[0] * x[1] - z[1] * x[0];
+
+    /* mpichler, 19950515 */
+    /* cross product gives area of parallelogram, which is < 1.0 for
+     * non-perpendicular unit-length vectors; so normalize x, y here
+     */
+
+    mag = (float)sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
+    if (mag) {
+        x[0] /= mag;
+        x[1] /= mag;
+        x[2] /= mag;
+    }
+
+    mag = (float)sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
+    if (mag) {
+        y[0] /= mag;
+        y[1] /= mag;
+        y[2] /= mag;
+    }
+
+#define M(row,col)  m[col*4+row]
+    M(0, 0) = x[0];
+    M(0, 1) = x[1];
+    M(0, 2) = x[2];
+    M(0, 3) = 0.0;
+    M(1, 0) = y[0];
+    M(1, 1) = y[1];
+    M(1, 2) = y[2];
+    M(1, 3) = 0.0;
+    M(2, 0) = z[0];
+    M(2, 1) = z[1];
+    M(2, 2) = z[2];
+    M(2, 3) = 0.0;
+    M(3, 0) = 0.0;
+    M(3, 1) = 0.0;
+    M(3, 2) = 0.0;
+    M(3, 3) = 1.0;
+#undef M
+    {
+        int a;
+        GLfixed fixedM[16];
+        for (a = 0; a < 16; ++a)
+            fixedM[a] = (GLfixed)(m[a] * 65536);
+        glMultMatrixx(fixedM);
+    }
+
+    /* Translate Eye to Origin */
+    glTranslatex((GLfixed)(-eyex * 65536),
+                 (GLfixed)(-eyey * 65536),
+                 (GLfixed)(-eyez * 65536));
+}
+
+
+static void camTrack()
+{
+    float lerp[5];
+    float eX, eY, eZ, cX, cY, cZ;
+    float trackPos;
+    CAMTRACK *cam;
+    long currentCamTick;
+    int a;
+
+    if (sNextCamTrackStartTick <= sTick)
+    {
+        ++sCurrentCamTrack;
+        sCurrentCamTrackStartTick = sNextCamTrackStartTick;
+    }
+    sNextCamTrackStartTick = sCurrentCamTrackStartTick +
+                             sCamTracks[sCurrentCamTrack].len * CAMTRACK_LEN;
+
+    cam = &sCamTracks[sCurrentCamTrack];
+    currentCamTick = sTick - sCurrentCamTrackStartTick;
+    trackPos = (float)currentCamTick / (CAMTRACK_LEN * cam->len);
+
+    for (a = 0; a < 5; ++a)
+        lerp[a] = (cam->src[a] + cam->dest[a] * trackPos) * 0.01f;
+
+    if (cam->dist)
+    {
+        float dist = cam->dist * 0.1f;
+        cX = lerp[0];
+        cY = lerp[1];
+        cZ = lerp[2];
+        eX = cX - (float)cos(lerp[3]) * dist;
+        eY = cY - (float)sin(lerp[3]) * dist;
+        eZ = cZ - lerp[4];
+    }
+    else
+    {
+        eX = lerp[0];
+        eY = lerp[1];
+        eZ = lerp[2];
+        cX = eX + (float)cos(lerp[3]);
+        cY = eY + (float)sin(lerp[3]);
+        cZ = eZ + lerp[4];
+    }
+    gluLookAt(eX, eY, eZ, cX, cY, cZ, 0, 0, 1);
+}
+
+
+// Called from the app framework.
+/* The tick is current time in milliseconds, width and height
+ * are the image dimensions to be rendered.
+ */
+void appRender(long tick, int width, int height)
+{
+    if (sStartTick == 0)
+        sStartTick = tick;
+    if (!gAppAlive)
+        return;
+
+    // Actual tick value is "blurred" a little bit.
+    sTick = (sTick + tick - sStartTick) >> 1;
+
+    // Terminate application after running through the demonstration once.
+    if (sTick >= RUN_LENGTH)
+    {
+        gAppAlive = 0;
+        return;
+    }
+
+    // Prepare OpenGL ES for rendering of the frame.
+    prepareFrame(width, height);
+
+    // Update the camera position and set the lookat.
+    camTrack();
+
+    // Configure environment.
+    configureLightAndMaterial();
+
+    // Draw the reflection by drawing models with negated Z-axis.
+    glPushMatrix();
+    drawModels(-1);
+    glPopMatrix();
+
+    // Blend the ground plane to the window.
+    drawGroundPlane();
+
+    // Draw all the models normally.
+    drawModels(1);
+
+    // Draw fade quad over whole window (when changing cameras).
+    drawFadeQuad();
+}
diff --git a/opengl/tests/angeles/gpustate.c b/opengl/tests/angeles/gpustate.c
new file mode 100644
index 0000000..3c540c9
--- /dev/null
+++ b/opengl/tests/angeles/gpustate.c
@@ -0,0 +1,39 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+static void *map_memory(const char *fn, unsigned base, unsigned size)
+{
+    int fd;
+    void *ptr;
+    
+    fd = open(fn, O_RDWR | O_SYNC);
+    if(fd < 0) {
+        perror("cannot open %s for mapping");
+        return MAP_FAILED;
+    }
+
+    ptr = mmap(0, size, PROT_READ | PROT_WRITE,
+               MAP_SHARED, fd, base);
+    close(fd);
+    
+    if(ptr == MAP_FAILED) {
+        fprintf(stderr,"cannot map %s (@%08x,%08x)\n", fn, base, size);
+    }
+    return ptr;    
+}
+
+
+int main(int argc, char** argv)
+{
+    void *grp_regs = map_memory("/dev/hw3d", 0, 1024 * 1024);
+    printf("GPU base mapped at %p\n", grp_regs);
+    int state_offset = 0x10140;
+    printf("GPU state = %08lx\n",
+            *((long*)((char*)grp_regs + state_offset))  );
+
+    return 0;
+}
diff --git a/opengl/tests/angeles/include/GLES/egl.h b/opengl/tests/angeles/include/GLES/egl.h
new file mode 100644
index 0000000..cdf8410
--- /dev/null
+++ b/opengl/tests/angeles/include/GLES/egl.h
@@ -0,0 +1,229 @@
+#ifndef __egl_h_
+#define __egl_h_
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.0 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2004 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+#include <GLES/gl.h>
+#include <GLES/egltypes.h>
+
+/*
+** egltypes.h is platform dependent. It defines:
+**
+**     - EGL types and resources
+**     - Native types
+**     - EGL and native handle values
+**
+** EGL types and resources are to be typedef'ed with appropriate platform
+** dependent resource handle types. EGLint must be an integer of at least
+** 32-bit.
+**
+** NativeDisplayType, NativeWindowType and NativePixmapType are to be
+** replaced with corresponding types of the native window system in egl.h.
+**
+** EGL and native handle values must match their types.
+**
+** Example egltypes.h:
+*/
+
+#if 0
+
+#include <sys/types.h>
+#include <native_window_system.h>
+
+/*
+** Types and resources
+*/
+typedef int EGLBoolean;
+typedef int32_t EGLint;
+typedef void *EGLDisplay;
+typedef void *EGLConfig;
+typedef void *EGLSurface;
+typedef void *EGLContext;
+
+/*
+** EGL and native handle values
+*/
+#define EGL_DEFAULT_DISPLAY ((NativeDisplayType)0)
+#define EGL_NO_CONTEXT ((EGLContext)0)
+#define EGL_NO_DISPLAY ((EGLDisplay)0)
+#define EGL_NO_SURFACE ((EGLSurface)0)
+
+#endif
+
+/*
+** Versioning and extensions
+*/
+#define EGL_VERSION_1_0		       1
+
+/*
+** Boolean
+*/
+#define EGL_FALSE		       0
+#define EGL_TRUE		       1
+
+/*
+** Errors
+*/
+#define EGL_SUCCESS		       0x3000
+#define EGL_NOT_INITIALIZED	       0x3001
+#define EGL_BAD_ACCESS		       0x3002
+#define EGL_BAD_ALLOC		       0x3003
+#define EGL_BAD_ATTRIBUTE	       0x3004
+#define EGL_BAD_CONFIG		       0x3005
+#define EGL_BAD_CONTEXT		       0x3006
+#define EGL_BAD_CURRENT_SURFACE        0x3007
+#define EGL_BAD_DISPLAY		       0x3008
+#define EGL_BAD_MATCH		       0x3009
+#define EGL_BAD_NATIVE_PIXMAP	       0x300A
+#define EGL_BAD_NATIVE_WINDOW	       0x300B
+#define EGL_BAD_PARAMETER	       0x300C
+#define EGL_BAD_SURFACE		       0x300D
+/* 0x300E - 0x301F reserved for additional errors. */
+
+/*
+** Config attributes
+*/
+#define EGL_BUFFER_SIZE		       0x3020
+#define EGL_ALPHA_SIZE		       0x3021
+#define EGL_BLUE_SIZE		       0x3022
+#define EGL_GREEN_SIZE		       0x3023
+#define EGL_RED_SIZE		       0x3024
+#define EGL_DEPTH_SIZE		       0x3025
+#define EGL_STENCIL_SIZE	       0x3026
+#define EGL_CONFIG_CAVEAT	       0x3027
+#define EGL_CONFIG_ID		       0x3028
+#define EGL_LEVEL		       0x3029
+#define EGL_MAX_PBUFFER_HEIGHT	       0x302A
+#define EGL_MAX_PBUFFER_PIXELS	       0x302B
+#define EGL_MAX_PBUFFER_WIDTH	       0x302C
+#define EGL_NATIVE_RENDERABLE	       0x302D
+#define EGL_NATIVE_VISUAL_ID	       0x302E
+#define EGL_NATIVE_VISUAL_TYPE	       0x302F
+/*#define EGL_PRESERVED_RESOURCES	 0x3030*/
+#define EGL_SAMPLES		       0x3031
+#define EGL_SAMPLE_BUFFERS	       0x3032
+#define EGL_SURFACE_TYPE	       0x3033
+#define EGL_TRANSPARENT_TYPE	       0x3034
+#define EGL_TRANSPARENT_BLUE_VALUE     0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE    0x3036
+#define EGL_TRANSPARENT_RED_VALUE      0x3037
+
+/*
+** Config attribute and value
+*/
+#define EGL_NONE		       0x3038
+/* 0x3039 - 0x304F reserved for additional config attributes. */
+
+/*
+** Config values
+*/
+#define EGL_DONT_CARE		       ((EGLint) -1)
+#define EGL_PBUFFER_BIT		       0x01
+#define EGL_PIXMAP_BIT		       0x02
+#define EGL_WINDOW_BIT		       0x04
+#define EGL_SLOW_CONFIG		       0x3050
+#define EGL_NON_CONFORMANT_CONFIG      0x3051
+#define EGL_TRANSPARENT_RGB	       0x3052
+
+/*
+** String names
+*/
+#define EGL_VENDOR		       0x3053
+#define EGL_VERSION		       0x3054
+#define EGL_EXTENSIONS		       0x3055
+
+/*
+** Surface attributes
+*/
+#define EGL_HEIGHT		       0x3056
+#define EGL_WIDTH		       0x3057
+#define EGL_LARGEST_PBUFFER	       0x3058
+
+/*
+** Current surfaces
+*/
+#define EGL_DRAW		       0x3059
+#define EGL_READ		       0x305A
+
+/*
+** Engines
+*/
+#define EGL_CORE_NATIVE_ENGINE	       0x305B
+
+/* 0x305C-0x3FFFF reserved for future use */
+
+/*
+** Functions
+*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GLAPI EGLint APIENTRY eglGetError (void);
+
+GLAPI EGLDisplay APIENTRY eglGetDisplay (NativeDisplayType display);
+GLAPI EGLBoolean APIENTRY eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);
+GLAPI EGLBoolean APIENTRY eglTerminate (EGLDisplay dpy);
+GLAPI const char * APIENTRY eglQueryString (EGLDisplay dpy, EGLint name);
+GLAPI void (* APIENTRY eglGetProcAddress (const char *procname))();
+
+GLAPI EGLBoolean APIENTRY eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+GLAPI EGLBoolean APIENTRY eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+GLAPI EGLBoolean APIENTRY eglGetConfigAttrib (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
+
+GLAPI EGLSurface APIENTRY eglCreateWindowSurface (EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list);
+GLAPI EGLSurface APIENTRY eglCreatePixmapSurface (EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list);
+GLAPI EGLSurface APIENTRY eglCreatePbufferSurface (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
+GLAPI EGLBoolean APIENTRY eglDestroySurface (EGLDisplay dpy, EGLSurface surface);
+GLAPI EGLBoolean APIENTRY eglQuerySurface (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
+
+GLAPI EGLContext APIENTRY eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list);
+GLAPI EGLBoolean APIENTRY eglDestroyContext (EGLDisplay dpy, EGLContext ctx);
+GLAPI EGLBoolean APIENTRY eglMakeCurrent (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+GLAPI EGLContext APIENTRY eglGetCurrentContext (void);
+GLAPI EGLSurface APIENTRY eglGetCurrentSurface (EGLint readdraw);
+GLAPI EGLDisplay APIENTRY eglGetCurrentDisplay (void);
+GLAPI EGLBoolean APIENTRY eglQueryContext (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
+
+GLAPI EGLBoolean APIENTRY eglWaitGL (void);
+GLAPI EGLBoolean APIENTRY eglWaitNative (EGLint engine);
+GLAPI EGLBoolean APIENTRY eglSwapBuffers (EGLDisplay dpy, EGLSurface draw);
+GLAPI EGLBoolean APIENTRY eglCopyBuffers (EGLDisplay dpy, EGLSurface surface, NativePixmapType target);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ___egl_h_ */
diff --git a/opengl/tests/angeles/include/GLES/egltypes.h b/opengl/tests/angeles/include/GLES/egltypes.h
new file mode 100644
index 0000000..9db36c9
--- /dev/null
+++ b/opengl/tests/angeles/include/GLES/egltypes.h
@@ -0,0 +1,20 @@
+/*
+** Types and resources
+*/
+typedef int EGLBoolean;
+typedef long EGLint;
+typedef void *EGLDisplay;
+typedef void *EGLConfig;
+typedef void *EGLSurface;
+typedef void *EGLContext;
+typedef void *NativeDisplayType;
+typedef void *NativeWindowType;
+typedef void *NativePixmapType;
+
+/*
+** EGL and native handle values
+*/
+#define EGL_DEFAULT_DISPLAY ((NativeDisplayType)0)
+#define EGL_NO_CONTEXT ((EGLContext)0)
+#define EGL_NO_DISPLAY ((EGLDisplay)0)
+#define EGL_NO_SURFACE ((EGLSurface)0)
diff --git a/opengl/tests/angeles/include/GLES/gl.h b/opengl/tests/angeles/include/GLES/gl.h
new file mode 100644
index 0000000..4154822
--- /dev/null
+++ b/opengl/tests/angeles/include/GLES/gl.h
@@ -0,0 +1,584 @@
+#ifndef __gl_h_
+#define __gl_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.0 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+** 
+** http://oss.sgi.com/projects/FreeB
+** 
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+** 
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+** 
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+*/
+
+#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__)
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef GLAPI
+#define GLAPI extern
+#endif
+
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef signed char GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef unsigned char GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef float GLfloat;
+typedef float GLclampf;
+typedef void GLvoid;
+typedef int GLintptrARB;
+typedef int GLsizeiptrARB;
+typedef int GLfixed;
+typedef int GLclampx;
+/* Internal convenience typedefs */
+typedef void (*_GLfuncptr)();
+
+/*************************************************************/
+
+/* Extensions */
+#define GL_OES_VERSION_1_0                1
+#define GL_OES_read_format                1
+#define GL_OES_compressed_paletted_texture 1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT               0x00000100
+#define GL_STENCIL_BUFFER_BIT             0x00000400
+#define GL_COLOR_BUFFER_BIT               0x00004000
+
+/* Boolean */
+#define GL_FALSE                          0
+#define GL_TRUE                           1
+
+/* BeginMode */
+#define GL_POINTS                         0x0000
+#define GL_LINES                          0x0001
+#define GL_LINE_LOOP                      0x0002
+#define GL_LINE_STRIP                     0x0003
+#define GL_TRIANGLES                      0x0004
+#define GL_TRIANGLE_STRIP                 0x0005
+#define GL_TRIANGLE_FAN                   0x0006
+
+/* AlphaFunction */
+#define GL_NEVER                          0x0200
+#define GL_LESS                           0x0201
+#define GL_EQUAL                          0x0202
+#define GL_LEQUAL                         0x0203
+#define GL_GREATER                        0x0204
+#define GL_NOTEQUAL                       0x0205
+#define GL_GEQUAL                         0x0206
+#define GL_ALWAYS                         0x0207
+
+/* BlendingFactorDest */
+#define GL_ZERO                           0
+#define GL_ONE                            1
+#define GL_SRC_COLOR                      0x0300
+#define GL_ONE_MINUS_SRC_COLOR            0x0301
+#define GL_SRC_ALPHA                      0x0302
+#define GL_ONE_MINUS_SRC_ALPHA            0x0303
+#define GL_DST_ALPHA                      0x0304
+#define GL_ONE_MINUS_DST_ALPHA            0x0305
+
+/* BlendingFactorSrc */
+/*      GL_ZERO */
+/*      GL_ONE */
+#define GL_DST_COLOR                      0x0306
+#define GL_ONE_MINUS_DST_COLOR            0x0307
+#define GL_SRC_ALPHA_SATURATE             0x0308
+/*      GL_SRC_ALPHA */
+/*      GL_ONE_MINUS_SRC_ALPHA */
+/*      GL_DST_ALPHA */
+/*      GL_ONE_MINUS_DST_ALPHA */
+
+/* ColorMaterialFace */
+/*      GL_FRONT_AND_BACK */
+
+/* ColorMaterialParameter */
+/*      GL_AMBIENT_AND_DIFFUSE */
+
+/* ColorPointerType */
+/*      GL_UNSIGNED_BYTE */
+/*      GL_FLOAT */
+/*      GL_FIXED */
+
+/* CullFaceMode */
+#define GL_FRONT                          0x0404
+#define GL_BACK                           0x0405
+#define GL_FRONT_AND_BACK                 0x0408
+
+/* DepthFunction */
+/*      GL_NEVER */
+/*      GL_LESS */
+/*      GL_EQUAL */
+/*      GL_LEQUAL */
+/*      GL_GREATER */
+/*      GL_NOTEQUAL */
+/*      GL_GEQUAL */
+/*      GL_ALWAYS */
+
+/* EnableCap */
+#define GL_FOG                            0x0B60
+#define GL_LIGHTING                       0x0B50
+#define GL_TEXTURE_2D                     0x0DE1
+#define GL_CULL_FACE                      0x0B44
+#define GL_ALPHA_TEST                     0x0BC0
+#define GL_BLEND                          0x0BE2
+#define GL_COLOR_LOGIC_OP                 0x0BF2
+#define GL_DITHER                         0x0BD0
+#define GL_STENCIL_TEST                   0x0B90
+#define GL_DEPTH_TEST                     0x0B71
+/*      GL_LIGHT0 */
+/*      GL_LIGHT1 */
+/*      GL_LIGHT2 */
+/*      GL_LIGHT3 */
+/*      GL_LIGHT4 */
+/*      GL_LIGHT5 */
+/*      GL_LIGHT6 */
+/*      GL_LIGHT7 */
+#define GL_POINT_SMOOTH                   0x0B10
+#define GL_LINE_SMOOTH                    0x0B20
+#define GL_SCISSOR_TEST                   0x0C11
+#define GL_COLOR_MATERIAL                 0x0B57
+#define GL_NORMALIZE                      0x0BA1
+#define GL_RESCALE_NORMAL                 0x803A
+#define GL_POLYGON_OFFSET_FILL            0x8037
+#define GL_VERTEX_ARRAY                   0x8074
+#define GL_NORMAL_ARRAY                   0x8075
+#define GL_COLOR_ARRAY                    0x8076
+#define GL_TEXTURE_COORD_ARRAY            0x8078
+#define GL_MULTISAMPLE                    0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE       0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE            0x809F
+#define GL_SAMPLE_COVERAGE                0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR                       0
+#define GL_INVALID_ENUM                   0x0500
+#define GL_INVALID_VALUE                  0x0501
+#define GL_INVALID_OPERATION              0x0502
+#define GL_STACK_OVERFLOW                 0x0503
+#define GL_STACK_UNDERFLOW                0x0504
+#define GL_OUT_OF_MEMORY                  0x0505
+
+/* FogMode */
+/*      GL_LINEAR */
+#define GL_EXP                            0x0800
+#define GL_EXP2                           0x0801
+
+/* FogParameter */
+#define GL_FOG_DENSITY                    0x0B62
+#define GL_FOG_START                      0x0B63
+#define GL_FOG_END                        0x0B64
+#define GL_FOG_MODE                       0x0B65
+#define GL_FOG_COLOR                      0x0B66
+
+/* FrontFaceDirection */
+#define GL_CW                             0x0900
+#define GL_CCW                            0x0901
+
+/* GetPName */
+#define GL_SMOOTH_POINT_SIZE_RANGE        0x0B12
+#define GL_SMOOTH_LINE_WIDTH_RANGE        0x0B22
+#define GL_ALIASED_POINT_SIZE_RANGE       0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE       0x846E
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
+#define GL_MAX_LIGHTS                     0x0D31
+#define GL_MAX_TEXTURE_SIZE               0x0D33
+#define GL_MAX_MODELVIEW_STACK_DEPTH      0x0D36
+#define GL_MAX_PROJECTION_STACK_DEPTH     0x0D38
+#define GL_MAX_TEXTURE_STACK_DEPTH        0x0D39
+#define GL_MAX_VIEWPORT_DIMS              0x0D3A
+#define GL_MAX_ELEMENTS_VERTICES          0x80E8
+#define GL_MAX_ELEMENTS_INDICES           0x80E9
+#define GL_MAX_TEXTURE_UNITS              0x84E2
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS     0x86A3
+#define GL_SUBPIXEL_BITS                  0x0D50
+#define GL_RED_BITS                       0x0D52
+#define GL_GREEN_BITS                     0x0D53
+#define GL_BLUE_BITS                      0x0D54
+#define GL_ALPHA_BITS                     0x0D55
+#define GL_DEPTH_BITS                     0x0D56
+#define GL_STENCIL_BITS                   0x0D57
+
+/* HintMode */
+#define GL_DONT_CARE                      0x1100
+#define GL_FASTEST                        0x1101
+#define GL_NICEST                         0x1102
+
+/* HintTarget */
+#define GL_PERSPECTIVE_CORRECTION_HINT    0x0C50
+#define GL_POINT_SMOOTH_HINT              0x0C51
+#define GL_LINE_SMOOTH_HINT               0x0C52
+#define GL_POLYGON_SMOOTH_HINT            0x0C53
+#define GL_FOG_HINT                       0x0C54
+
+/* LightModelParameter */
+#define GL_LIGHT_MODEL_AMBIENT            0x0B53
+#define GL_LIGHT_MODEL_TWO_SIDE           0x0B52
+
+/* LightParameter */
+#define GL_AMBIENT                        0x1200
+#define GL_DIFFUSE                        0x1201
+#define GL_SPECULAR                       0x1202
+#define GL_POSITION                       0x1203
+#define GL_SPOT_DIRECTION                 0x1204
+#define GL_SPOT_EXPONENT                  0x1205
+#define GL_SPOT_CUTOFF                    0x1206
+#define GL_CONSTANT_ATTENUATION           0x1207
+#define GL_LINEAR_ATTENUATION             0x1208
+#define GL_QUADRATIC_ATTENUATION          0x1209
+
+/* DataType */
+#define GL_BYTE                           0x1400
+#define GL_UNSIGNED_BYTE                  0x1401
+#define GL_SHORT                          0x1402
+#define GL_UNSIGNED_SHORT                 0x1403
+#define GL_FLOAT                          0x1406
+#define GL_FIXED                          0x140C
+
+/* LogicOp */
+#define GL_CLEAR                          0x1500
+#define GL_AND                            0x1501
+#define GL_AND_REVERSE                    0x1502
+#define GL_COPY                           0x1503
+#define GL_AND_INVERTED                   0x1504
+#define GL_NOOP                           0x1505
+#define GL_XOR                            0x1506
+#define GL_OR                             0x1507
+#define GL_NOR                            0x1508
+#define GL_EQUIV                          0x1509
+#define GL_INVERT                         0x150A
+#define GL_OR_REVERSE                     0x150B
+#define GL_COPY_INVERTED                  0x150C
+#define GL_OR_INVERTED                    0x150D
+#define GL_NAND                           0x150E
+#define GL_SET                            0x150F
+
+/* MaterialFace */
+/*      GL_FRONT_AND_BACK */
+
+/* MaterialParameter */
+#define GL_EMISSION                       0x1600
+#define GL_SHININESS                      0x1601
+#define GL_AMBIENT_AND_DIFFUSE            0x1602
+/*      GL_AMBIENT */
+/*      GL_DIFFUSE */
+/*      GL_SPECULAR */
+
+/* MatrixMode */
+#define GL_MODELVIEW                      0x1700
+#define GL_PROJECTION                     0x1701
+#define GL_TEXTURE                        0x1702
+
+/* NormalPointerType */
+/*      GL_BYTE */
+/*      GL_SHORT */
+/*      GL_FLOAT */
+/*      GL_FIXED */
+
+/* PixelFormat */
+#define GL_ALPHA                          0x1906
+#define GL_RGB                            0x1907
+#define GL_RGBA                           0x1908
+#define GL_LUMINANCE                      0x1909
+#define GL_LUMINANCE_ALPHA                0x190A
+
+/* PixelStoreParameter */
+#define GL_UNPACK_ALIGNMENT               0x0CF5
+#define GL_PACK_ALIGNMENT                 0x0D05
+
+/* PixelType */
+/*      GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4         0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1         0x8034
+#define GL_UNSIGNED_SHORT_5_6_5           0x8363
+
+/* ShadingModel */
+#define GL_FLAT                           0x1D00
+#define GL_SMOOTH                         0x1D01
+
+/* StencilFunction */
+/*      GL_NEVER */
+/*      GL_LESS */
+/*      GL_EQUAL */
+/*      GL_LEQUAL */
+/*      GL_GREATER */
+/*      GL_NOTEQUAL */
+/*      GL_GEQUAL */
+/*      GL_ALWAYS */
+
+/* StencilOp */
+/*      GL_ZERO */
+#define GL_KEEP                           0x1E00
+#define GL_REPLACE                        0x1E01
+#define GL_INCR                           0x1E02
+#define GL_DECR                           0x1E03
+/*      GL_INVERT */
+
+/* StringName */
+#define GL_VENDOR                         0x1F00
+#define GL_RENDERER                       0x1F01
+#define GL_VERSION                        0x1F02
+#define GL_EXTENSIONS                     0x1F03
+
+/* TexCoordPointerType */
+/*      GL_SHORT */
+/*      GL_FLOAT */
+/*      GL_FIXED */
+/*      GL_BYTE */
+
+/* TextureEnvMode */
+#define GL_MODULATE                       0x2100
+#define GL_DECAL                          0x2101
+/*      GL_BLEND */
+#define GL_ADD                            0x0104
+/*      GL_REPLACE */
+
+/* TextureEnvParameter */
+#define GL_TEXTURE_ENV_MODE               0x2200
+#define GL_TEXTURE_ENV_COLOR              0x2201
+
+/* TextureEnvTarget */
+#define GL_TEXTURE_ENV                    0x2300
+
+/* TextureMagFilter */
+#define GL_NEAREST                        0x2600
+#define GL_LINEAR                         0x2601
+
+/* TextureMinFilter */
+/*      GL_NEAREST */
+/*      GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST         0x2700
+#define GL_LINEAR_MIPMAP_NEAREST          0x2701
+#define GL_NEAREST_MIPMAP_LINEAR          0x2702
+#define GL_LINEAR_MIPMAP_LINEAR           0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER             0x2800
+#define GL_TEXTURE_MIN_FILTER             0x2801
+#define GL_TEXTURE_WRAP_S                 0x2802
+#define GL_TEXTURE_WRAP_T                 0x2803
+
+/* TextureTarget */
+/*      GL_TEXTURE_2D */
+
+/* TextureUnit */
+#define GL_TEXTURE0                       0x84C0
+#define GL_TEXTURE1                       0x84C1
+#define GL_TEXTURE2                       0x84C2
+#define GL_TEXTURE3                       0x84C3
+#define GL_TEXTURE4                       0x84C4
+#define GL_TEXTURE5                       0x84C5
+#define GL_TEXTURE6                       0x84C6
+#define GL_TEXTURE7                       0x84C7
+#define GL_TEXTURE8                       0x84C8
+#define GL_TEXTURE9                       0x84C9
+#define GL_TEXTURE10                      0x84CA
+#define GL_TEXTURE11                      0x84CB
+#define GL_TEXTURE12                      0x84CC
+#define GL_TEXTURE13                      0x84CD
+#define GL_TEXTURE14                      0x84CE
+#define GL_TEXTURE15                      0x84CF
+#define GL_TEXTURE16                      0x84D0
+#define GL_TEXTURE17                      0x84D1
+#define GL_TEXTURE18                      0x84D2
+#define GL_TEXTURE19                      0x84D3
+#define GL_TEXTURE20                      0x84D4
+#define GL_TEXTURE21                      0x84D5
+#define GL_TEXTURE22                      0x84D6
+#define GL_TEXTURE23                      0x84D7
+#define GL_TEXTURE24                      0x84D8
+#define GL_TEXTURE25                      0x84D9
+#define GL_TEXTURE26                      0x84DA
+#define GL_TEXTURE27                      0x84DB
+#define GL_TEXTURE28                      0x84DC
+#define GL_TEXTURE29                      0x84DD
+#define GL_TEXTURE30                      0x84DE
+#define GL_TEXTURE31                      0x84DF
+
+/* TextureWrapMode */
+#define GL_REPEAT                         0x2901
+#define GL_CLAMP_TO_EDGE                  0x812F
+
+/* PixelInternalFormat */
+#define GL_PALETTE4_RGB8_OES              0x8B90
+#define GL_PALETTE4_RGBA8_OES             0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES          0x8B92
+#define GL_PALETTE4_RGBA4_OES             0x8B93
+#define GL_PALETTE4_RGB5_A1_OES           0x8B94
+#define GL_PALETTE8_RGB8_OES              0x8B95
+#define GL_PALETTE8_RGBA8_OES             0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES          0x8B97
+#define GL_PALETTE8_RGBA4_OES             0x8B98
+#define GL_PALETTE8_RGB5_A1_OES           0x8B99
+
+/* VertexPointerType */
+/*      GL_SHORT */
+/*      GL_FLOAT */
+/*      GL_FIXED */
+/*      GL_BYTE */
+
+/* LightName */
+#define GL_LIGHT0                         0x4000
+#define GL_LIGHT1                         0x4001
+#define GL_LIGHT2                         0x4002
+#define GL_LIGHT3                         0x4003
+#define GL_LIGHT4                         0x4004
+#define GL_LIGHT5                         0x4005
+#define GL_LIGHT6                         0x4006
+#define GL_LIGHT7                         0x4007
+
+
+/*************************************************************/
+
+GLAPI void APIENTRY glActiveTexture (GLenum texture);
+GLAPI void APIENTRY glAlphaFunc (GLenum func, GLclampf ref);
+GLAPI void APIENTRY glAlphaFuncx (GLenum func, GLclampx ref);
+GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture);
+GLAPI void APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GLAPI void APIENTRY glClear (GLbitfield mask);
+GLAPI void APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GLAPI void APIENTRY glClearColorx (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
+GLAPI void APIENTRY glClearDepthf (GLclampf depth);
+GLAPI void APIENTRY glClearDepthx (GLclampx depth);
+GLAPI void APIENTRY glClearStencil (GLint s);
+GLAPI void APIENTRY glClientActiveTexture (GLenum texture);
+GLAPI void APIENTRY glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GLAPI void APIENTRY glColor4x (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GLAPI void APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GLAPI void APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+GLAPI void APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GLAPI void APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glCullFace (GLenum mode);
+GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
+GLAPI void APIENTRY glDepthFunc (GLenum func);
+GLAPI void APIENTRY glDepthMask (GLboolean flag);
+GLAPI void APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GLAPI void APIENTRY glDepthRangex (GLclampx zNear, GLclampx zFar);
+GLAPI void APIENTRY glDisable (GLenum cap);
+GLAPI void APIENTRY glDisableClientState (GLenum array);
+GLAPI void APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+GLAPI void APIENTRY glEnable (GLenum cap);
+GLAPI void APIENTRY glEnableClientState (GLenum array);
+GLAPI void APIENTRY glFinish (void);
+GLAPI void APIENTRY glFlush (void);
+GLAPI void APIENTRY glFogf (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glFogfv (GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glFogx (GLenum pname, GLfixed param);
+GLAPI void APIENTRY glFogxv (GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glFrontFace (GLenum mode);
+GLAPI void APIENTRY glFrustumf (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GLAPI void APIENTRY glFrustumx (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);
+GLAPI GLenum APIENTRY glGetError (void);
+GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *params);
+GLAPI const GLubyte * APIENTRY glGetString (GLenum name);
+GLAPI void APIENTRY glHint (GLenum target, GLenum mode);
+GLAPI void APIENTRY glLightModelf (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glLightModelfv (GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glLightModelx (GLenum pname, GLfixed param);
+GLAPI void APIENTRY glLightModelxv (GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glLightf (GLenum light, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glLightfv (GLenum light, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glLightx (GLenum light, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glLightxv (GLenum light, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glLineWidth (GLfloat width);
+GLAPI void APIENTRY glLineWidthx (GLfixed width);
+GLAPI void APIENTRY glLoadIdentity (void);
+GLAPI void APIENTRY glLoadMatrixf (const GLfloat *m);
+GLAPI void APIENTRY glLoadMatrixx (const GLfixed *m);
+GLAPI void APIENTRY glLogicOp (GLenum opcode);
+GLAPI void APIENTRY glMaterialf (GLenum face, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glMaterialfv (GLenum face, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glMaterialx (GLenum face, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glMaterialxv (GLenum face, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glMatrixMode (GLenum mode);
+GLAPI void APIENTRY glMultMatrixf (const GLfloat *m);
+GLAPI void APIENTRY glMultMatrixx (const GLfixed *m);
+GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+GLAPI void APIENTRY glMultiTexCoord4x (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GLAPI void APIENTRY glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz);
+GLAPI void APIENTRY glNormal3x (GLfixed nx, GLfixed ny, GLfixed nz);
+GLAPI void APIENTRY glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer);
+GLAPI void APIENTRY glOrthof (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GLAPI void APIENTRY glOrthox (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param);
+GLAPI void APIENTRY glPointSize (GLfloat size);
+GLAPI void APIENTRY glPointSizex (GLfixed size);
+GLAPI void APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GLAPI void APIENTRY glPolygonOffsetx (GLfixed factor, GLfixed units);
+GLAPI void APIENTRY glPopMatrix (void);
+GLAPI void APIENTRY glPushMatrix (void);
+GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+GLAPI void APIENTRY glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GLAPI void APIENTRY glSampleCoveragex (GLclampx value, GLboolean invert);
+GLAPI void APIENTRY glScalef (GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glScalex (GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glShadeModel (GLenum mode);
+GLAPI void APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GLAPI void APIENTRY glStencilMask (GLuint mask);
+GLAPI void APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GLAPI void APIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GLAPI void APIENTRY glTexEnvf (GLenum target, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glTexEnvx (GLenum target, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glTexEnvxv (GLenum target, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+GLAPI void APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glTexParameterx (GLenum target, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+GLAPI void APIENTRY glTranslatef (GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glTranslatex (GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl_h_ */
diff --git a/opengl/tests/angeles/license-BSD.txt b/opengl/tests/angeles/license-BSD.txt
new file mode 100644
index 0000000..8924e3c
--- /dev/null
+++ b/opengl/tests/angeles/license-BSD.txt
@@ -0,0 +1,34 @@
+This is the BSD-style license for the "San Angeles Observation"

+OpenGL ES version example source code

+---------------------------------------------------------------

+

+San Angeles Observation OpenGL ES version example

+Copyright (c) 2004-2005, Jetro Lauha

+All rights reserved.

+

+Redistribution and use in source and binary forms, with or without

+modification, are permitted provided that the following conditions

+are met:

+

+    * Redistributions of source code must retain the above copyright

+      notice, this list of conditions and the following disclaimer.

+    * Redistributions in binary form must reproduce the above copyright

+      notice, this list of conditions and the following disclaimer in

+      the documentation and/or other materials provided with the

+      distribution.

+    * Neither the name of the software product's copyright owner nor

+      the names of its contributors may be used to endorse or promote

+      products derived from this software without specific prior written

+      permission.

+

+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED

+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR

+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF

+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING

+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

diff --git a/opengl/tests/angeles/license-LGPL.txt b/opengl/tests/angeles/license-LGPL.txt
new file mode 100644
index 0000000..b1e3f5a
--- /dev/null
+++ b/opengl/tests/angeles/license-LGPL.txt
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/opengl/tests/angeles/license.txt b/opengl/tests/angeles/license.txt
new file mode 100644
index 0000000..620841e
--- /dev/null
+++ b/opengl/tests/angeles/license.txt
@@ -0,0 +1,19 @@
+San Angeles Observation OpenGL ES version example

+Copyright 2004-2005 Jetro Lauha

+All rights reserved.

+Web: http://iki.fi/jetro/

+

+This source is free software; you can redistribute it and/or

+modify it under the terms of EITHER:

+  (1) The GNU Lesser General Public License as published by the Free

+      Software Foundation; either version 2.1 of the License, or (at

+      your option) any later version. The text of the GNU Lesser

+      General Public License is included with this source in the

+      file LICENSE-LGPL.txt.

+  (2) The BSD-style license that is included with this source in

+      the file LICENSE-BSD.txt.

+

+This source is distributed in the hope that it will be useful,

+but WITHOUT ANY WARRANTY; without even the implied warranty of

+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files

+LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.

diff --git a/opengl/tests/angeles/shapes.h b/opengl/tests/angeles/shapes.h
new file mode 100644
index 0000000..25ffae8
--- /dev/null
+++ b/opengl/tests/angeles/shapes.h
@@ -0,0 +1,59 @@
+/* San Angeles Observation OpenGL ES version example
+ * Copyright 2004-2005 Jetro Lauha
+ * All rights reserved.
+ * Web: http://iki.fi/jetro/
+ *
+ * This source is free software; you can redistribute it and/or
+ * modify it under the terms of EITHER:
+ *   (1) The GNU Lesser General Public License as published by the Free
+ *       Software Foundation; either version 2.1 of the License, or (at
+ *       your option) any later version. The text of the GNU Lesser
+ *       General Public License is included with this source in the
+ *       file LICENSE-LGPL.txt.
+ *   (2) The BSD-style license that is included with this source in
+ *       the file LICENSE-BSD.txt.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
+ * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
+ *
+ * $Id: shapes.h,v 1.6 2005/01/31 22:15:30 tonic Exp $
+ * $Revision: 1.6 $
+ */
+
+#ifndef SHAPES_H_INCLUDED
+#define SHAPES_H_INCLUDED
+
+
+#define SUPERSHAPE_PARAMS 15
+
+static const float sSuperShapeParams[][SUPERSHAPE_PARAMS] =
+{
+    // m  a     b     n1      n2     n3     m     a     b     n1     n2      n3   res1 res2 scale  (org.res1,res2)
+    { 10, 1,    2,    90,      1,   -45,    8,    1,    1,    -1,     1,  -0.4f,   20,  30, 2 }, // 40, 60
+    { 10, 1,    2,    90,      1,   -45,    4,    1,    1,    10,     1,  -0.4f,   20,  20, 4 }, // 40, 40
+    { 10, 1,    2,    60,      1,   -10,    4,    1,    1,    -1,    -2,  -0.4f,   41,  41, 1 }, // 82, 82
+    {  6, 1,    1,    60,      1,   -70,    8,    1,    1,  0.4f,     3,  0.25f,   20,  20, 1 }, // 40, 40
+    {  4, 1,    1,    30,      1,    20,   12,    1,    1,  0.4f,     3,  0.25f,   10,  30, 1 }, // 20, 60
+    {  8, 1,    1,    30,      1,    -4,    8,    2,    1,    -1,     5,   0.5f,   25,  26, 1 }, // 60, 60
+    { 13, 1,    1,    30,      1,    -4,   13,    1,    1,     1,     5,      1,   30,  30, 6 }, // 60, 60
+    { 10, 1, 1.1f, -0.5f,   0.1f,    70,   60,    1,    1,   -90,     0, -0.25f,   20,  60, 8 }, // 60, 180
+    {  7, 1,    1,    20,  -0.3f, -3.5f,    6,    1,    1,    -1,  4.5f,   0.5f,   10,  20, 4 }, // 60, 80
+    {  4, 1,    1,    10,     10,    10,    4,    1,    1,    10,    10,     10,   10,  20, 1 }, // 20, 40
+    {  4, 1,    1,     1,      1,     1,    4,    1,    1,     1,     1,      1,   10,  10, 2 }, // 10, 10
+    {  1, 1,    1,    38, -0.25f,    19,    4,    1,    1,    10,    10,     10,   10,  15, 2 }, // 20, 40
+    {  2, 1,    1,  0.7f,   0.3f,  0.2f,    3,    1,    1,   100,   100,    100,   10,  25, 2 }, // 20, 50
+    {  6, 1,    1,     1,      1,     1,    3,    1,    1,     1,     1,      1,   30,  30, 2 }, // 60, 60
+    {  3, 1,    1,     1,      1,     1,    6,    1,    1,     2,     1,      1,   10,  20, 2 }, // 20, 40
+    {  6, 1,    1,     6,   5.5f,   100,    6,    1,    1,    25,    10,     10,   30,  20, 2 }, // 60, 40
+    {  3, 1,    1,  0.5f,   1.7f,  1.7f,    2,    1,    1,    10,    10,     10,   20,  20, 2 }, // 40, 40
+    {  5, 1,    1,  0.1f,   1.7f,  1.7f,    1,    1,    1,  0.3f,  0.5f,   0.5f,   20,  20, 4 }, // 40, 40
+    {  2, 1,    1,     6,   5.5f,   100,    6,    1,    1,     4,    10,     10,   10,  22, 1 }, // 40, 40
+    {  6, 1,    1,    -1,     70,  0.1f,    9,    1, 0.5f,   -98, 0.05f,    -45,   20,  30, 4 }, // 60, 91
+    {  6, 1,    1,    -1,     90, -0.1f,    7,    1,    1,    90,  1.3f,     34,   13,  16, 1 }, // 32, 60
+};
+#define SUPERSHAPE_COUNT (sizeof(sSuperShapeParams) / sizeof(sSuperShapeParams[0]))
+
+
+#endif // !SHAPES_H_INCLUDED
diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk
new file mode 100644
index 0000000..a448f0d
--- /dev/null
+++ b/opengl/tests/filter/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	filter.c
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+    libEGL \
+    libGLESv1_CM \
+    libui
+
+LOCAL_MODULE:= test-opengl-filter
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/filter/filter.c b/opengl/tests/filter/filter.c
new file mode 100644
index 0000000..de97119
--- /dev/null
+++ b/opengl/tests/filter/filter.c
@@ -0,0 +1,130 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+int main(int argc, char** argv)
+{
+    if (argc!=2 && argc!=3) {
+        printf("usage: %s <0-6> [pbuffer]\n", argv[0]);
+        return 0;
+    }
+    
+    const int test = atoi(argv[1]);
+    int usePbuffer = argc==3 && !strcmp(argv[2], "pbuffer");
+    EGLint s_configAttribs[] = {
+         EGL_SURFACE_TYPE, EGL_PBUFFER_BIT|EGL_WINDOW_BIT,
+         EGL_RED_SIZE,       5,
+         EGL_GREEN_SIZE,     6,
+         EGL_BLUE_SIZE,      5,
+         EGL_NONE
+     };
+     
+     EGLint numConfigs = -1;
+     EGLint majorVersion;
+     EGLint minorVersion;
+     EGLConfig config;
+     EGLContext context;
+     EGLSurface surface;
+     EGLint w, h;
+     
+     EGLDisplay dpy;
+
+     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+     eglInitialize(dpy, &majorVersion, &minorVersion);
+     eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
+     if (!usePbuffer) {
+         surface = eglCreateWindowSurface(dpy, config,
+                 android_createDisplaySurface(), NULL);
+     } else {
+         printf("using pbuffer\n");
+         EGLint attribs[] = { EGL_WIDTH, 320, EGL_HEIGHT, 480, EGL_NONE };
+         surface = eglCreatePbufferSurface(dpy, config, attribs);
+         if (surface == EGL_NO_SURFACE) {
+             printf("eglCreatePbufferSurface error %x\n", eglGetError());
+         }
+     }
+     context = eglCreateContext(dpy, config, NULL, NULL);
+     eglMakeCurrent(dpy, surface, surface, context);   
+     eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+     GLint dim = w<h ? w : h;
+
+     glClear(GL_COLOR_BUFFER_BIT);
+
+     GLint crop[4] = { 0, 4, 4, -4 };
+     glBindTexture(GL_TEXTURE_2D, 0);
+     glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+     glEnable(GL_TEXTURE_2D);
+     glColor4f(1,1,1,1);
+
+     // packing is always 4
+     uint8_t t8[]  = { 
+             0x00, 0x55, 0x00, 0x55, 
+             0xAA, 0xFF, 0xAA, 0xFF,
+             0x00, 0x55, 0x00, 0x55, 
+             0xAA, 0xFF, 0xAA, 0xFF  };
+
+     uint16_t t16[]  = { 
+             0x0000, 0x5555, 0x0000, 0x5555, 
+             0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF,
+             0x0000, 0x5555, 0x0000, 0x5555, 
+             0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF  };
+
+     uint16_t t5551[]  = { 
+             0x0000, 0xFFFF, 0x0000, 0xFFFF, 
+             0xFFFF, 0x0000, 0xFFFF, 0x0000,
+             0x0000, 0xFFFF, 0x0000, 0xFFFF, 
+             0xFFFF, 0x0000, 0xFFFF, 0x0000  };
+
+     uint32_t t32[]  = { 
+             0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 
+             0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF, 
+             0xFF00FFFF, 0xFF00FF00, 0x00FF00FF, 0xFFFFFF00, 
+             0xFF000000, 0xFFFF00FF, 0xFF00FFFF, 0xFFFFFFFF
+     };
+
+     switch(test) 
+     {
+     case 1:
+         glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
+                 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, t8);
+         break;
+     case 2:
+         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+                 4, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16);
+         break;
+     case 3:
+         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+                 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t16);
+         break;
+     case 4:
+         glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
+                 4, 4, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, t16);
+         break;
+     case 5:
+         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+                 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, t5551);
+         break;
+     case 6:
+         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+                 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
+         break;
+     }
+
+     glDrawTexiOES(0, 0, 0, dim, dim);
+
+     if (!usePbuffer) {
+         eglSwapBuffers(dpy, surface);
+     } else {
+         glFinish();
+     }
+     
+     eglTerminate(dpy);
+     return 0;
+}
diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk
new file mode 100644
index 0000000..26836c1
--- /dev/null
+++ b/opengl/tests/finish/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	finish.c
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+    libEGL \
+    libGLESv1_CM \
+    libui
+
+LOCAL_MODULE:= test-opengl-finish
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/finish/finish.c b/opengl/tests/finish/finish.c
new file mode 100644
index 0000000..45fc758
--- /dev/null
+++ b/opengl/tests/finish/finish.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2007 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 <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+
+long long systemTime()
+{
+    struct timespec t;
+    t.tv_sec = t.tv_nsec = 0;
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    return (long long)(t.tv_sec)*1000000000LL + t.tv_nsec;
+}
+
+int main(int argc, char** argv)
+{
+    EGLint s_configAttribs[] = {
+         EGL_RED_SIZE,       5,
+         EGL_GREEN_SIZE,     6,
+         EGL_BLUE_SIZE,      5,
+         EGL_NONE
+     };
+     
+     EGLint numConfigs = -1;
+     EGLint majorVersion;
+     EGLint minorVersion;
+     EGLConfig config;
+     EGLContext context;
+     EGLSurface surface;
+     EGLint w, h;
+     
+     EGLDisplay dpy;
+
+     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+     eglInitialize(dpy, &majorVersion, &minorVersion);
+     eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
+     surface = eglCreateWindowSurface(dpy, config, 
+             android_createDisplaySurface(), NULL);
+     context = eglCreateContext(dpy, config, NULL, NULL);
+     eglMakeCurrent(dpy, surface, surface, context);   
+     eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+     GLint dim = w<h ? w : h;
+
+     glBindTexture(GL_TEXTURE_2D, 0);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+     glEnable(GL_TEXTURE_2D);
+     glColor4f(1,1,1,1);
+     glDisable(GL_DITHER);
+     glShadeModel(GL_FLAT);
+
+     long long now, t;
+     int i;
+
+     char* texels = malloc(512*512*2);
+     memset(texels,0xFF,512*512*2);
+     
+     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+             512, 512, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texels);
+
+     char* dst = malloc(320*480*2);
+     memset(dst, 0, 320*480*2);
+     printf("307200 bytes memcpy\n");
+     for (i=0 ; i<4 ; i++) {
+         now = systemTime();
+         memcpy(dst, texels, 320*480*2);
+         t = systemTime();
+         printf("memcpy() time = %llu us\n", (t-now)/1000);
+         fflush(stdout);
+     }
+     free(dst);
+
+     free(texels);
+
+     setpriority(PRIO_PROCESS, 0, -20);
+     
+     printf("512x512 unmodified texture, 512x512 blit:\n");
+     glClear(GL_COLOR_BUFFER_BIT);
+     for (i=0 ; i<4 ; i++) {
+         GLint crop[4] = { 0, 512, 512, -512 };
+         glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+         now = systemTime();
+         glDrawTexiOES(0, 0, 0, 512, 512);
+         glFinish();
+         t = systemTime();
+         printf("glFinish() time = %llu us\n", (t-now)/1000);
+         fflush(stdout);
+         eglSwapBuffers(dpy, surface);
+     }
+     
+     printf("512x512 unmodified texture, 1x1 blit:\n");
+     glClear(GL_COLOR_BUFFER_BIT);
+     for (i=0 ; i<4 ; i++) {
+         GLint crop[4] = { 0, 1, 1, -1 };
+         glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+         now = systemTime();
+         glDrawTexiOES(0, 0, 0, 1, 1);
+         glFinish();
+         t = systemTime();
+         printf("glFinish() time = %llu us\n", (t-now)/1000);
+         fflush(stdout);
+         eglSwapBuffers(dpy, surface);
+     }
+     
+     printf("512x512 unmodified texture, 512x512 blit (x2):\n");
+     glClear(GL_COLOR_BUFFER_BIT);
+     for (i=0 ; i<4 ; i++) {
+         GLint crop[4] = { 0, 512, 512, -512 };
+         glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+         now = systemTime();
+         glDrawTexiOES(0, 0, 0, 512, 512);
+         glDrawTexiOES(0, 0, 0, 512, 512);
+         glFinish();
+         t = systemTime();
+         printf("glFinish() time = %llu us\n", (t-now)/1000);
+         fflush(stdout);
+         eglSwapBuffers(dpy, surface);
+     }
+
+     printf("512x512 unmodified texture, 1x1 blit (x2):\n");
+     glClear(GL_COLOR_BUFFER_BIT);
+     for (i=0 ; i<4 ; i++) {
+         GLint crop[4] = { 0, 1, 1, -1 };
+         glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+         now = systemTime();
+         glDrawTexiOES(0, 0, 0, 1, 1);
+         glDrawTexiOES(0, 0, 0, 1, 1);
+         glFinish();
+         t = systemTime();
+         printf("glFinish() time = %llu us\n", (t-now)/1000);
+         fflush(stdout);
+         eglSwapBuffers(dpy, surface);
+     }
+
+     
+     printf("512x512 (1x1 texel MODIFIED texture), 512x512 blit:\n");
+     glClear(GL_COLOR_BUFFER_BIT);
+     for (i=0 ; i<4 ; i++) {
+         uint16_t green = 0x7E0;
+         GLint crop[4] = { 0, 512, 512, -512 };
+         glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &green);
+         now = systemTime();
+         glDrawTexiOES(0, 0, 0, 512, 512);
+         glFinish();
+         t = systemTime();
+         printf("glFinish() time = %llu us\n", (t-now)/1000);
+         fflush(stdout);
+         eglSwapBuffers(dpy, surface);
+     }
+
+
+     int16_t texel = 0xF800;
+     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+             1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &texel);
+
+     printf("1x1 unmodified texture, 1x1 blit:\n");
+     glClear(GL_COLOR_BUFFER_BIT);
+     for (i=0 ; i<4 ; i++) {
+         GLint crop[4] = { 0, 1, 1, -1 };
+         glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+         now = systemTime();
+         glDrawTexiOES(0, 0, 0, 1, 1);
+         glFinish();
+         t = systemTime();
+         printf("glFinish() time = %llu us\n", (t-now)/1000);
+         eglSwapBuffers(dpy, surface);
+     }
+
+     printf("1x1 unmodified texture, 512x512 blit:\n");
+     glClear(GL_COLOR_BUFFER_BIT);
+     for (i=0 ; i<4 ; i++) {
+         GLint crop[4] = { 0, 1, 1, -1 };
+         glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+         now = systemTime();
+         glDrawTexiOES(0, 0, 0, 512, 512);
+         glFinish();
+         t = systemTime();
+         printf("glFinish() time = %llu us\n", (t-now)/1000);
+         fflush(stdout);
+         eglSwapBuffers(dpy, surface);
+     }
+
+     printf("1x1 (1x1 texel MODIFIED texture), 512x512 blit:\n");
+     glClear(GL_COLOR_BUFFER_BIT);
+     for (i=0 ; i<4 ; i++) {
+         uint16_t green = 0x7E0;
+         GLint crop[4] = { 0, 1, 1, -1 };
+         glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &green);
+         now = systemTime();
+         glDrawTexiOES(0, 0, 0, 1, 1);
+         glFinish();
+         t = systemTime();
+         printf("glFinish() time = %llu us\n", (t-now)/1000);
+         fflush(stdout);
+         eglSwapBuffers(dpy, surface);
+     }
+
+     return 0;
+}
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
new file mode 100644
index 0000000..a8c6220
--- /dev/null
+++ b/opengl/tests/textures/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	textures.c
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+    libEGL \
+    libGLESv1_CM \
+    libui
+
+LOCAL_MODULE:= test-opengl-textures
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/textures/textures.c b/opengl/tests/textures/textures.c
new file mode 100644
index 0000000..214291b
--- /dev/null
+++ b/opengl/tests/textures/textures.c
@@ -0,0 +1,109 @@
+/*
+**
+** Copyright 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 <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+int main(int argc, char** argv)
+{
+    EGLint s_configAttribs[] = {
+         EGL_RED_SIZE,       5,
+         EGL_GREEN_SIZE,     6,
+         EGL_BLUE_SIZE,      5,
+         EGL_NONE
+     };
+     
+     EGLint numConfigs = -1;
+     EGLint majorVersion;
+     EGLint minorVersion;
+     EGLConfig config;
+     EGLContext context;
+     EGLSurface surface;
+     EGLint w, h;
+     
+     EGLDisplay dpy;
+
+     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+     eglInitialize(dpy, &majorVersion, &minorVersion);
+     eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
+     surface = eglCreateWindowSurface(dpy, config,
+             android_createDisplaySurface(), NULL);
+     context = eglCreateContext(dpy, config, NULL, NULL);
+     eglMakeCurrent(dpy, surface, surface, context);   
+     eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+     GLint dim = w<h ? w : h;
+
+
+     GLint crop[4] = { 0, 4, 4, -4 };
+     glBindTexture(GL_TEXTURE_2D, 0);
+     glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+     glEnable(GL_TEXTURE_2D);
+     glColor4f(1,1,1,1);
+
+     // packing is always 4
+     uint8_t t8[]  = { 
+             0x00, 0x55, 0x00, 0x55, 
+             0xAA, 0xFF, 0xAA, 0xFF,
+             0x00, 0x55, 0x00, 0x55, 
+             0xAA, 0xFF, 0xAA, 0xFF  };
+
+     uint16_t t16[]  = { 
+             0x0000, 0x5555, 0x0000, 0x5555, 
+             0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF,
+             0x0000, 0x5555, 0x0000, 0x5555, 
+             0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF  };
+
+     uint16_t t5551[]  = { 
+             0x0000, 0xFFFF, 0x0000, 0xFFFF, 
+             0xFFFF, 0x0000, 0xFFFF, 0x0000,
+             0x0000, 0xFFFF, 0x0000, 0xFFFF, 
+             0xFFFF, 0x0000, 0xFFFF, 0x0000  };
+
+     uint32_t t32[]  = { 
+             0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 
+             0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF, 
+             0xFF00FFFF, 0xFF00FF00, 0x00FF00FF, 0xFFFFFF00, 
+             0xFF000000, 0xFFFF00FF, 0xFF00FFFF, 0xFFFFFFFF
+     };
+
+
+     glClear(GL_COLOR_BUFFER_BIT);
+     glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, t8);
+     glDrawTexiOES(0, 0, 0, dim/2, dim/2);
+
+     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16);
+     glDrawTexiOES(dim/2, 0, 0, dim/2, dim/2);
+
+     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t16);
+     glDrawTexiOES(0, dim/2, 0, dim/2, dim/2);
+
+     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
+     glDrawTexiOES(dim/2, dim/2, 0, dim/2, dim/2);
+
+     eglSwapBuffers(dpy, surface);
+     return 0;
+}
diff --git a/opengl/tests/tritex/Android.mk b/opengl/tests/tritex/Android.mk
new file mode 100644
index 0000000..5cd1f04
--- /dev/null
+++ b/opengl/tests/tritex/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	tritex.c
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+    libEGL \
+    libGLESv1_CM \
+    libui
+
+LOCAL_MODULE:= test-opengl-tritex
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/tritex/tritex.c b/opengl/tests/tritex/tritex.c
new file mode 100644
index 0000000..60a7feb
--- /dev/null
+++ b/opengl/tests/tritex/tritex.c
@@ -0,0 +1,273 @@
+// Calls glDrawElements() the number of times specified by
+// ITERATIONS. Should draw a checkerboard on the screen after
+// a few seconds.
+//
+// Ported from a Java version by Google.
+
+#include <EGL/egl.h>

+#include <GLES/gl.h>
+
+#include <stdio.h>

+#include <stdlib.h>
+#include <math.h>
+

+EGLDisplay eglDisplay;

+EGLSurface eglSurface;

+EGLContext eglContext;

+GLuint texture;

+

+#define FIXED_ONE 0x10000
+#define ITERATIONS 50

+

+int init_gl_surface(void);

+void free_gl_surface(void);

+void init_scene(void);

+void render(int quads);

+void create_texture(void);
+int readTimer(void);

+
+static void gluLookAt(float eyeX, float eyeY, float eyeZ,
+        float centerX, float centerY, float centerZ, float upX, float upY,
+        float upZ)
+{
+    // See the OpenGL GLUT documentation for gluLookAt for a description
+    // of the algorithm. We implement it in a straightforward way:
+
+    float fx = centerX - eyeX;
+    float fy = centerY - eyeY;
+    float fz = centerZ - eyeZ;
+
+    // Normalize f
+    float rlf = 1.0f / sqrtf(fx*fx + fy*fy + fz*fz);
+    fx *= rlf;
+    fy *= rlf;
+    fz *= rlf;
+
+    // Normalize up
+    float rlup = 1.0f / sqrtf(upX*upX + upY*upY + upZ*upZ);
+    upX *= rlup;
+    upY *= rlup;
+    upZ *= rlup;
+
+    // compute s = f x up (x means "cross product")
+
+    float sx = fy * upZ - fz * upY;
+    float sy = fz * upX - fx * upZ;
+    float sz = fx * upY - fy * upX;
+
+    // compute u = s x f
+    float ux = sy * fz - sz * fy;
+    float uy = sz * fx - sx * fz;
+    float uz = sx * fy - sy * fx;
+
+    float m[16] ;
+    m[0] = sx;
+    m[1] = ux;
+    m[2] = -fx;
+    m[3] = 0.0f;
+
+    m[4] = sy;
+    m[5] = uy;
+    m[6] = -fy;
+    m[7] = 0.0f;
+
+    m[8] = sz;
+    m[9] = uz;
+    m[10] = -fz;
+    m[11] = 0.0f;
+
+    m[12] = 0.0f;
+    m[13] = 0.0f;
+    m[14] = 0.0f;
+    m[15] = 1.0f;
+
+    glMultMatrixf(m);
+    glTranslatef(-eyeX, -eyeY, -eyeZ);
+}
+

+int main(int argc, char **argv)

+{

+    int q;
+    int start, end;

+
+    printf("Initializing EGL...\n");
+

+    if(!init_gl_surface())

+    {

+        printf("GL initialisation failed - exiting\n");

+        return 0;

+    }

+

+    init_scene();

+

+    create_texture();

+

+    printf("Start test...\n");
+
+    render(argc==2 ? atoi(argv[1]) : ITERATIONS);

+

+    free_gl_surface();

+

+    return 0;

+}

+

+int init_gl_surface(void)

+{

+    EGLint numConfigs = 1;

+    EGLConfig myConfig = {0};

+    EGLint attrib[] =

+    {

+            EGL_DEPTH_SIZE,     16,

+            EGL_NONE

+    };

+

+    if ( (eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY )

+    {

+        printf("eglGetDisplay failed\n");

+        return 0;

+    }

+

+    if ( eglInitialize(eglDisplay, NULL, NULL) != EGL_TRUE )

+    {

+        printf("eglInitialize failed\n");

+        return 0;

+    }

+

+    if ( eglChooseConfig(eglDisplay, attrib, &myConfig, 1, &numConfigs) != EGL_TRUE )

+    {

+        printf("eglChooseConfig failed\n");

+        return 0;

+    }

+

+    if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig,
+            android_createDisplaySurface(), 0)) == EGL_NO_SURFACE )

+    {

+        printf("eglCreateWindowSurface failed\n");

+        return 0;

+    }

+

+    if ( (eglContext = eglCreateContext(eglDisplay, myConfig, 0, 0)) == EGL_NO_CONTEXT )

+    {

+        printf("eglCreateContext failed\n");

+        return 0;

+    }

+

+    if ( eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext) != EGL_TRUE )

+    {

+        printf("eglMakeCurrent failed\n");

+        return 0;

+    }

+

+    return 1;

+}

+

+void free_gl_surface(void)

+{

+    if (eglDisplay != EGL_NO_DISPLAY)

+    {

+        eglMakeCurrent( EGL_NO_DISPLAY, EGL_NO_SURFACE,

+                EGL_NO_SURFACE, EGL_NO_CONTEXT );

+        eglDestroyContext( eglDisplay, eglContext );

+        eglDestroySurface( eglDisplay, eglSurface );

+        eglTerminate( eglDisplay );

+        eglDisplay = EGL_NO_DISPLAY;

+    }

+}

+

+void init_scene(void)

+{

+    glDisable(GL_DITHER);
+    glEnable(GL_CULL_FACE);
+
+    float ratio = 320.0f / 480.0f;
+    glViewport(0, 0, 320, 480);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glFrustumf(-ratio, ratio, -1, 1, 1, 10);
+
+    glMatrixMode(GL_MODELVIEW);

+    glLoadIdentity();
+    gluLookAt(
+            0, 0, 3,  // eye
+            0, 0, 0,  // center
+            0, 1, 0); // up
+

+    glEnable(GL_TEXTURE_2D);

+    glEnableClientState(GL_VERTEX_ARRAY);

+    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+}

+

+void create_texture(void)

+{

+    const unsigned int on = 0xff0000ff;
+    const unsigned int off = 0xffffffff;
+    const unsigned int pixels[] =
+    {
+            on, off, on, off, on, off, on, off,
+            off, on, off, on, off, on, off, on,
+            on, off, on, off, on, off, on, off,
+            off, on, off, on, off, on, off, on,
+            on, off, on, off, on, off, on, off,
+            off, on, off, on, off, on, off, on,
+            on, off, on, off, on, off, on, off,
+            off, on, off, on, off, on, off, on,
+    };

+    glGenTextures(1, &texture);

+    glBindTexture(GL_TEXTURE_2D, texture);

+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

+    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

+}

+

+void render(int quads)

+{

+    int i, j;

+

+    const GLfloat vertices[] = {

+            -1,  -1,  0,

+             1,  -1,  0,

+             1,   1,  0,

+            -1,   1,  0

+    };

+

+    const GLfixed texCoords[] = {

+            0,            0,

+            FIXED_ONE,    0,

+            FIXED_ONE,    FIXED_ONE,

+            0,            FIXED_ONE

+    };

+

+    const GLushort template[] = { 0, 1, 2,  0, 2, 3 };
+
+
+    GLushort* indices = (GLushort*)malloc(quads*sizeof(template));
+    for (i=0 ; i<quads ; i++)
+        memcpy(indices+(sizeof(template)/sizeof(indices[0]))*i, template, sizeof(template));
+

+    glVertexPointer(3, GL_FLOAT, 0, vertices);

+    glTexCoordPointer(2, GL_FIXED, 0, texCoords);
+
+    // make sure to do a couple eglSwapBuffers to make sure there are
+    // no problems with the very first ones (who knows)
+    glClearColor(0.4, 0.4, 0.4, 0.4);
+    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+    eglSwapBuffers(eglDisplay, eglSurface);
+    glClearColor(0.6, 0.6, 0.6, 0.6);
+    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+    eglSwapBuffers(eglDisplay, eglSurface);
+    glClearColor(1.0, 1.0, 1.0, 1.0);
+
+    for (j=0 ; j<10 ; j++) {
+        printf("loop %d / 10 (%d quads / loop)\n", j, quads);
+
+        int nelem = sizeof(template)/sizeof(template[0]);
+        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+        glDrawElements(GL_TRIANGLES, nelem*quads, GL_UNSIGNED_SHORT, indices);
+        eglSwapBuffers(eglDisplay, eglSurface);
+    }
+
+    free(indices);

+}

+
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
new file mode 100755
index 0000000..1c49861
--- /dev/null
+++ b/opengl/tools/glgen/gen
@@ -0,0 +1,99 @@
+#!/bin/sh
+rm -rf out generated
+
+mkdir out
+mkdir -p out/javax/microedition/khronos/opengles
+mkdir -p out/com/google/android/gles_jni
+mkdir -p out/android/graphics
+
+echo "package android.graphics;" > out/android/graphics/Canvas.java
+echo "public interface Canvas {}" >> out/android/graphics/Canvas.java
+
+GLFILE=out/javax/microedition/khronos/opengles/GL.java
+cp stubs/GLHeader.java-if $GLFILE
+
+GLGEN_FILES="CFunc.java CType.java CodeEmitter.java GenerateGL.java JFunc.java JType.java JniCodeEmitter.java ParameterChecker.java"
+
+pushd src > /dev/null
+javac ${GLGEN_FILES}
+popd > /dev/null
+java -classpath src GenerateGL -c glspec-1.0 glspec-1.0ext glspec-1.1 glspec-1.1ext glspec-1.1extpack glspec-checks
+
+pushd out > /dev/null
+mkdir classes
+javac -d classes com/google/android/gles_jni/GLImpl.java javax/microedition/khronos/opengles/GL10.java javax/microedition/khronos/opengles/GL10Ext.java javax/microedition/khronos/opengles/GL11.java javax/microedition/khronos/opengles/GL11Ext.java javax/microedition/khronos/opengles/GL11ExtensionPack.java
+popd > /dev/null
+
+rm -rf generated
+mkdir -p generated/C
+cp out/com_google_android_gles_jni_GLImpl.cpp generated/C
+cp -r out/com generated
+cp -r out/javax generated
+
+rm -rf out
+
+# com_google_android_gles_jni_GLImpl.cpp
+if cmp ../../../frameworks/base/core/jni/com_google_android_gles_jni_GLImpl.cpp generated/C/com_google_android_gles_jni_GLImpl.cpp ; then
+echo com_google_android_gles_jni_GLImpl.cpp unchanged
+else
+echo Please edit ../../../frameworks/base/core/jni/com_google_android_gles_jni_GLImpl.cpp
+echo Please cp generated/C/com_google_android_gles_jni_GLImpl.cpp ../../../frameworks/base/core/jni
+fi
+
+# GLImpl.java
+if cmp ../../java/com/google/android/gles_jni/GLImpl.java generated/com/google/android/gles_jni/GLImpl.java ; then
+echo GLImpl.java unchanged
+else
+echo Please edit ../../java/com/google/android/gles_jni/GLImpl.java
+echo Please cp generated/com/google/android/gles_jni/GLImpl.java ../../java/com/google/android/gles_jni
+fi
+
+# GL.java
+if cmp ../../java/javax/microedition/khronos/opengles/GL.java generated/javax/microedition/khronos/opengles/GL.java ; then
+echo GL.java unchanged
+else
+echo Please edit ../../java/javax/microedition/khronos/opengles/GL.java
+echo Please cp generated/javax/microedition/khronos/opengles/GL.java ../../java/javax/microedition/khronos/opengles/GL.java
+fi
+
+# GL10.java
+if cmp ../../java/javax/microedition/khronos/opengles/GL10.java generated/javax/microedition/khronos/opengles/GL10.java ; then
+echo GL10.java unchanged
+else
+echo Please edit ../../java/javax/microedition/khronos/opengles/GL10.java
+echo Please cp generated/javax/microedition/khronos/opengles/GL10.java ../../java/javax/microedition/khronos/opengles/GL10.java
+fi
+
+# GL10Ext.java
+if cmp ../../java/javax/microedition/khronos/opengles/GL10Ext.java generated/javax/microedition/khronos/opengles/GL10Ext.java ; then
+echo GL10Ext.java unchanged
+else
+echo Please edit ../../java/javax/microedition/khronos/opengles/GL10Ext.java
+echo Please cp generated/javax/microedition/khronos/opengles/GL10Ext.java ../../java/javax/microedition/khronos/opengles/GL10Ext.java
+fi
+
+# GL11.java
+if cmp ../../java/javax/microedition/khronos/opengles/GL11.java generated/javax/microedition/khronos/opengles/GL11.java ; then
+echo GL11.java unchanged
+else
+echo Please edit ../../java/javax/microedition/khronos/opengles/GL11.java
+echo Please cp generated/javax/microedition/khronos/opengles/GL11.java ../../java/javax/microedition/khronos/opengles/GL11.java
+fi
+
+# GL11Ext.java
+if cmp ../../java/javax/microedition/khronos/opengles/GL11Ext.java generated/javax/microedition/khronos/opengles/GL11Ext.java ; then
+echo GL11Ext.java unchanged
+else
+echo Please edit ../../java/javax/microedition/khronos/opengles/GL11Ext.java
+echo Please cp generated/javax/microedition/khronos/opengles/GL11Ext.java ../../java/javax/microedition/khronos/opengles/GL11Ext.java
+fi
+
+# GL11ExtensionPack.java
+if cmp ../../java/javax/microedition/khronos/opengles/GL11ExtensionPack.java generated/javax/microedition/khronos/opengles/GL11ExtensionPack.java ; then
+echo GL11ExtensionPack.java unchanged
+else
+echo Please edit ../../java/javax/microedition/khronos/opengles/GL11ExtensionPack.java
+echo Please cp generated/javax/microedition/khronos/opengles/GL11ExtensionPack.java ../../java/javax/microedition/khronos/opengles/GL11ExtensionPack.java
+fi
+
+rm -rf generated
diff --git a/opengl/tools/glgen/glspec-1.0 b/opengl/tools/glgen/glspec-1.0
new file mode 100644
index 0000000..c442320
--- /dev/null
+++ b/opengl/tools/glgen/glspec-1.0
@@ -0,0 +1,106 @@
+void glActiveTexture ( GLenum texture )

+void glAlphaFunc ( GLenum func, GLclampf ref )

+void glAlphaFuncx ( GLenum func, GLclampx ref )

+void glBindTexture ( GLenum target, GLuint texture )

+void glBlendFunc ( GLenum sfactor, GLenum dfactor )

+void glClear ( GLbitfield mask )

+void glClearColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )

+void glClearColorx ( GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha )

+void glClearDepthf ( GLclampf depth )

+void glClearDepthx ( GLclampx depth )

+void glClearStencil ( GLint s )

+void glClientActiveTexture ( GLenum texture )

+void glColor4f ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha )

+void glColor4x ( GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha )

+void glColorMask ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha )

+void glColorPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer )

+void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data )

+void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data )

+void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border )

+void glCopyTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height )

+void glCullFace ( GLenum mode )

+void glDeleteTextures ( GLsizei n, const GLuint *textures )

+void glDepthFunc ( GLenum func )

+void glDepthMask ( GLboolean flag )

+void glDepthRangef ( GLclampf zNear, GLclampf zFar )

+void glDepthRangex ( GLclampx zNear, GLclampx zFar )

+void glDisable ( GLenum cap )

+void glDisableClientState ( GLenum array )

+void glDrawArrays ( GLenum mode, GLint first, GLsizei count )

+void glDrawElements ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices )

+void glEnable ( GLenum cap )

+void glEnableClientState ( GLenum array )

+void glFinish ( void )

+void glFlush ( void )

+void glFogf ( GLenum pname, GLfloat param )

+void glFogfv ( GLenum pname, const GLfloat *params )

+void glFogx ( GLenum pname, GLfixed param )

+void glFogxv ( GLenum pname, const GLfixed *params )

+void glFrontFace ( GLenum mode )

+void glFrustumf ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar )

+void glFrustumx ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar )

+void glGenTextures ( GLsizei n, GLuint *textures )

+GLenum glGetError ( void )

+void glGetIntegerv ( GLenum pname, GLint *params )

+const GLubyte * glGetString ( GLenum name )

+void glHint ( GLenum target, GLenum mode )

+void glLightModelf ( GLenum pname, GLfloat param )

+void glLightModelfv ( GLenum pname, const GLfloat *params )

+void glLightModelx ( GLenum pname, GLfixed param )

+void glLightModelxv ( GLenum pname, const GLfixed *params )

+void glLightf ( GLenum light, GLenum pname, GLfloat param )

+void glLightfv ( GLenum light, GLenum pname, const GLfloat *params )

+void glLightx ( GLenum light, GLenum pname, GLfixed param )

+void glLightxv ( GLenum light, GLenum pname, const GLfixed *params )

+void glLineWidth ( GLfloat width )

+void glLineWidthx ( GLfixed width )

+void glLoadIdentity ( void )

+void glLoadMatrixf ( const GLfloat *m )

+void glLoadMatrixx ( const GLfixed *m )

+void glLogicOp ( GLenum opcode )

+void glMaterialf ( GLenum face, GLenum pname, GLfloat param )

+void glMaterialfv ( GLenum face, GLenum pname, const GLfloat *params )

+void glMaterialx ( GLenum face, GLenum pname, GLfixed param )

+void glMaterialxv ( GLenum face, GLenum pname, const GLfixed *params )

+void glMatrixMode ( GLenum mode )

+void glMultMatrixf ( const GLfloat *m )

+void glMultMatrixx ( const GLfixed *m )

+void glMultiTexCoord4f ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q )

+void glMultiTexCoord4x ( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q )

+void glNormal3f ( GLfloat nx, GLfloat ny, GLfloat nz )

+void glNormal3x ( GLfixed nx, GLfixed ny, GLfixed nz )

+void glNormalPointer ( GLenum type, GLsizei stride, const GLvoid *pointer )

+void glOrthof ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar )

+void glOrthox ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar )

+void glPixelStorei ( GLenum pname, GLint param )

+void glPointSize ( GLfloat size )

+void glPointSizex ( GLfixed size )

+void glPolygonOffset ( GLfloat factor, GLfloat units )

+void glPolygonOffsetx ( GLfixed factor, GLfixed units )

+void glPopMatrix ( void )

+void glPushMatrix ( void )

+void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels )

+void glRotatef ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )

+void glRotatex ( GLfixed angle, GLfixed x, GLfixed y, GLfixed z )

+void glSampleCoverage ( GLclampf value, GLboolean invert )

+void glSampleCoveragex ( GLclampx value, GLboolean invert )

+void glScalef ( GLfloat x, GLfloat y, GLfloat z )

+void glScalex ( GLfixed x, GLfixed y, GLfixed z )

+void glScissor ( GLint x, GLint y, GLsizei width, GLsizei height )

+void glShadeModel ( GLenum mode )

+void glStencilFunc ( GLenum func, GLint ref, GLuint mask )

+void glStencilMask ( GLuint mask )

+void glStencilOp ( GLenum fail, GLenum zfail, GLenum zpass )

+void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer )

+void glTexEnvf ( GLenum target, GLenum pname, GLfloat param )

+void glTexEnvfv ( GLenum target, GLenum pname, const GLfloat *params )

+void glTexEnvx ( GLenum target, GLenum pname, GLfixed param )

+void glTexEnvxv ( GLenum target, GLenum pname, const GLfixed *params )

+void glTexImage2D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels )

+void glTexParameterf ( GLenum target, GLenum pname, GLfloat param )

+void glTexParameterx ( GLenum target, GLenum pname, GLfixed param )

+void glTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels )

+void glTranslatef ( GLfloat x, GLfloat y, GLfloat z )

+void glTranslatex ( GLfixed x, GLfixed y, GLfixed z )

+void glVertexPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer )

+void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height )

diff --git a/opengl/tools/glgen/glspec-1.0ext b/opengl/tools/glgen/glspec-1.0ext
new file mode 100644
index 0000000..7d19758
--- /dev/null
+++ b/opengl/tools/glgen/glspec-1.0ext
@@ -0,0 +1 @@
+GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent )

diff --git a/opengl/tools/glgen/glspec-1.1 b/opengl/tools/glgen/glspec-1.1
new file mode 100644
index 0000000..9149a7f
--- /dev/null
+++ b/opengl/tools/glgen/glspec-1.1
@@ -0,0 +1,42 @@
+void glBindBuffer ( GLenum target, GLuint buffer )

+void glBufferData ( GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage )

+void glBufferSubData ( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data )

+void glClipPlanef ( GLenum plane, const GLfloat *equation )

+void glClipPlanex ( GLenum plane, const GLfixed *equation )

+void glColor4ub ( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha )

+void glColorPointer ( GLint size, GLenum type, GLsizei stride, GLint offset )

+void glDeleteBuffers ( GLsizei n, const GLuint *buffers )

+void glDrawElements ( GLenum mode, GLsizei count, GLenum type, GLint offset )

+void glGenBuffers ( GLsizei n, GLuint *buffers )

+void glGetBooleanv ( GLenum pname, GLboolean *params )

+void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params )

+void glGetClipPlanef ( GLenum pname, GLfloat *eqn )

+void glGetClipPlanex ( GLenum pname, GLfixed *eqn )

+void glGetFixedv ( GLenum pname, GLfixed *params )

+void glGetFloatv ( GLenum pname, GLfloat *params )

+void glGetLightfv ( GLenum light, GLenum pname, GLfloat *params )

+void glGetLightxv ( GLenum light, GLenum pname, GLfixed *params )

+void glGetMaterialfv ( GLenum face, GLenum pname, GLfloat *params )

+void glGetMaterialxv ( GLenum face, GLenum pname, GLfixed *params )

+void glGetTexEnviv ( GLenum env, GLenum pname, GLint *params )

+void glGetTexEnvxv ( GLenum env, GLenum pname, GLfixed *params )

+void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params )

+void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params )

+void glGetTexParameterxv ( GLenum target, GLenum pname, GLfixed *params )

+GLboolean glIsBuffer ( GLuint buffer )

+GLboolean glIsEnabled ( GLenum cap )

+GLboolean glIsTexture ( GLuint texture )

+void glNormalPointer ( GLenum type, GLsizei stride, GLint offset )

+void glPointParameterf ( GLenum pname, GLfloat param )

+void glPointParameterfv ( GLenum pname, const GLfloat *params )

+void glPointParameterx ( GLenum pname, GLfixed param )

+void glPointParameterxv ( GLenum pname, const GLfixed *params )

+void glPointSizePointerOES ( GLenum type, GLsizei stride, const GLvoid *pointer )

+void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, GLint offset )

+void glTexEnvi ( GLenum target, GLenum pname, GLint param )

+void glTexEnviv ( GLenum target, GLenum pname, const GLint *params )

+void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params )

+void glTexParameteri ( GLenum target, GLenum pname, GLint param )

+void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params )

+void glTexParameterxv ( GLenum target, GLenum pname, const GLfixed *params )

+void glVertexPointer ( GLint size, GLenum type, GLsizei stride, GLint offset )

diff --git a/opengl/tools/glgen/glspec-1.1ext b/opengl/tools/glgen/glspec-1.1ext
new file mode 100644
index 0000000..cc08c73
--- /dev/null
+++ b/opengl/tools/glgen/glspec-1.1ext
@@ -0,0 +1,16 @@
+void glCurrentPaletteMatrixOES ( GLuint matrixpaletteindex )

+void glDrawTexfOES ( GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height )

+void glDrawTexfvOES ( const GLfloat *coords )

+void glDrawTexiOES ( GLint x, GLint y, GLint z, GLint width, GLint height )

+void glDrawTexivOES ( const GLint *coords )

+void glDrawTexsOES ( GLshort x, GLshort y, GLshort z, GLshort width, GLshort height )

+void glDrawTexsvOES ( const GLshort *coords )

+void glDrawTexxOES ( GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height )

+void glDrawTexxvOES ( const GLfixed *coords )

+void glEnable ( GLenum cap )

+void glEnableClientState ( GLenum array )

+void glLoadPaletteFromModelViewMatrixOES ( void )

+void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer )

+void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, GLint offset )

+void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer )

+void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, GLint offset )

diff --git a/opengl/tools/glgen/glspec-1.1extpack b/opengl/tools/glgen/glspec-1.1extpack
new file mode 100644
index 0000000..ca9e6d2
--- /dev/null
+++ b/opengl/tools/glgen/glspec-1.1extpack
@@ -0,0 +1,38 @@
+void glBindFramebufferOES ( GLint target, GLint framebuffer )
+void glBindRenderbufferOES ( GLint target, GLint renderbuffer )
+void glBindTexture ( GLint target, GLint texture )
+void glBlendEquation ( GLint mode )
+void glBlendEquationSeparate ( GLint modeRGB, GLint modeAlpha )
+void glBlendFuncSeparate ( GLint srcRGB, GLint dstRGB, GLint srcAlpha, GLint dstAlpha )
+GLint glCheckFramebufferStatusOES ( GLint target )
+void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data )
+void glCopyTexImage2D ( GLint target, GLint level, GLint internalformat, GLint x, GLint y, GLint width, GLint height, GLint border )
+void glDeleteFramebuffersOES ( GLint n, GLint *framebuffers )
+void glDeleteRenderbuffersOES ( GLint n, GLint *renderbuffers )
+void glEnable ( GLint cap )
+void glFramebufferRenderbufferOES ( GLint target, GLint attachment, GLint renderbuffertarget, GLint renderbuffer )
+void glFramebufferTexture2DOES ( GLint target, GLint attachment, GLint textarget, GLint texture, GLint level )
+void glGenerateMipmapOES ( GLint target )
+void glGenFramebuffersOES ( GLint n, GLint *framebuffers )
+void glGenRenderbuffersOES ( GLint n, GLint *renderbuffers )
+void glGetFramebufferAttachmentParameterivOES ( GLint target, GLint attachment, GLint pname, GLint *params )
+void glGetIntegerv ( GLint pname, GLint *params )
+void glGetRenderbufferParameterivOES ( GLint target, GLint pname, GLint *params )
+void glGetTexGenfv ( GLint coord, GLint pname, GLfloat *params )
+void glGetTexGeniv ( GLint coord, GLint pname, GLint *params )
+void glGetTexGenxv ( GLint coord, GLint pname, GLint *params )
+GLboolean glIsFramebufferOES ( GLint framebuffer )
+GLboolean glIsRenderbufferOES ( GLint renderbuffer )
+void glRenderbufferStorageOES ( GLint target, GLint internalformat, GLint width, GLint height )
+void glStencilOp ( GLint fail, GLint zfail, GLint zpass )
+void glTexEnvf ( GLint target, GLint pname, GLfloat param )
+void glTexEnvfv ( GLint target, GLint pname, GLfloat *params )
+void glTexEnvx ( GLint target, GLint pname, GLint param )
+void glTexEnvxv ( GLint target, GLint pname, GLint *params )
+void glTexGenf ( GLint coord, GLint pname, GLfloat param )
+void glTexGenfv ( GLint coord, GLint pname, GLfloat *params )
+void glTexGeni ( GLint coord, GLint pname, GLint param )
+void glTexGeniv ( GLint coord, GLint pname, GLint *params )
+void glTexGenx ( GLint coord, GLint pname, GLint param )
+void glTexGenxv ( GLint coord, GLint pname, GLint *params )
+void glTexParameterf ( GLint target, GLint pname, GLfloat param )
diff --git a/opengl/tools/glgen/glspec-checks b/opengl/tools/glgen/glspec-checks
new file mode 100644
index 0000000..a84ed65
--- /dev/null
+++ b/opengl/tools/glgen/glspec-checks
@@ -0,0 +1,59 @@
+glClipPlanef check equation 4

+glClipPlanex check equation 4

+glDeleteBuffers check buffers n 

+glDeleteTextures check textures n

+glDrawElements check_AIOOBE indices count

+glFog ifcheck params 1 pname GL_FOG_MODE,GL_FOG_DENSITY,GL_FOG_START,GL_FOG_END ifcheck params 4 pname GL_FOG_COLOR

+glGenBuffers check buffers n

+glGenTextures check textures n

+glGetClipPlane check eqn 4

+glGetIntegerv ifcheck params 1 pname GL_ALPHA_BITS,GL_ALPHA_TEST_FUNC,GL_ALPHA_TEST_REF,GL_BLEND_DST,GL_BLUE_BITS,GL_COLOR_ARRAY_BUFFER_BINDING,GL_COLOR_ARRAY_SIZE,GL_COLOR_ARRAY_STRIDE,GL_COLOR_ARRAY_TYPE,GL_CULL_FACE,GL_DEPTH_BITS,GL_DEPTH_CLEAR_VALUE,GL_DEPTH_FUNC,GL_DEPTH_WRITEMASK,GL_FOG_DENSITY,GL_FOG_END,GL_FOG_MODE,GL_FOG_START,GL_FRONT_FACE,GL_GREEN_BITS,GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES,GL_IMPLEMENTATION_COLOR_READ_TYPE_OES,GL_LIGHT_MODEL_TWO_SIDE,GL_LINE_SMOOTH_HINT,GL_LINE_WIDTH,GL_LOGIC_OP_MODE,GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES,GL_MATRIX_INDEX_ARRAY_SIZE_OES,GL_MATRIX_INDEX_ARRAY_STRIDE_OES,GL_MATRIX_INDEX_ARRAY_TYPE_OES,GL_MATRIX_MODE,GL_MAX_CLIP_PLANES,GL_MAX_ELEMENTS_INDICES,GL_MAX_ELEMENTS_VERTICES,GL_MAX_LIGHTS,GL_MAX_MODELVIEW_STACK_DEPTH,GL_MAX_PALETTE_MATRICES_OES,GL_MAX_PROJECTION_STACK_DEPTH,GL_MAX_TEXTURE_SIZE,GL_MAX_TEXTURE_STACK_DEPTH,GL_MAX_TEXTURE_UNITS,GL_MAX_VERTEX_UNITS_OES,GL_MODELVIEW_STACK_DEPTH,GL_NORMAL_ARRAY_BUFFER_BINDING,GL_NORMAL_ARRAY_STRIDE,GL_NORMAL_ARRAY_TYPE,GL_NUM_COMPRESSED_TEXTURE_FORMATS,GL_PACK_ALIGNMENT,GL_PERSPECTIVE_CORRECTION_HINT,GL_POINT_SIZE,GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES,GL_POINT_SIZE_ARRAY_STRIDE_OES,GL_POINT_SIZE_ARRAY_TYPE_OES,GL_POINT_SMOOTH_HINT,GL_POLYGON_OFFSET_FACTOR,GL_POLYGON_OFFSET_UNITS,GL_PROJECTION_STACK_DEPTH,GL_RED_BITS,GL_SHADE_MODEL,GL_STENCIL_BITS,GL_STENCIL_CLEAR_VALUE,GL_STENCIL_FAIL,GL_STENCIL_FUNC,GL_STENCIL_PASS_DEPTH_FAIL,GL_STENCIL_PASS_DEPTH_PASS,GL_STENCIL_REF,GL_STENCIL_VALUE_MASK,GL_STENCIL_WRITEMASK,GL_SUBPIXEL_BITS,GL_TEXTURE_BINDING_2D,GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING,GL_TEXTURE_COORD_ARRAY_SIZE,GL_TEXTURE_COORD_ARRAY_STRIDE,GL_TEXTURE_COORD_ARRAY_TYPE,GL_TEXTURE_STACK_DEPTH,GL_UNPACK_ALIGNMENT,GL_VERTEX_ARRAY_BUFFER_BINDING,GL_VERTEX_ARRAY_SIZE,GL_VERTEX_ARRAY_STRIDE,GL_VERTEX_ARRAY_TYPE,GL_WEIGHT_ARRAY_BUFFER_BINDING_OES,GL_WEIGHT_ARRAY_SIZE_OES,GL_WEIGHT_ARRAY_STRIDE_OES,GL_WEIGHT_ARRAY_TYPE_OES ifcheck params 2 pname GL_ALIASED_POINT_SIZE_RANGE,GL_ALIASED_LINE_WIDTH_RANGE,GL_DEPTH_RANGE,GL_MAX_VIEWPORT_DIMS,GL_SMOOTH_LINE_WIDTH_RANGE,GL_SMOOTH_POINT_SIZE_RANGE ifcheck params 4 pname GL_COLOR_CLEAR_VALUE,GL_COLOR_WRITEMASK,GL_SCISSOR_BOX,GL_VIEWPORT ifcheck params 16 pname GL_MODELVIEW_MATRIX,GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES,GL_PROJECTION_MATRIX,GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES,GL_TEXTURE_MATRIX,GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES ifcheck params _NUM_COMPRESSED_TEXTURE_FORMATS pname GL_COMPRESSED_TEXTURE_FORMATS,GL_FOG_COLOR,GL_LIGHT_MODEL_AMBIENT

+glGetLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION

+glGetMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE

+glGetTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR

+glGetTexParameter check params 1

+glLightModel ifcheck params 1 pname GL_LIGHT_MODEL_TWO_SIDE ifcheck params 4 pname GL_LIGHT_MODEL_AMBIENT

+glLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION

+glLoadMatrix check m 16

+glMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE

+glMultMatrix check m 16

+glPointParameter check params 1

+glTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR

+glTexImage2D nullAllowed

+glTexSubImage2D nullAllowed

+glBufferData nullAllowed

+glTexParameter check params 1

+glQueryMatrixxOES check mantissa 16 check exponent 16 return -1

+glDrawTexfvOES check coords 5

+glDrawTexivOES check coords 5

+glDrawTexsvOES check coords 5

+glDrawTexxvOES check coords 5

+glBindFramebufferOES unsupported

+glBindRenderbufferOES unsupported

+glBlendEquation unsupported

+glBlendEquationSeparate unsupported

+glBlendFuncSeparate unsupported

+glCheckFramebufferStatusOES unsupported return 0

+glCurrentPaletteMatrixOES unsupported

+glDeleteFramebuffersOES unsupported

+glDeleteRenderbuffersOES unsupported

+glFramebufferRenderbufferOES unsupported

+glFramebufferStorageOES unsupported

+glFramebufferTexture2DOES unsupported

+glGenFramebuffersOES unsupported

+glGenRenderbuffersOES unsupported

+glGenerateMipmapOES unsupported

+glGetBufferParameter unsupported

+glGetFramebufferAttachmentParameterivOES unsupported

+glGetRenderbufferParameterivOES unsupported

+glGetTexGen unsupported

+glIsFramebufferOES unsupported return JNI_FALSE

+glIsRenderbufferOES unsupported return JNI_FALSE

+glLoadPaletteFromModelViewMatrixOES unsupported

+glMatrixIndexPointerOES unsupported

+glRenderbufferStorageOES unsupported return false

+glTexGen unsupported

+glTexGenf unsupported

+glTexGeni unsupported

+glTexGenx unsupported

+glWeightPointerOES unsupported

diff --git a/opengl/tools/glgen/src/CFunc.java b/opengl/tools/glgen/src/CFunc.java
new file mode 100644
index 0000000..0794f41
--- /dev/null
+++ b/opengl/tools/glgen/src/CFunc.java
@@ -0,0 +1,155 @@
+

+import java.util.*;

+

+public class CFunc {

+

+    String original;

+

+    CType ftype;

+    String fname;

+

+    List<String> argNames = new ArrayList<String>();

+    List<CType> argTypes = new ArrayList<CType>();

+

+    boolean hasPointerArg = false;

+    boolean hasTypedPointerArg = false;

+

+    public CFunc(String original) {

+        this.original = original;

+    }

+

+    public String getOriginal() {

+        return original;

+    }

+

+    public void setName(String fname) {

+        this.fname = fname;

+    }

+

+    public String getName() {

+        return fname;

+    }

+

+    public void setType(CType ftype) {

+        this.ftype = ftype;

+    }

+

+    public CType getType() {

+        return ftype;

+    }

+

+    public void addArgument(String argName, CType argType) {

+        argNames.add(argName);

+        argTypes.add(argType);

+

+        if (argType.isPointer()) {

+            hasPointerArg = true;

+        }

+        if (argType.isTypedPointer()) {

+            hasTypedPointerArg = true;

+        }

+    }

+

+    public int getNumArgs() {

+        return argNames.size();

+    }

+

+    public int getArgIndex(String name) {

+        int len = argNames.size();

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

+            if (name.equals(argNames.get(i))) {

+                return i;

+            }

+        }

+        return -1;

+    }

+

+    public String getArgName(int index) {

+        return argNames.get(index);

+    }

+

+    public CType getArgType(int index) {

+        return argTypes.get(index);

+    }

+

+    public boolean hasPointerArg() {

+        return hasPointerArg;

+    }

+

+    public boolean hasTypedPointerArg() {

+        return hasTypedPointerArg;

+    }

+

+    public String toString() {

+        String s =  "Function " + fname + " returns " + ftype + ": ";

+        for (int i = 0; i < argNames.size(); i++) {

+            if (i > 0) {

+                s += ", ";

+            }

+            s += argTypes.get(i) + " " + argNames.get(i);

+        }

+        return s;

+    }

+

+    public static CFunc parseCFunc(String s) {

+        CFunc cfunc = new CFunc(s);

+        String[] tokens = s.split("\\s");

+

+        int i = 0;

+        CType ftype = new CType();

+        String ftypeName = tokens[i++];

+        if (ftypeName.equals("const")) {

+            ftype.setIsConst(true);

+            ftypeName = tokens[i++];

+        }

+        ftype.setBaseType(ftypeName);

+

+        String fname = tokens[i++];

+        if (fname.equals("*")) {

+            ftype.setIsPointer(true);

+            fname = tokens[i++];

+        }

+	

+        cfunc.setName(fname);

+        cfunc.setType(ftype);

+	

+        while (i < tokens.length) {

+            String tok = tokens[i++];

+	    

+            if (tok.equals("(")) {

+                continue;

+            }

+            if (tok.equals(")")) {

+                break;

+            }

+

+            CType argType = new CType();

+	    

+            String argTypeName = tok;

+            String argName = "";

+	    

+            if (argTypeName.equals("const")) {

+                argType.setIsConst(true);

+                argTypeName = tokens[i++];

+            }

+            argType.setBaseType(argTypeName);

+

+            if (argTypeName.equals("void")) {

+                break;

+            }

+	    

+            argName = tokens[i++];

+            if (argName.startsWith("*")) {

+                argType.setIsPointer(true);

+                argName = argName.substring(1, argName.length());

+            }

+            if (argName.endsWith(",")) {

+                argName = argName.substring(0, argName.length() - 1);

+            }

+	    

+            cfunc.addArgument(argName, argType);

+        }

+

+        return cfunc;

+    }

+}

diff --git a/opengl/tools/glgen/src/CType.java b/opengl/tools/glgen/src/CType.java
new file mode 100644
index 0000000..331ec62
--- /dev/null
+++ b/opengl/tools/glgen/src/CType.java
@@ -0,0 +1,85 @@
+

+public class CType {

+

+    String baseType;

+    boolean isConst;

+    boolean isPointer;

+

+    public CType() {

+    }

+

+    public CType(String baseType) {

+	setBaseType(baseType);

+    }

+

+    public CType(String baseType, boolean isConst, boolean isPointer) {

+	setBaseType(baseType);

+	setIsConst(isConst);

+	setIsPointer(isPointer);

+    }

+

+    public String getDeclaration() {

+	return baseType + (isPointer ? " *" : "");

+    }

+    

+    public void setIsConst(boolean isConst) {

+	this.isConst = isConst;

+    }

+

+    public boolean isConst() {

+	return isConst;

+    }

+

+    public void setIsPointer(boolean isPointer) {

+	this.isPointer = isPointer;

+    }

+

+    public boolean isPointer() {

+	return isPointer;

+    }

+

+    boolean isVoid() {

+	String baseType = getBaseType();

+	return baseType.equals("GLvoid") ||

+	    baseType.equals("void");

+    }

+

+    public boolean isTypedPointer() {

+	return isPointer() && !isVoid();

+    }

+

+    public void setBaseType(String baseType) {

+	this.baseType = baseType;

+    }

+

+    public String getBaseType() {

+	return baseType;

+    }

+

+    public String toString() {

+	String s = "";

+	if (isConst()) {

+	    s += "const ";

+	}

+	s += baseType;

+	if (isPointer()) {

+	    s += "*";

+	}

+

+	return s;

+    }

+

+    public int hashCode() {

+	return baseType.hashCode() ^ (isPointer ? 2 : 0) ^ (isConst ? 1 : 0);

+    }

+

+    public boolean equals(Object o) {

+	if (o != null && o instanceof CType) {

+	    CType c = (CType)o;

+	    return baseType.equals(c.baseType) &&

+		isPointer() == c.isPointer() &&

+		isConst() == c.isConst();

+	}

+	return false;

+    }

+}

diff --git a/opengl/tools/glgen/src/CodeEmitter.java b/opengl/tools/glgen/src/CodeEmitter.java
new file mode 100644
index 0000000..3e9b90a
--- /dev/null
+++ b/opengl/tools/glgen/src/CodeEmitter.java
@@ -0,0 +1,8 @@
+

+public interface CodeEmitter {

+

+    void setVersion(int version, boolean ext, boolean pack);

+    void emitCode(CFunc cfunc, String original);

+    void addNativeRegistration(String fname);

+    void emitNativeRegistration();

+}

diff --git a/opengl/tools/glgen/src/GenerateGL.java b/opengl/tools/glgen/src/GenerateGL.java
new file mode 100644
index 0000000..657ee6e
--- /dev/null
+++ b/opengl/tools/glgen/src/GenerateGL.java
@@ -0,0 +1,164 @@
+

+import java.io.*;

+import java.util.*;

+

+public class GenerateGL {

+

+    static void copy(String filename, PrintStream out) throws IOException {

+        BufferedReader br = new BufferedReader(new FileReader(filename));

+        String s;

+        while ((s = br.readLine()) != null) {

+            out.println(s);

+        }

+    }

+

+    private static void emit(int version, boolean ext, boolean pack,

+                             CodeEmitter emitter,

+                             BufferedReader specReader,

+                             PrintStream glStream,

+                             PrintStream glImplStream,

+                             PrintStream cStream) throws Exception {

+        String s = null;

+        int counter = 0;

+        while ((s = specReader.readLine()) != null) {

+            if (s.trim().startsWith("//")) {

+                continue;

+            }

+

+            CFunc cfunc = CFunc.parseCFunc(s);

+

+            String fname = cfunc.getName();

+            File f = new File("stubs/" + fname +

+                              ".java-1" + version + "-if");

+            if (f.exists()) {

+                System.out.println("Special-casing function " + fname);

+                copy("stubs/" + fname +

+                     ".java-1" + version + "-if", glStream);

+                copy("stubs/" + fname + ".java-impl", glImplStream);

+                copy("stubs/" + fname + ".cpp", cStream);

+

+                // Register native function names

+                // This should be improved to require fewer discrete files

+                String filename = "stubs/" + fname + ".nativeReg";

+                BufferedReader br =

+                    new BufferedReader(new FileReader(filename));

+                String nfunc;

+                while ((nfunc = br.readLine()) != null) {

+                    emitter.addNativeRegistration(nfunc);

+                }

+            } else {

+                emitter.setVersion(version, ext, pack);

+                emitter.emitCode(cfunc, s);

+            }

+        }

+    }

+

+    public static void main(String[] args) throws Exception {

+        String classPathName = "com/google/android/gles_jni/GLImpl";

+        boolean useContextPointer = true;

+

+        int aidx = 0;

+        while (args[aidx].charAt(0) == '-') {

+            switch (args[aidx].charAt(1)) {

+            case 'c':

+                useContextPointer = false;

+                break;

+

+            default:

+                System.err.println("Unknown flag: " + args[aidx]);

+                System.exit(1);

+            }

+

+            aidx++;

+        }

+

+        System.out.println("useContextPointer = " + useContextPointer);

+

+        BufferedReader spec10Reader =

+            new BufferedReader(new FileReader(args[aidx++]));

+        BufferedReader spec10ExtReader =

+            new BufferedReader(new FileReader(args[aidx++]));

+        BufferedReader spec11Reader =

+            new BufferedReader(new FileReader(args[aidx++]));

+        BufferedReader spec11ExtReader =

+            new BufferedReader(new FileReader(args[aidx++]));

+        BufferedReader spec11ExtPackReader =

+            new BufferedReader(new FileReader(args[aidx++]));

+        BufferedReader checksReader =

+            new BufferedReader(new FileReader(args[aidx++]));

+

+        String gl10Filename = "javax/microedition/khronos/opengles/GL10.java";

+        String gl10ExtFilename =

+            "javax/microedition/khronos/opengles/GL10Ext.java";

+        String gl11Filename = "javax/microedition/khronos/opengles/GL11.java";

+        String gl11ExtFilename =

+            "javax/microedition/khronos/opengles/GL11Ext.java";

+        String gl11ExtPackFilename =

+            "javax/microedition/khronos/opengles/GL11ExtensionPack.java";

+        String glImplFilename = "com/google/android/gles_jni/GLImpl.java";

+        String cFilename = "com_google_android_gles_jni_GLImpl.cpp";

+

+        PrintStream gl10Stream =

+            new PrintStream(new FileOutputStream("out/" + gl10Filename));

+        PrintStream gl10ExtStream =

+            new PrintStream(new FileOutputStream("out/" + gl10ExtFilename));

+        PrintStream gl11Stream =

+            new PrintStream(new FileOutputStream("out/" + gl11Filename));

+        PrintStream gl11ExtStream =

+            new PrintStream(new FileOutputStream("out/" + gl11ExtFilename));

+        PrintStream gl11ExtPackStream =

+            new PrintStream(new FileOutputStream("out/" + gl11ExtPackFilename));

+        PrintStream glImplStream =

+            new PrintStream(new FileOutputStream("out/" + glImplFilename));

+        PrintStream cStream =

+            new PrintStream(new FileOutputStream("out/" + cFilename));

+

+        ParameterChecker checker = new ParameterChecker(checksReader);

+

+        CodeEmitter emitter =

+            new JniCodeEmitter(classPathName,

+                               checker,

+                               gl10Stream, gl10ExtStream,

+                               gl11Stream, gl11ExtStream, gl11ExtPackStream,

+                               glImplStream, cStream,

+                               useContextPointer);

+

+        gl10Stream.println("/* //device/java/android/" + gl10Filename);

+        gl10ExtStream.println("/* //device/java/android/" + gl10ExtFilename);

+        gl11Stream.println("/* //device/java/android/" + gl11Filename);

+        gl11ExtStream.println("/* //device/java/android/" + gl11ExtFilename);

+        gl11ExtPackStream.println("/* //device/java/android/" +

+            gl11ExtPackFilename);

+        glImplStream.println("/* //device/java/android/" + glImplFilename);

+        cStream.println("/* //device/libs/android_runtime/" + cFilename);

+

+        copy("stubs/GL10Header.java-if", gl10Stream);

+        copy("stubs/GL10ExtHeader.java-if", gl10ExtStream);

+        copy("stubs/GL11Header.java-if", gl11Stream);

+        copy("stubs/GL11ExtHeader.java-if", gl11ExtStream);

+        copy("stubs/GL11ExtensionPackHeader.java-if", gl11ExtPackStream);

+        copy("stubs/GLImplHeader.java-impl", glImplStream);

+        copy("stubs/GLCHeader.cpp", cStream);

+

+        emit(0, false, false,

+             emitter, spec10Reader, gl10Stream, glImplStream, cStream);

+        emit(0, true, false,

+             emitter, spec10ExtReader, gl10ExtStream, glImplStream, cStream);

+        emit(1, false, false,

+             emitter, spec11Reader, gl11Stream, glImplStream, cStream);

+        emit(1, true, false,

+             emitter, spec11ExtReader, gl11ExtStream, glImplStream, cStream);

+        emit(1, true, true,

+             emitter, spec11ExtPackReader, gl11ExtPackStream, glImplStream,

+             cStream);

+

+        emitter.emitNativeRegistration();

+

+        gl10Stream.println("}");

+        gl10ExtStream.println("}");

+        gl11Stream.println("}");

+        gl11ExtStream.println("}");

+        gl11ExtPackStream.println("}");

+        glImplStream.println("}");

+    }

+}

diff --git a/opengl/tools/glgen/src/JFunc.java b/opengl/tools/glgen/src/JFunc.java
new file mode 100644
index 0000000..42d466c
--- /dev/null
+++ b/opengl/tools/glgen/src/JFunc.java
@@ -0,0 +1,148 @@
+

+import java.util.ArrayList;

+import java.util.List;

+

+public class JFunc {

+

+    String className = "com.google.android.gles_jni.GL11Impl";

+

+    CFunc cfunc;

+    JType ftype;

+    String fname;

+

+    List<String> argNames = new ArrayList<String>();

+    List<JType> argTypes = new ArrayList<JType>();

+    List<Integer> argCIndices = new ArrayList<Integer>();

+

+    boolean hasBufferArg = false;

+    boolean hasTypedBufferArg = false;

+    ArrayList<String> bufferArgNames = new ArrayList<String>();

+

+    public JFunc(CFunc cfunc) {

+        this.cfunc = cfunc;

+    }

+

+    public CFunc getCFunc() {

+        return cfunc;

+    }

+

+    public void setName(String fname) {

+        this.fname = fname;

+    }

+

+    public String getName() {

+        return fname;

+    }

+

+    public void setType(JType ftype) {

+        this.ftype = ftype;

+    }

+

+    public JType getType() {

+        return ftype;

+    }

+

+    public void setClassName(String className) {

+        this.className = className;

+    }

+

+    public String getClassName() {

+        return className;

+    }

+    

+    public boolean hasBufferArg() {

+        return hasBufferArg;

+    }

+

+    public boolean hasTypedBufferArg() {

+        return hasTypedBufferArg;

+    }

+

+    public String getBufferArgName(int index) {

+        return bufferArgNames.get(index);

+    }

+

+    public void addArgument(String argName, JType argType, int cindex) {

+        argNames.add(argName);

+        argTypes.add(argType);

+        argCIndices.add(new Integer(cindex));

+

+        if (argType.isBuffer()) {

+            hasBufferArg = true;

+            bufferArgNames.add(argName);

+        }

+        if (argType.isTypedBuffer()) {

+            hasTypedBufferArg = true;

+            bufferArgNames.add(argName);

+        }

+    }

+

+    public int getNumArgs() {

+        return argNames.size();

+    }

+

+    public int getArgIndex(String name) {

+        int len = argNames.size();

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

+            if (name.equals(argNames.get(i))) {

+                return i;

+            }

+        }

+        return -1;

+    }

+

+    public String getArgName(int index) {

+        return argNames.get(index);

+    }

+

+    public JType getArgType(int index) {

+        return argTypes.get(index);

+    }

+

+    public int getArgCIndex(int index) {

+        return argCIndices.get(index).intValue();

+    }

+

+    public static JFunc convert(CFunc cfunc, boolean useArray) {

+        JFunc jfunc = new JFunc(cfunc);

+        jfunc.setName(cfunc.getName());

+        jfunc.setType(JType.convert(cfunc.getType(), false));

+	

+        int numArgs = cfunc.getNumArgs();

+        int numOffsets = 0;

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

+            CType cArgType = cfunc.getArgType(i);

+            if (cArgType.isTypedPointer() && useArray) {

+                ++numOffsets;

+            }

+        }

+

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

+            String cArgName = cfunc.getArgName(i);

+            CType cArgType = cfunc.getArgType(i);

+

+            jfunc.addArgument(cArgName, JType.convert(cArgType, useArray), i);

+            if (cArgType.isTypedPointer() && useArray) {

+                if (numOffsets > 1) {

+                    jfunc.addArgument(cArgName + "Offset", new JType("int"), i);

+                } else {

+                    jfunc.addArgument("offset", new JType("int"), i);

+                }

+            }

+        }

+

+        return jfunc;

+    }

+

+    public String toString() {

+        String s =  "Function " + fname + " returns " + ftype + ": ";

+        for (int i = 0; i < argNames.size(); i++) {

+            if (i > 0) {

+                s += ", ";

+            }

+            s += argTypes.get(i) + " " + argNames.get(i);

+        }

+        return s;

+    }

+

+}

diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java
new file mode 100644
index 0000000..a16d440
--- /dev/null
+++ b/opengl/tools/glgen/src/JType.java
@@ -0,0 +1,139 @@
+

+import java.util.HashMap;

+

+public class JType {

+    

+    String baseType;

+    boolean isArray;

+    boolean isClass;

+

+    static HashMap<CType,JType> typeMapping = new HashMap<CType,JType>();

+    static HashMap<CType,JType> arrayTypeMapping = new HashMap<CType,JType>();

+

+    static {

+	// Primitive types

+	typeMapping.put(new CType("GLbitfield"), new JType("int"));

+	typeMapping.put(new CType("GLboolean"), new JType("boolean"));

+	typeMapping.put(new CType("GLclampf"), new JType("float"));

+	typeMapping.put(new CType("GLclampx"), new JType("int"));

+	typeMapping.put(new CType("GLenum"), new JType("int"));

+	typeMapping.put(new CType("GLfloat"), new JType("float"));

+	typeMapping.put(new CType("GLfixed"), new JType("int"));

+	typeMapping.put(new CType("GLint"), new JType("int"));

+	typeMapping.put(new CType("GLintptr"), new JType("int"));

+	typeMapping.put(new CType("GLshort"), new JType("short"));

+	typeMapping.put(new CType("GLsizei"), new JType("int"));

+	typeMapping.put(new CType("GLsizeiptr"), new JType("int"));

+	typeMapping.put(new CType("GLubyte"), new JType("byte"));

+	typeMapping.put(new CType("GLuint"), new JType("int"));

+	typeMapping.put(new CType("void"), new JType("void"));

+	typeMapping.put(new CType("GLubyte", true, true), new JType("String"));

+

+	// Untyped pointers map to untyped Buffers

+	typeMapping.put(new CType("GLvoid", true, true),

+			new JType("java.nio.Buffer", true, false));

+	typeMapping.put(new CType("GLvoid", false, true),

+			new JType("java.nio.Buffer", true, false));

+	typeMapping.put(new CType("void", false, true),

+			new JType("java.nio.Buffer", true, false));

+

+	// Typed pointers map to typed Buffers

+	typeMapping.put(new CType("GLboolean", false, true),

+			new JType("java.nio.IntBuffer", true, false));

+	typeMapping.put(new CType("GLfixed", false, true),

+			new JType("java.nio.IntBuffer", true, false));

+	typeMapping.put(new CType("GLfixed", true, true),

+			new JType("java.nio.IntBuffer", true, false));

+	typeMapping.put(new CType("GLfloat", false, true),

+			new JType("java.nio.FloatBuffer", true, false));

+	typeMapping.put(new CType("GLfloat", true, true),

+			new JType("java.nio.FloatBuffer", true, false));

+	typeMapping.put(new CType("GLint", false, true),

+			new JType("java.nio.IntBuffer", true, false));

+	typeMapping.put(new CType("GLint", true, true),

+			new JType("java.nio.IntBuffer", true, false));

+	typeMapping.put(new CType("GLuint", false, true),

+			new JType("java.nio.IntBuffer", true, false));

+	typeMapping.put(new CType("GLuint", true, true),

+			new JType("java.nio.IntBuffer", true, false));

+	typeMapping.put(new CType("GLshort", true, true),

+			new JType("java.nio.ShortBuffer", true, false));

+

+	// Typed pointers map to arrays + offsets

+	arrayTypeMapping.put(new CType("GLboolean", false, true),

+			     new JType("boolean", false, true));

+	arrayTypeMapping.put(new CType("GLfixed", true, true), new JType("int", false, true));

+	arrayTypeMapping.put(new CType("GLfixed", false, true), new JType("int", false, true));

+	arrayTypeMapping.put(new CType("GLfloat", false, true), new JType("float", false, true));

+	arrayTypeMapping.put(new CType("GLfloat", true, true), new JType("float", false, true));

+	arrayTypeMapping.put(new CType("GLint", false, true), new JType("int", false, true));

+	arrayTypeMapping.put(new CType("GLint", true, true), new JType("int", false, true));

+	arrayTypeMapping.put(new CType("GLshort", true, true), new JType("short", false, true));

+	arrayTypeMapping.put(new CType("GLuint", false, true), new JType("int", false, true));

+	arrayTypeMapping.put(new CType("GLuint", true, true), new JType("int", false, true));

+	arrayTypeMapping.put(new CType("GLintptr"), new JType("int", false, true));

+	arrayTypeMapping.put(new CType("GLsizeiptr"), new JType("int", false, true));

+    }

+

+    public JType() {

+    }

+

+    public JType(String primitiveTypeName) {

+	this.baseType = primitiveTypeName;

+	this.isClass = false;

+	this.isArray = false;

+    }

+

+    public JType(String primitiveTypeName, boolean isClass, boolean isArray) {

+	this.baseType = primitiveTypeName;

+	this.isClass = isClass;

+	this.isArray = isArray;

+    }

+

+    public String getBaseType() {

+	return baseType;

+    }

+

+    public String toString() {

+	return baseType + (isArray ? "[]" : "");

+    }

+

+    public boolean isArray() {

+	return isArray;

+    }

+

+    public boolean isClass() {

+	return isClass;

+    }

+

+    public boolean isPrimitive() {

+	return !isClass() && !isArray();

+    }

+

+    public boolean isVoid() {

+	return baseType.equals("void");

+    }

+

+    public boolean isBuffer() {

+	return baseType.indexOf("Buffer") != -1;

+    }

+

+    public boolean isTypedBuffer() {

+	return !baseType.equals("java.nio.Buffer") &&

+	    (baseType.indexOf("Buffer") != -1);

+    }

+

+    public static JType convert(CType ctype, boolean useArray) {

+ 	JType javaType = null;

+ 	if (useArray) {

+ 	    javaType = arrayTypeMapping.get(ctype);

+ 	}

+ 	if (javaType == null) {

+ 	    javaType = typeMapping.get(ctype);

+ 	}

+ 	if (javaType == null) {

+ 	    throw new RuntimeException("Unsupported C type: " + ctype);

+ 	}

+ 	return javaType;

+    }

+}

diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
new file mode 100644
index 0000000..33b9a3e
--- /dev/null
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -0,0 +1,1086 @@
+import java.io.PrintStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Emits a Java interface and Java & C implementation for a C function.
+ *
+ * <p> The Java interface will have Buffer and array variants for functions that
+ * have a typed pointer argument.  The array variant will convert a single "<type> *data"
+ * argument to a pair of arguments "<type>[] data, int offset".
+ */
+public class JniCodeEmitter implements CodeEmitter {
+
+    // If true, use C++ style for calling through a JNIEnv *:
+    // env->Func(...)
+    // If false, use C style:
+    // (*env)->Func(env, ...)
+    static final boolean mUseCPlusPlus = true;
+
+    boolean mUseContextPointer = true;
+
+    String mClassPathName;
+    
+    ParameterChecker mChecker;
+    PrintStream mJava10InterfaceStream;
+    PrintStream mJava10ExtInterfaceStream;
+    PrintStream mJava11InterfaceStream;
+    PrintStream mJava11ExtInterfaceStream;
+    PrintStream mJava11ExtPackInterfaceStream;
+    PrintStream mJavaImplStream;
+    PrintStream mCStream;
+
+    PrintStream mJavaInterfaceStream;
+
+    List<String> nativeRegistrations = new ArrayList<String>();
+
+    boolean needsExit;
+
+    static String indent = "    ";
+
+    HashSet<String> mFunctionsEmitted = new HashSet<String>();
+
+    /**
+     * @param java10InterfaceStream the PrintStream to which to emit the Java interface for GL 1.0 functions
+     * @param java10ExtInterfaceStream the PrintStream to which to emit the Java interface for GL 1.0 extension functions
+     * @param java11InterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 functions 
+     * @param java11ExtInterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 Extension functions
+     * @param java11ExtPackInterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 Extension Pack functions
+     * @param javaImplStream the PrintStream to which to emit the Java implementation
+     * @param cStream the PrintStream to which to emit the C implementation
+     */
+    public JniCodeEmitter(String classPathName,
+                          ParameterChecker checker,
+                          PrintStream java10InterfaceStream,
+                          PrintStream java10ExtInterfaceStream,
+                          PrintStream java11InterfaceStream,
+                          PrintStream java11ExtInterfaceStream,
+                          PrintStream java11ExtPackInterfaceStream,
+                          PrintStream javaImplStream,
+                          PrintStream cStream,
+                          boolean useContextPointer) {
+        mClassPathName = classPathName;
+        mChecker = checker;
+        mJava10InterfaceStream = java10InterfaceStream;
+        mJava10ExtInterfaceStream = java10ExtInterfaceStream;
+        mJava11InterfaceStream = java11InterfaceStream;
+        mJava11ExtInterfaceStream = java11ExtInterfaceStream;
+        mJava11ExtPackInterfaceStream = java11ExtPackInterfaceStream;
+        mJavaImplStream = javaImplStream;
+        mCStream = cStream;
+        mUseContextPointer = useContextPointer;
+    }
+
+    public void setVersion(int version, boolean ext, boolean pack) {
+        if (version == 0) {
+            mJavaInterfaceStream = ext ? mJava10ExtInterfaceStream :
+                mJava10InterfaceStream;
+        } else if (version == 1) {
+            mJavaInterfaceStream = ext ?
+                (pack ? mJava11ExtPackInterfaceStream :
+                 mJava11ExtInterfaceStream) :
+                mJava11InterfaceStream;
+        } else {
+            throw new RuntimeException("Bad version: " + version);
+        }
+    }
+
+    public void emitCode(CFunc cfunc, String original) {
+        JFunc jfunc;
+        String signature;
+        boolean duplicate;
+        
+        if (cfunc.hasTypedPointerArg()) {
+            jfunc = JFunc.convert(cfunc, true);
+
+            // Don't emit duplicate functions
+            // These may appear because they are defined in multiple
+            // Java interfaces (e.g., GL11/GL11ExtensionPack)
+            signature = jfunc.toString();
+            duplicate = false;
+            if (mFunctionsEmitted.contains(signature)) {
+                duplicate = true;
+            } else {
+                mFunctionsEmitted.add(signature);
+            }
+
+            if (!duplicate) {
+                emitNativeDeclaration(jfunc, mJavaImplStream);
+                emitJavaCode(jfunc, mJavaImplStream);
+            }
+            emitJavaInterfaceCode(jfunc, mJavaInterfaceStream);
+            if (!duplicate) {
+                emitJniCode(jfunc, mCStream);
+            }
+        }
+
+        jfunc = JFunc.convert(cfunc, false);
+
+        signature = jfunc.toString();
+        duplicate = false;
+        if (mFunctionsEmitted.contains(signature)) {
+            duplicate = true;
+        } else {
+            mFunctionsEmitted.add(signature);
+        }
+
+        if (!duplicate) {
+            emitNativeDeclaration(jfunc, mJavaImplStream);
+        }
+        emitJavaInterfaceCode(jfunc, mJavaInterfaceStream);
+        if (!duplicate) {
+            emitJavaCode(jfunc, mJavaImplStream);
+            emitJniCode(jfunc, mCStream);
+        }
+    }
+
+    public void emitNativeDeclaration(JFunc jfunc, PrintStream out) {
+        out.println("    // C function " + jfunc.getCFunc().getOriginal());
+        out.println();
+
+        emitFunction(jfunc, out, true, false);
+    }
+
+    public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) {
+        emitFunction(jfunc, out, false, true);
+    }
+
+    public void emitJavaCode(JFunc jfunc, PrintStream out) {
+        emitFunction(jfunc, out, false, false);
+    }
+    
+    void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray ) {
+        boolean isVoid = jfunc.getType().isVoid();
+        boolean isPointerFunc = jfunc.getName().endsWith("Pointer") &&
+            jfunc.getCFunc().hasPointerArg();
+
+        if (!isVoid) {
+            out.println(iii +
+                        jfunc.getType() + " _returnValue;");
+        }
+        out.println(iii +
+                    (isVoid ? "" : "_returnValue = ") +
+                    jfunc.getName() +
+                    (isPointerFunc ? "Bounds" : "" ) +
+                    "(");
+	
+        int numArgs = jfunc.getNumArgs();
+        for (int i = 0; i < numArgs; i++) {
+            String argName = jfunc.getArgName(i);
+            JType argType = jfunc.getArgType(i);
+
+            if (grabArray && argType.isTypedBuffer()) {
+                String typeName = argType.getBaseType();
+                typeName = typeName.substring(9, typeName.length() - 6);
+                out.println(iii + indent + "get" + typeName + "Array(" + argName + "),");
+                out.print(iii + indent + "getOffset(" + argName + ")"); 
+            } else {
+                out.print(iii + indent + argName);
+            }
+            if (i == numArgs - 1) {
+                if (isPointerFunc) {
+                    out.println(",");
+                    out.println(iii + indent + argName + ".remaining()");
+                } else {
+                    out.println();
+                }
+            } else {
+                out.println(",");
+            }
+        }
+	
+        out.println(iii + ");");
+    }
+
+    void printIfcheckPostamble(PrintStream out, boolean isBuffer,
+                               boolean emitExceptionCheck, String iii) {
+        printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
+                              "offset", "_remaining", iii);
+    }
+
+    void printIfcheckPostamble(PrintStream out, boolean isBuffer,
+                               boolean emitExceptionCheck,
+                               String offset, String remaining, String iii) {
+        out.println(iii + "    default:");
+        out.println(iii + "        _needed = 0;");
+        out.println(iii + "        break;");
+        out.println(iii + "}");
+
+        out.println(iii + "if (" + remaining + " < _needed) {");
+        if (emitExceptionCheck) {
+            out.println(iii + indent + "_exception = 1;");
+        }
+        out.println(iii + indent +
+                    (mUseCPlusPlus ? "_env" : "(*_env)") +
+                    "->ThrowNew(" +
+                    (mUseCPlusPlus ? "" : "_env, ") +
+                    "IAEClass, " +
+                    "\"" +
+                    (isBuffer ? 
+                     "remaining()" : "length - " + offset) +
+                    " < needed\");");
+        out.println(iii + indent + "goto exit;");
+        needsExit = true;
+        out.println(iii + "}");
+    }
+
+    boolean isNullAllowed(CFunc cfunc) {
+        String[] checks = mChecker.getChecks(cfunc.getName());
+        int index = 1;
+        if (checks != null) {
+            while (index < checks.length) {
+                if (checks[index].equals("return")) {
+                    index += 2;
+                } else if (checks[index].startsWith("check")) {
+                    index += 3;
+                } else if (checks[index].equals("ifcheck")) {
+                    index += 5;
+                } else if (checks[index].equals("unsupported")) {
+                    index += 1;
+                } else if (checks[index].equals("nullAllowed")) {
+                    return true;
+                } else {
+                    System.out.println("Error: unknown keyword \"" +
+                                       checks[index] + "\"");
+                    System.exit(0);
+                }
+            }
+        }
+        return false;
+    }
+
+    String getErrorReturnValue(CFunc cfunc) {
+        CType returnType = cfunc.getType();
+        boolean isVoid = returnType.isVoid();
+        if (isVoid) {
+            return null;
+        }
+
+        String[] checks = mChecker.getChecks(cfunc.getName());
+
+        int index = 1;
+        if (checks != null) {
+            while (index < checks.length) {
+                if (checks[index].equals("return")) {
+                    return checks[index + 1];
+                } else if (checks[index].startsWith("check")) {
+                    index += 3;
+                } else if (checks[index].equals("ifcheck")) {
+                    index += 5;
+                } else if (checks[index].equals("unsupported")) {
+                    index += 1;
+                } else if (checks[index].equals("nullAllowed")) {
+                    index += 1;
+                } else {
+                    System.out.println("Error: unknown keyword \"" +
+                                       checks[index] + "\"");
+                    System.exit(0);
+                }
+            }
+        }
+
+        return null;
+    }
+
+    boolean isUnsupportedFunc(CFunc cfunc) {
+        String[] checks = mChecker.getChecks(cfunc.getName());
+        int index = 1;
+        if (checks != null) {
+            while (index < checks.length) {
+                if (checks[index].equals("unsupported")) {
+                    return true;
+                } else if (checks[index].equals("return")) {
+                    index += 2;
+                } else if (checks[index].startsWith("check")) {
+                    index += 3;
+                } else if (checks[index].equals("ifcheck")) {
+                    index += 5;
+                } else if (checks[index].equals("nullAllowed")) {
+                    index += 1;
+                } else {
+                    System.out.println("Error: unknown keyword \"" +
+                                       checks[index] + "\"");
+                    System.exit(0);
+                }
+            }
+        }
+        return false;
+    }
+
+    void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,
+                                boolean isBuffer, boolean emitExceptionCheck,
+                                String offset, String remaining, String iii) {
+        CType returnType = cfunc.getType();
+        boolean isVoid = returnType.isVoid();
+
+        String[] checks = mChecker.getChecks(cfunc.getName());
+        String checkVar;
+        String retval = getErrorReturnValue(cfunc);
+
+        boolean lastWasIfcheck = false;
+
+        int index = 1;
+        if (checks != null) {
+            boolean remainingDeclared = false;
+            boolean nullCheckDeclared = false;
+            boolean offsetChecked = false;
+            while (index < checks.length) {
+                if (checks[index].startsWith("check")) {
+                    if (lastWasIfcheck) {
+                        printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
+                                              offset, remaining, iii);
+                    }
+                    lastWasIfcheck = false;
+                    if (cname != null && !cname.equals(checks[index + 1])) {
+                        index += 3;
+                        continue;
+                    }
+                    out.println(iii + "if (" + remaining + " < " +
+                                checks[index + 2] +
+                                ") {");
+                    if (emitExceptionCheck) {
+                        out.println(iii + indent + "_exception = 1;");
+                    }
+		    String exceptionClassName = "IAEClass";
+		    // If the "check" keyword was of the form
+		    // "check_<class name>", use the class name in the
+		    // exception to be thrown
+		    int underscore = checks[index].indexOf('_');
+		    if (underscore >= 0) {
+			exceptionClassName = checks[index].substring(underscore + 1) + "Class";
+		    }
+                    out.println(iii + indent +
+                                (mUseCPlusPlus ? "_env" : "(*_env)") +
+                                "->ThrowNew(" +
+                                (mUseCPlusPlus ? "" : "_env, ") +
+				exceptionClassName + ", " +
+                                "\"" +
+                                (isBuffer ? 
+                                 "remaining()" : "length - " + offset) +
+                                " < " + checks[index + 2] +
+                                "\");");
+
+                    out.println(iii + indent + "goto exit;");
+                    needsExit = true;
+                    out.println(iii + "}");
+                
+                    index += 3;
+                } else if (checks[index].equals("ifcheck")) {
+                    String[] matches = checks[index + 4].split(",");
+
+                    if (!lastWasIfcheck) {
+                        out.println(iii + "int _needed;");
+                        out.println(iii +
+                                    "switch (" +
+                                    checks[index + 3] +
+                                    ") {");
+                    }
+                    
+                    for (int i = 0; i < matches.length; i++) {
+                        out.println("#if defined(" + matches[i] + ")");
+                        out.println(iii +
+                                    "    case " +
+                                    matches[i] +
+                                    ":");
+                        out.println("#endif // defined(" + matches[i] + ")");
+                    }
+                    out.println(iii +
+                                "        _needed = " +
+                                checks[index + 2] +
+                                ";");
+                    out.println(iii +
+                                "        break;");
+                
+                    lastWasIfcheck = true;
+                    index += 5;
+                } else if (checks[index].equals("return")) {
+                    // ignore
+                    index += 2;
+                } else if (checks[index].equals("unsupported")) {
+                    // ignore
+                    index += 1;
+                } else if (checks[index].equals("nullAllowed")) {
+                    // ignore
+                    index += 1;
+                } else {
+                    System.out.println("Error: unknown keyword \"" +
+                                       checks[index] + "\"");
+                    System.exit(0);
+                }
+            }
+        }
+
+        if (lastWasIfcheck) {
+            printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
+        }
+    }
+
+    boolean hasNonConstArg(JFunc jfunc, CFunc cfunc,
+        List<Integer> nonPrimitiveArgs) {
+        if (nonPrimitiveArgs.size() > 0) {
+            for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
+                int idx = nonPrimitiveArgs.get(i).intValue();
+                int cIndex = jfunc.getArgCIndex(idx);
+                if (jfunc.getArgType(idx).isArray()) {
+                    if (!cfunc.getArgType(cIndex).isConst()) {
+                        return true;
+                    }
+                } else if (jfunc.getArgType(idx).isBuffer()) {
+                    if (!cfunc.getArgType(cIndex).isConst()) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+    
+    /**
+     * Emit a function in several variants:
+     *
+     * if nativeDecl: public native <returntype> func(args);
+     *
+     * if !nativeDecl:
+     *   if interfaceDecl:  public <returntype> func(args);
+     *   if !interfaceDecl: public <returntype> func(args) { body }
+     */
+    void emitFunction(JFunc jfunc,
+                      PrintStream out,
+                      boolean nativeDecl, boolean interfaceDecl) {
+        boolean isPointerFunc =
+            jfunc.getName().endsWith("Pointer") &&
+            jfunc.getCFunc().hasPointerArg();
+
+        if (!nativeDecl && !interfaceDecl && !isPointerFunc) {
+            // If it's not a pointer function, we've already emitted it
+            // with nativeDecl == true
+            return;
+        }
+
+        if (isPointerFunc) {
+            out.println(indent +
+                        (nativeDecl ? "private native " :
+                         (interfaceDecl ? "" : "public ")) +
+                        jfunc.getType() + " " +
+                        jfunc.getName() +
+                        (nativeDecl ? "Bounds" : "") +
+                        "(");
+        } else {
+            out.println(indent +
+                        (nativeDecl ? "public native " :
+                         (interfaceDecl ? "" : "public ")) +
+                        jfunc.getType() + " " +
+                        jfunc.getName() +
+                        "(");
+        }
+	
+        int numArgs = jfunc.getNumArgs();
+        for (int i = 0; i < numArgs; i++) {
+            String argName = jfunc.getArgName(i);
+            JType argType = jfunc.getArgType(i);
+	    
+            out.print(indent + indent + argType + " " + argName);
+            if (i == numArgs - 1) {
+                if (isPointerFunc && nativeDecl) {
+                    out.println(",");
+                    out.println(indent + indent + "int remaining");
+                } else {
+                    out.println();
+                }
+            } else {
+                out.println(",");
+            }
+        }
+
+        if (nativeDecl || interfaceDecl) {
+            out.println(indent + ");");
+        } else {
+            out.println(indent + ") {");
+
+            String iii = indent + indent;
+
+            String fname = jfunc.getName();
+            if (isPointerFunc) {
+                // TODO - deal with VBO variants
+                if (fname.equals("glColorPointer")) {
+                    out.println(iii + "if ((size == 4) &&");
+                    out.println(iii + "    ((type == GL_FLOAT) ||");
+                    out.println(iii + "     (type == GL_UNSIGNED_BYTE) ||");
+                    out.println(iii + "     (type == GL_FIXED)) &&");
+                    out.println(iii + "    (stride >= 0)) {");
+                    out.println(iii + indent + "_colorPointer = pointer;");
+                    out.println(iii + "}");
+                } else if (fname.equals("glNormalPointer")) {
+                    out.println(iii + "if (((type == GL_FLOAT) ||");
+                    out.println(iii + "     (type == GL_BYTE) ||");
+                    out.println(iii + "     (type == GL_SHORT) ||");
+                    out.println(iii + "     (type == GL_FIXED)) &&");
+                    out.println(iii + "    (stride >= 0)) {");
+                    out.println(iii + indent + "_normalPointer = pointer;");
+                    out.println(iii + "}");
+                } else if (fname.equals("glTexCoordPointer")) {
+                    out.println(iii + "if (((size == 2) ||");
+                    out.println(iii + "     (size == 3) ||");
+                    out.println(iii + "     (size == 4)) &&");
+                    out.println(iii + "    ((type == GL_FLOAT) ||");
+                    out.println(iii + "     (type == GL_BYTE) ||");
+                    out.println(iii + "     (type == GL_SHORT) ||");
+                    out.println(iii + "     (type == GL_FIXED)) &&");
+                    out.println(iii + "    (stride >= 0)) {");
+                    out.println(iii + indent + "_texCoordPointer = pointer;");
+                    out.println(iii + "}");
+                } else if (fname.equals("glVertexPointer")) {
+                    out.println(iii + "if (((size == 2) ||");
+                    out.println(iii + "     (size == 3) ||");
+                    out.println(iii + "     (size == 4)) &&");
+                    out.println(iii + "    ((type == GL_FLOAT) ||");
+                    out.println(iii + "     (type == GL_BYTE) ||");
+                    out.println(iii + "     (type == GL_SHORT) ||");
+                    out.println(iii + "     (type == GL_FIXED)) &&");
+                    out.println(iii + "    (stride >= 0)) {");
+                    out.println(iii + indent + "_vertexPointer = pointer;");
+                    out.println(iii + "}");
+                }
+            }
+
+            // emitBoundsChecks(jfunc, out, iii);
+            emitFunctionCall(jfunc, out, iii, false);
+
+            boolean isVoid = jfunc.getType().isVoid();
+
+            if (!isVoid) {
+                out.println(indent + indent + "return _returnValue;");
+            }
+            out.println(indent + "}");
+        }
+        out.println();
+    }
+
+    public static String getJniName(JType jType) {
+        String jniName = "";
+        if (jType.isClass()) {
+            return "L" + jType.getBaseType() + ";";
+        } else if (jType.isArray()) {
+            jniName = "[";
+        }
+	
+        String baseType = jType.getBaseType();
+        if (baseType.equals("int")) {
+            jniName += "I";
+        } else if (baseType.equals("float")) {
+            jniName += "F";
+        } else if (baseType.equals("boolean")) {
+            jniName += "Z";
+        } else if (baseType.equals("short")) {
+            jniName += "S";
+        } else if (baseType.equals("long")) {
+            jniName += "L";
+        } else if (baseType.equals("byte")) {
+            jniName += "B";
+        }
+        return jniName;
+    }
+
+    String getJniType(JType jType) {
+        if (jType.isVoid()) {
+            return "void";
+        }
+
+        String baseType = jType.getBaseType();
+        if (jType.isPrimitive()) {
+            if (baseType.equals("String")) {
+                return "jstring";
+            } else {
+                return "j" + baseType;
+            }
+        } else if (jType.isArray()) {
+            return "j" + baseType + "Array";
+        } else {
+            return "jobject";
+        }
+    }
+    
+    String getJniMangledName(String name) {
+        name = name.replaceAll("_", "_1");
+        name = name.replaceAll(";", "_2");
+        name = name.replaceAll("\\[", "_3");
+        return name;
+    }
+
+    public void emitJniCode(JFunc jfunc, PrintStream out) {
+        CFunc cfunc = jfunc.getCFunc();
+	
+        // Emit comment identifying original C function
+        //
+        // Example:
+        //
+        // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */
+        //
+        out.println("/* " + cfunc.getOriginal() + " */");
+
+        // Emit JNI signature (name)
+        //
+        // Example:
+        //
+        // void
+        // android_glClipPlanef__I_3FI
+        //
+
+        String outName = "android_" + jfunc.getName();
+        boolean isPointerFunc = outName.endsWith("Pointer") &&
+            jfunc.getCFunc().hasPointerArg();
+        boolean isVBOPointerFunc = (outName.endsWith("Pointer") ||
+            outName.endsWith("DrawElements")) &&
+            !jfunc.getCFunc().hasPointerArg();
+        if (isPointerFunc) {
+            outName += "Bounds";
+        }
+
+        out.print("static ");
+        out.println(getJniType(jfunc.getType()));
+        out.print(outName);
+
+        String rsignature = getJniName(jfunc.getType());
+
+        String signature = "";
+        int numArgs = jfunc.getNumArgs();
+        for (int i = 0; i < numArgs; i++) {
+            JType argType = jfunc.getArgType(i);
+            signature += getJniName(argType);
+        }
+        if (isPointerFunc) {
+            signature += "I";
+        }
+
+        // Append signature to function name
+        String sig = getJniMangledName(signature).replace('.', '_');        
+        out.print("__" + sig);
+        outName += "__" + sig;
+	
+        signature = signature.replace('.', '/');
+        rsignature = rsignature.replace('.', '/');
+	
+        out.println();
+        if (rsignature.length() == 0) {
+            rsignature = "V";
+        }
+
+        String s = "{\"" +
+            jfunc.getName() +
+            (isPointerFunc ? "Bounds" : "") +
+            "\", \"(" + signature +")" +
+            rsignature +
+            "\", (void *) " +
+            outName +
+            " },";
+        nativeRegistrations.add(s);
+
+        List<Integer> nonPrimitiveArgs = new ArrayList<Integer>();
+        int numBufferArgs = 0;
+        List<String> bufferArgNames = new ArrayList<String>();
+
+        // Emit JNI signature (arguments)
+        //
+        // Example:
+        //
+        // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) {
+        //
+        out.print("  (JNIEnv *_env, jobject _this");
+        for (int i = 0; i < numArgs; i++) {
+            out.print(", ");
+            JType argType = jfunc.getArgType(i);
+            String suffix;
+            if (!argType.isPrimitive()) {
+                if (argType.isArray()) {
+                    suffix = "_ref";
+                } else {
+                    suffix = "_buf";
+                }
+                nonPrimitiveArgs.add(new Integer(i));
+                if (jfunc.getArgType(i).isBuffer()) {
+                    int cIndex = jfunc.getArgCIndex(i);
+                    String cname = cfunc.getArgName(cIndex);
+                    bufferArgNames.add(cname);
+                    numBufferArgs++;
+                }
+            } else {
+                suffix = "";
+            }
+
+            out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
+        }
+        if (isPointerFunc) {
+            out.print(", jint remaining");
+        }
+        out.println(") {");
+	
+        int numArrays = 0;
+        int numBuffers = 0;
+        for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
+            int idx = nonPrimitiveArgs.get(i).intValue();
+            int cIndex = jfunc.getArgCIndex(idx);
+            String cname = cfunc.getArgName(cIndex);
+            if (jfunc.getArgType(idx).isArray()) {
+                ++numArrays;
+            }
+            if (jfunc.getArgType(idx).isBuffer()) {
+                ++numBuffers;
+            }
+        }
+
+        // Emit method body
+
+        // Emit local variable declarations for _exception and _returnValue
+        //
+        // Example:
+        //
+        // android::gl::ogles_context_t *ctx;
+        // 
+        // jint _exception;
+        // GLenum _returnValue;
+        //
+        CType returnType = cfunc.getType();
+        boolean isVoid = returnType.isVoid();
+
+        boolean isUnsupported = isUnsupportedFunc(cfunc);
+        if (isUnsupported) {
+            out.println(indent +
+                        "_env->ThrowNew(UOEClass,");
+            out.println(indent +
+                        "    \"" + cfunc.getName() + "\");");
+            if (!isVoid) {
+                String retval = getErrorReturnValue(cfunc);
+                out.println(indent + "return " + retval + ";");
+            }
+            out.println("}");
+            out.println();
+            return;
+        }
+
+        if (mUseContextPointer) {
+            out.println(indent +
+                "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
+        }
+
+        boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) &&
+            hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs);
+        // mChecker.getChecks(cfunc.getName()) != null
+
+        // Emit an _exeption variable if there will be error checks
+        if (emitExceptionCheck) {
+            out.println(indent + "jint _exception = 0;");
+        }
+
+        // Emit a single _array or multiple _XXXArray variables
+        if (numBufferArgs == 1) {
+                out.println(indent + "jarray _array = (jarray) 0;");
+        } else {
+            for (int i = 0; i < numBufferArgs; i++) {
+                out.println(indent + "jarray _" + bufferArgNames.get(i) +
+                            "Array = (jarray) 0;");
+            }
+        }
+        if (!isVoid) {
+            String retval = getErrorReturnValue(cfunc);
+            if (retval != null) {
+                out.println(indent + returnType.getDeclaration() +
+                            " _returnValue = " + retval + ";");
+            } else {
+                out.println(indent + returnType.getDeclaration() +
+                            " _returnValue;");
+            }
+        }
+
+        // Emit local variable declarations for pointer arguments
+        //
+        // Example:
+        //
+        // GLfixed *eqn_base;
+        // GLfixed *eqn;
+        //
+        String offset = "offset";
+        String remaining = "_remaining";
+        if (nonPrimitiveArgs.size() > 0) {
+            for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
+                int idx = nonPrimitiveArgs.get(i).intValue();
+                int cIndex = jfunc.getArgCIndex(idx);
+                String cname = cfunc.getArgName(cIndex);
+
+                CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
+                String decl = type.getDeclaration();
+                if (jfunc.getArgType(idx).isArray()) {
+                    out.println(indent +
+                                decl +
+                                (decl.endsWith("*") ? "" : " ") +
+                                jfunc.getArgName(idx) +
+                                "_base = (" + decl + ") 0;");
+                }
+                remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
+                    "_" + cname + "Remaining";
+                out.println(indent +
+                            "jint " + remaining + ";");
+                out.println(indent +
+                            decl +
+                            (decl.endsWith("*") ? "" : " ") +
+                            jfunc.getArgName(idx) + 
+                            " = (" + decl + ") 0;");
+            }
+
+            out.println();
+        }
+
+        String retval = isVoid ? "" : " _returnValue";
+
+        // Emit 'GetPrimitiveArrayCritical' for arrays
+        // Emit 'GetPointer' calls for Buffer pointers
+        int bufArgIdx = 0;
+        if (nonPrimitiveArgs.size() > 0) {
+            for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
+                int idx = nonPrimitiveArgs.get(i).intValue();
+                int cIndex = jfunc.getArgCIndex(idx);
+		
+                String cname = cfunc.getArgName(cIndex);
+                offset = numArrays <= 1 ? "offset" :
+                    cname + "Offset";
+                remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
+                    "_" + cname + "Remaining";
+
+                if (jfunc.getArgType(idx).isArray()) {
+                    out.println(indent +
+                                "if (!" + 
+                                cname +
+                                "_ref) {");
+                    if (emitExceptionCheck) {
+                        out.println(indent + indent + "_exception = 1;");
+                    }
+                    out.println(indent + "    " +
+                                (mUseCPlusPlus ? "_env" : "(*_env)") +
+                                "->ThrowNew(" +
+                                (mUseCPlusPlus ? "" : "_env, ") +
+                                "IAEClass, " +
+                                "\"" + cname +
+                                " == null\");");
+                    out.println(indent + "    goto exit;");
+                    needsExit = true;
+                    out.println(indent + "}");
+
+                    out.println(indent + "if (" + offset + " < 0) {");
+                    if (emitExceptionCheck) {
+                        out.println(indent + indent + "_exception = 1;");
+                    }
+                    out.println(indent + "    " +
+                                (mUseCPlusPlus ? "_env" : "(*_env)") +
+                                "->ThrowNew(" +
+                                (mUseCPlusPlus ? "" : "_env, ") +
+                                "IAEClass, " +
+                                "\"" + offset + " < 0\");");
+                    out.println(indent + "    goto exit;");
+                    needsExit = true;
+                    out.println(indent + "}");
+
+                    out.println(indent + remaining + " = " +
+                                    (mUseCPlusPlus ? "_env" : "(*_env)") + 
+                                    "->GetArrayLength(" +
+                                    (mUseCPlusPlus ? "" : "_env, ") +
+                                    cname + "_ref) - " + offset + ";");
+
+                    emitNativeBoundsChecks(cfunc, cname, out, false,
+                                           emitExceptionCheck,
+                                           offset, remaining, "    ");
+
+                    out.println(indent +
+                                cname +
+                                "_base = (" +
+                                cfunc.getArgType(cIndex).getDeclaration() +
+                                ")");
+                    out.println(indent + "    " +
+                                (mUseCPlusPlus ? "_env" : "(*_env)") +
+                                "->GetPrimitiveArrayCritical(" +
+                                (mUseCPlusPlus ? "" : "_env, ") + 
+                                jfunc.getArgName(idx) +
+                                "_ref, (jboolean *)0);");
+                    out.println(indent +
+                                cname + " = " + cname + "_base + " + offset +
+                                ";");
+                    out.println();
+                } else {
+                    String array = numBufferArgs <= 1 ? "_array" :
+                        "_" + bufferArgNames.get(bufArgIdx++) + "Array";
+
+                    boolean nullAllowed = isNullAllowed(cfunc);
+                    if (nullAllowed) {
+                        out.println(indent + "if (" + cname + "_buf) {");
+                        out.print(indent);
+                    }
+                    
+                    out.println(indent +
+                                cname +
+                                " = (" +
+                                cfunc.getArgType(cIndex).getDeclaration() +
+                                ")getPointer(_env, " +
+                                cname +
+                                "_buf, &" + array + ", &" + remaining + ");");
+
+                    if (nullAllowed) {
+                        out.println(indent + "}");
+                    }
+
+                    emitNativeBoundsChecks(cfunc, cname, out, true,
+                                           emitExceptionCheck,
+                                           offset, remaining, "    ");
+                }
+            }
+        }
+
+        if (!isVoid) {
+            out.print(indent + "_returnValue = ");
+        } else {
+            out.print(indent);
+        }
+        String name = cfunc.getName();
+
+        if (mUseContextPointer) {
+            name = name.substring(2, name.length()); // Strip off 'gl' prefix
+            name = name.substring(0, 1).toLowerCase() +
+                name.substring(1, name.length());
+            out.print("ctx->procs.");
+        }
+        
+        out.print(name + (isPointerFunc ? "Bounds" : "") + "(");
+
+        numArgs = cfunc.getNumArgs();    
+        if (numArgs == 0) {
+            if (mUseContextPointer) {
+                out.println("ctx);");
+            } else {
+                out.println(");");
+            }
+        } else {
+            if (mUseContextPointer) {
+                out.println("ctx,");
+            } else {
+                out.println();
+            }
+            for (int i = 0; i < numArgs; i++) {
+                String typecast;
+                if (i == numArgs - 1 && isVBOPointerFunc) {
+                    typecast = "const GLvoid *";
+                } else {
+                    typecast = cfunc.getArgType(i).getDeclaration();
+                }
+                out.print(indent + indent +
+                          "(" +
+                          typecast +
+                          ")" +
+                          cfunc.getArgName(i));
+
+                if (i == numArgs - 1) {
+                    if (isPointerFunc) {
+                        out.println(",");
+                        out.println(indent + indent + "(GLsizei)remaining");
+                    } else {
+                        out.println();
+                    }
+                } else {
+                    out.println(",");
+                }
+            }
+            out.println(indent + ");");
+        }
+
+        if (needsExit) {
+            out.println();
+            out.println("exit:");
+            needsExit = false;
+        }
+
+        bufArgIdx = 0;
+        if (nonPrimitiveArgs.size() > 0) {
+            for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
+                int idx = nonPrimitiveArgs.get(i).intValue();
+
+                int cIndex = jfunc.getArgCIndex(idx);
+                if (jfunc.getArgType(idx).isArray()) {
+		    
+                    // If the argument is 'const', GL will not write to it.
+                    // In this case, we can use the 'JNI_ABORT' flag to avoid
+                    // the need to write back to the Java array
+                    out.println(indent +
+                                "if (" + jfunc.getArgName(idx) + "_base) {");
+                    out.println(indent + indent +
+                                (mUseCPlusPlus ? "_env" : "(*_env)") +
+                                "->ReleasePrimitiveArrayCritical(" +
+                                (mUseCPlusPlus ? "" : "_env, ") + 
+                                jfunc.getArgName(idx) + "_ref, " +
+                                cfunc.getArgName(cIndex) +
+                                "_base,");
+                    out.println(indent + indent + indent +
+                                (cfunc.getArgType(cIndex).isConst() ?
+                                 "JNI_ABORT" :
+                                 "_exception ? JNI_ABORT: 0") +
+                                ");");
+                    out.println(indent + "}");
+                } else if (jfunc.getArgType(idx).isBuffer()) {
+                    String array = numBufferArgs <= 1 ? "_array" :
+                        "_" + bufferArgNames.get(bufArgIdx++) + "Array";
+                    out.println(indent + "if (" + array + ") {");
+                    out.println(indent + indent +
+                                "releasePointer(_env, " + array + ", " +
+                                cfunc.getArgName(cIndex) +
+                                ", " +
+                                (cfunc.getArgType(cIndex).isConst() ?
+                                 "JNI_FALSE" : "_exception ? JNI_FALSE : JNI_TRUE") +
+                                ");");
+                    out.println(indent + "}");
+                }
+            }
+        }
+
+        if (!isVoid) {
+            out.println(indent + "return _returnValue;");
+        }
+
+        out.println("}");
+        out.println();
+    }
+
+    public void addNativeRegistration(String s) {
+        nativeRegistrations.add(s);
+    }
+
+    public void emitNativeRegistration() {
+        mCStream.println("static const char *classPathName = \"" +
+                        mClassPathName +
+                        "\";");
+        mCStream.println();
+
+        mCStream.println("static JNINativeMethod methods[] = {");
+
+        mCStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },");
+
+        Iterator<String> i = nativeRegistrations.iterator();
+        while (i.hasNext()) {
+            mCStream.println(i.next());
+        }
+
+        mCStream.println("};");
+        mCStream.println();
+    
+
+        mCStream.println("int register_com_google_android_gles_jni_GLImpl(JNIEnv *_env)");
+        mCStream.println("{");
+        mCStream.println(indent +
+                        "int err;");
+
+        mCStream.println(indent +
+                        "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));");
+
+        mCStream.println(indent + "return err;");
+        mCStream.println("}");
+    }
+}
diff --git a/opengl/tools/glgen/src/ParameterChecker.java b/opengl/tools/glgen/src/ParameterChecker.java
new file mode 100644
index 0000000..df26acd
--- /dev/null
+++ b/opengl/tools/glgen/src/ParameterChecker.java
@@ -0,0 +1,28 @@
+
+import java.io.BufferedReader;
+import java.util.HashMap;
+
+public class ParameterChecker {
+
+    HashMap<String,String[]> map = new HashMap<String,String[]>();
+
+    public ParameterChecker(BufferedReader reader) throws Exception {
+        String s;
+        while ((s = reader.readLine()) != null) {
+            String[] tokens = s.split("\\s");
+            map.put(tokens[0], tokens);
+        }
+    }
+
+    public String[] getChecks(String functionName) {
+        String[] checks = map.get(functionName);
+        if (checks == null &&
+            (functionName.endsWith("fv") ||
+             functionName.endsWith("xv") ||
+             functionName.endsWith("iv"))) {
+            functionName = functionName.substring(0, functionName.length() - 2);
+            checks = map.get(functionName);
+        }
+        return checks;
+    }
+}
diff --git a/opengl/tools/glgen/stubs/GL10ExtHeader.java-if b/opengl/tools/glgen/stubs/GL10ExtHeader.java-if
new file mode 100644
index 0000000..b0999c2
--- /dev/null
+++ b/opengl/tools/glgen/stubs/GL10ExtHeader.java-if
@@ -0,0 +1,22 @@
+**
+** Copyright 2007, 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.
+*/
+
+// This source file is automatically generated
+
+package javax.microedition.khronos.opengles;
+
+public interface GL10Ext extends GL {
+
diff --git a/opengl/tools/glgen/stubs/GL10Header.java-if b/opengl/tools/glgen/stubs/GL10Header.java-if
new file mode 100644
index 0000000..8392821
--- /dev/null
+++ b/opengl/tools/glgen/stubs/GL10Header.java-if
@@ -0,0 +1,259 @@
+**
+** Copyright 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.
+*/
+
+// This source file is automatically generated
+
+package javax.microedition.khronos.opengles;
+
+public interface GL10 extends GL {
+    int GL_ADD                                   = 0x0104;
+    int GL_ALIASED_LINE_WIDTH_RANGE              = 0x846E;
+    int GL_ALIASED_POINT_SIZE_RANGE              = 0x846D;
+    int GL_ALPHA                                 = 0x1906;
+    int GL_ALPHA_BITS                            = 0x0D55;
+    int GL_ALPHA_TEST                            = 0x0BC0;
+    int GL_ALWAYS                                = 0x0207;
+    int GL_AMBIENT                               = 0x1200;
+    int GL_AMBIENT_AND_DIFFUSE                   = 0x1602;
+    int GL_AND                                   = 0x1501;
+    int GL_AND_INVERTED                          = 0x1504;
+    int GL_AND_REVERSE                           = 0x1502;
+    int GL_BACK                                  = 0x0405;
+    int GL_BLEND                                 = 0x0BE2;
+    int GL_BLUE_BITS                             = 0x0D54;
+    int GL_BYTE                                  = 0x1400;
+    int GL_CCW                                   = 0x0901;
+    int GL_CLAMP_TO_EDGE                         = 0x812F;
+    int GL_CLEAR                                 = 0x1500;
+    int GL_COLOR_ARRAY                           = 0x8076;
+    int GL_COLOR_BUFFER_BIT                      = 0x4000;
+    int GL_COLOR_LOGIC_OP                        = 0x0BF2;
+    int GL_COLOR_MATERIAL                        = 0x0B57;
+    int GL_COMPRESSED_TEXTURE_FORMATS            = 0x86A3;
+    int GL_CONSTANT_ATTENUATION                  = 0x1207;
+    int GL_COPY                                  = 0x1503;
+    int GL_COPY_INVERTED                         = 0x150C;
+    int GL_CULL_FACE                             = 0x0B44;
+    int GL_CW                                    = 0x0900;
+    int GL_DECAL                                 = 0x2101;
+    int GL_DECR                                  = 0x1E03;
+    int GL_DEPTH_BITS                            = 0x0D56;
+    int GL_DEPTH_BUFFER_BIT                      = 0x0100;
+    int GL_DEPTH_TEST                            = 0x0B71;
+    int GL_DIFFUSE                               = 0x1201;
+    int GL_DITHER                                = 0x0BD0;
+    int GL_DONT_CARE                             = 0x1100;
+    int GL_DST_ALPHA                             = 0x0304;
+    int GL_DST_COLOR                             = 0x0306;
+    int GL_EMISSION                              = 0x1600;
+    int GL_EQUAL                                 = 0x0202;
+    int GL_EQUIV                                 = 0x1509;
+    int GL_EXP                                   = 0x0800;
+    int GL_EXP2                                  = 0x0801;
+    int GL_EXTENSIONS                            = 0x1F03;
+    int GL_FALSE                                 = 0;
+    int GL_FASTEST                               = 0x1101;
+    int GL_FIXED                                 = 0x140C;
+    int GL_FLAT                                  = 0x1D00;
+    int GL_FLOAT                                 = 0x1406;
+    int GL_FOG                                   = 0x0B60;
+    int GL_FOG_COLOR                             = 0x0B66;
+    int GL_FOG_DENSITY                           = 0x0B62;
+    int GL_FOG_END                               = 0x0B64;
+    int GL_FOG_HINT                              = 0x0C54;
+    int GL_FOG_MODE                              = 0x0B65;
+    int GL_FOG_START                             = 0x0B63;
+    int GL_FRONT                                 = 0x0404;
+    int GL_FRONT_AND_BACK                        = 0x0408;
+    int GL_GEQUAL                                = 0x0206;
+    int GL_GREATER                               = 0x0204;
+    int GL_GREEN_BITS                            = 0x0D53;
+    int GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES  = 0x8B9B;
+    int GL_IMPLEMENTATION_COLOR_READ_TYPE_OES    = 0x8B9A;
+    int GL_INCR                                  = 0x1E02;
+    int GL_INVALID_ENUM                          = 0x0500;
+    int GL_INVALID_OPERATION                     = 0x0502;
+    int GL_INVALID_VALUE                         = 0x0501;
+    int GL_INVERT                                = 0x150A;
+    int GL_KEEP                                  = 0x1E00;
+    int GL_LEQUAL                                = 0x0203;
+    int GL_LESS                                  = 0x0201;
+    int GL_LIGHT_MODEL_AMBIENT                   = 0x0B53;
+    int GL_LIGHT_MODEL_TWO_SIDE                  = 0x0B52;
+    int GL_LIGHT0                                = 0x4000;
+    int GL_LIGHT1                                = 0x4001;
+    int GL_LIGHT2                                = 0x4002;
+    int GL_LIGHT3                                = 0x4003;
+    int GL_LIGHT4                                = 0x4004;
+    int GL_LIGHT5                                = 0x4005;
+    int GL_LIGHT6                                = 0x4006;
+    int GL_LIGHT7                                = 0x4007;
+    int GL_LIGHTING                              = 0x0B50;
+    int GL_LINE_LOOP                             = 0x0002;
+    int GL_LINE_SMOOTH                           = 0x0B20;
+    int GL_LINE_SMOOTH_HINT                      = 0x0C52;
+    int GL_LINE_STRIP                            = 0x0003;
+    int GL_LINEAR                                = 0x2601;
+    int GL_LINEAR_ATTENUATION                    = 0x1208;
+    int GL_LINEAR_MIPMAP_LINEAR                  = 0x2703;
+    int GL_LINEAR_MIPMAP_NEAREST                 = 0x2701;
+    int GL_LINES                                 = 0x0001;
+    int GL_LUMINANCE                             = 0x1909;
+    int GL_LUMINANCE_ALPHA                       = 0x190A;
+    int GL_MAX_ELEMENTS_INDICES                  = 0x80E9;
+    int GL_MAX_ELEMENTS_VERTICES                 = 0x80E8;
+    int GL_MAX_LIGHTS                            = 0x0D31;
+    int GL_MAX_MODELVIEW_STACK_DEPTH             = 0x0D36;
+    int GL_MAX_PROJECTION_STACK_DEPTH            = 0x0D38;
+    int GL_MAX_TEXTURE_SIZE                      = 0x0D33;
+    int GL_MAX_TEXTURE_STACK_DEPTH               = 0x0D39;
+    int GL_MAX_TEXTURE_UNITS                     = 0x84E2;
+    int GL_MAX_VIEWPORT_DIMS                     = 0x0D3A;
+    int GL_MODELVIEW                             = 0x1700;
+    int GL_MODULATE                              = 0x2100;
+    int GL_MULTISAMPLE                           = 0x809D;
+    int GL_NAND                                  = 0x150E;
+    int GL_NEAREST                               = 0x2600;
+    int GL_NEAREST_MIPMAP_LINEAR                 = 0x2702;
+    int GL_NEAREST_MIPMAP_NEAREST                = 0x2700;
+    int GL_NEVER                                 = 0x0200;
+    int GL_NICEST                                = 0x1102;
+    int GL_NO_ERROR                              = 0;
+    int GL_NOOP                                  = 0x1505;
+    int GL_NOR                                   = 0x1508;
+    int GL_NORMAL_ARRAY                          = 0x8075;
+    int GL_NORMALIZE                             = 0x0BA1;
+    int GL_NOTEQUAL                              = 0x0205;
+    int GL_NUM_COMPRESSED_TEXTURE_FORMATS        = 0x86A2;
+    int GL_ONE                                   = 1;
+    int GL_ONE_MINUS_DST_ALPHA                   = 0x0305;
+    int GL_ONE_MINUS_DST_COLOR                   = 0x0307;
+    int GL_ONE_MINUS_SRC_ALPHA                   = 0x0303;
+    int GL_ONE_MINUS_SRC_COLOR                   = 0x0301;
+    int GL_OR                                    = 0x1507;
+    int GL_OR_INVERTED                           = 0x150D;
+    int GL_OR_REVERSE                            = 0x150B;
+    int GL_OUT_OF_MEMORY                         = 0x0505;
+    int GL_PACK_ALIGNMENT                        = 0x0D05;
+    int GL_PALETTE4_R5_G6_B5_OES                 = 0x8B92;
+    int GL_PALETTE4_RGB5_A1_OES                  = 0x8B94;
+    int GL_PALETTE4_RGB8_OES                     = 0x8B90;
+    int GL_PALETTE4_RGBA4_OES                    = 0x8B93;
+    int GL_PALETTE4_RGBA8_OES                    = 0x8B91;
+    int GL_PALETTE8_R5_G6_B5_OES                 = 0x8B97;
+    int GL_PALETTE8_RGB5_A1_OES                  = 0x8B99;
+    int GL_PALETTE8_RGB8_OES                     = 0x8B95;
+    int GL_PALETTE8_RGBA4_OES                    = 0x8B98;
+    int GL_PALETTE8_RGBA8_OES                    = 0x8B96;
+    int GL_PERSPECTIVE_CORRECTION_HINT           = 0x0C50;
+    int GL_POINT_SMOOTH                          = 0x0B10;
+    int GL_POINT_SMOOTH_HINT                     = 0x0C51;
+    int GL_POINTS                                = 0x0000;
+    int GL_POINT_FADE_THRESHOLD_SIZE             = 0x8128;
+    int GL_POINT_SIZE                            = 0x0B11;
+    int GL_POLYGON_OFFSET_FILL                   = 0x8037;
+    int GL_POLYGON_SMOOTH_HINT                   = 0x0C53;
+    int GL_POSITION                              = 0x1203;
+    int GL_PROJECTION                            = 0x1701;
+    int GL_QUADRATIC_ATTENUATION                 = 0x1209;
+    int GL_RED_BITS                              = 0x0D52;
+    int GL_RENDERER                              = 0x1F01;
+    int GL_REPEAT                                = 0x2901;
+    int GL_REPLACE                               = 0x1E01;
+    int GL_RESCALE_NORMAL                        = 0x803A;
+    int GL_RGB                                   = 0x1907;
+    int GL_RGBA                                  = 0x1908;
+    int GL_SAMPLE_ALPHA_TO_COVERAGE              = 0x809E;
+    int GL_SAMPLE_ALPHA_TO_ONE                   = 0x809F;
+    int GL_SAMPLE_COVERAGE                       = 0x80A0;
+    int GL_SCISSOR_TEST                          = 0x0C11;
+    int GL_SET                                   = 0x150F;
+    int GL_SHININESS                             = 0x1601;
+    int GL_SHORT                                 = 0x1402;
+    int GL_SMOOTH                                = 0x1D01;
+    int GL_SMOOTH_LINE_WIDTH_RANGE               = 0x0B22;
+    int GL_SMOOTH_POINT_SIZE_RANGE               = 0x0B12;
+    int GL_SPECULAR                              = 0x1202;
+    int GL_SPOT_CUTOFF                           = 0x1206;
+    int GL_SPOT_DIRECTION                        = 0x1204;
+    int GL_SPOT_EXPONENT                         = 0x1205;
+    int GL_SRC_ALPHA                             = 0x0302;
+    int GL_SRC_ALPHA_SATURATE                    = 0x0308;
+    int GL_SRC_COLOR                             = 0x0300;
+    int GL_STACK_OVERFLOW                        = 0x0503;
+    int GL_STACK_UNDERFLOW                       = 0x0504;
+    int GL_STENCIL_BITS                          = 0x0D57;
+    int GL_STENCIL_BUFFER_BIT                    = 0x0400;
+    int GL_STENCIL_TEST                          = 0x0B90;
+    int GL_SUBPIXEL_BITS                         = 0x0D50;
+    int GL_TEXTURE                               = 0x1702;
+    int GL_TEXTURE_2D                            = 0x0DE1;
+    int GL_TEXTURE_COORD_ARRAY                   = 0x8078;
+    int GL_TEXTURE_ENV                           = 0x2300;
+    int GL_TEXTURE_ENV_COLOR                     = 0x2201;
+    int GL_TEXTURE_ENV_MODE                      = 0x2200;
+    int GL_TEXTURE_MAG_FILTER                    = 0x2800;
+    int GL_TEXTURE_MIN_FILTER                    = 0x2801;
+    int GL_TEXTURE_WRAP_S                        = 0x2802;
+    int GL_TEXTURE_WRAP_T                        = 0x2803;
+    int GL_TEXTURE0                              = 0x84C0;
+    int GL_TEXTURE1                              = 0x84C1;
+    int GL_TEXTURE2                              = 0x84C2;
+    int GL_TEXTURE3                              = 0x84C3;
+    int GL_TEXTURE4                              = 0x84C4;
+    int GL_TEXTURE5                              = 0x84C5;
+    int GL_TEXTURE6                              = 0x84C6;
+    int GL_TEXTURE7                              = 0x84C7;
+    int GL_TEXTURE8                              = 0x84C8;
+    int GL_TEXTURE9                              = 0x84C9;
+    int GL_TEXTURE10                             = 0x84CA;
+    int GL_TEXTURE11                             = 0x84CB;
+    int GL_TEXTURE12                             = 0x84CC;
+    int GL_TEXTURE13                             = 0x84CD;
+    int GL_TEXTURE14                             = 0x84CE;
+    int GL_TEXTURE15                             = 0x84CF;
+    int GL_TEXTURE16                             = 0x84D0;
+    int GL_TEXTURE17                             = 0x84D1;
+    int GL_TEXTURE18                             = 0x84D2;
+    int GL_TEXTURE19                             = 0x84D3;
+    int GL_TEXTURE20                             = 0x84D4;
+    int GL_TEXTURE21                             = 0x84D5;
+    int GL_TEXTURE22                             = 0x84D6;
+    int GL_TEXTURE23                             = 0x84D7;
+    int GL_TEXTURE24                             = 0x84D8;
+    int GL_TEXTURE25                             = 0x84D9;
+    int GL_TEXTURE26                             = 0x84DA;
+    int GL_TEXTURE27                             = 0x84DB;
+    int GL_TEXTURE28                             = 0x84DC;
+    int GL_TEXTURE29                             = 0x84DD;
+    int GL_TEXTURE30                             = 0x84DE;
+    int GL_TEXTURE31                             = 0x84DF;
+    int GL_TRIANGLE_FAN                          = 0x0006;
+    int GL_TRIANGLE_STRIP                        = 0x0005;
+    int GL_TRIANGLES                             = 0x0004;
+    int GL_TRUE                                  = 1;
+    int GL_UNPACK_ALIGNMENT                      = 0x0CF5;
+    int GL_UNSIGNED_BYTE                         = 0x1401;
+    int GL_UNSIGNED_SHORT                        = 0x1403;
+    int GL_UNSIGNED_SHORT_4_4_4_4                = 0x8033;
+    int GL_UNSIGNED_SHORT_5_5_5_1                = 0x8034;
+    int GL_UNSIGNED_SHORT_5_6_5                  = 0x8363;
+    int GL_VENDOR                                = 0x1F00;
+    int GL_VERSION                               = 0x1F02;
+    int GL_VERTEX_ARRAY                          = 0x8074;
+    int GL_XOR                                   = 0x1506;
+    int GL_ZERO                                  = 0;
+
diff --git a/opengl/tools/glgen/stubs/GL11ExtHeader.java-if b/opengl/tools/glgen/stubs/GL11ExtHeader.java-if
new file mode 100644
index 0000000..7be2164
--- /dev/null
+++ b/opengl/tools/glgen/stubs/GL11ExtHeader.java-if
@@ -0,0 +1,40 @@
+**
+** Copyright 2007, 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.
+*/
+
+// This source file is automatically generated
+
+package javax.microedition.khronos.opengles;
+
+public interface GL11Ext extends GL {
+    int GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES = 0x8B9E;
+    int GL_MATRIX_INDEX_ARRAY_OES                = 0x8844;
+    int GL_MATRIX_INDEX_ARRAY_POINTER_OES        = 0x8849;
+    int GL_MATRIX_INDEX_ARRAY_SIZE_OES           = 0x8846;
+    int GL_MATRIX_INDEX_ARRAY_STRIDE_OES         = 0x8848;
+    int GL_MATRIX_INDEX_ARRAY_TYPE_OES           = 0x8847;
+    int GL_MATRIX_PALETTE_OES                    = 0x8840;
+    int GL_MAX_PALETTE_MATRICES_OES              = 0x8842;
+    int GL_MAX_VERTEX_UNITS_OES                  = 0x86A4;
+    int GL_TEXTURE_CROP_RECT_OES                 = 0x8B9D;
+    int GL_WEIGHT_ARRAY_BUFFER_BINDING_OES       = 0x889E;
+    int GL_WEIGHT_ARRAY_OES                      = 0x86AD;
+    int GL_WEIGHT_ARRAY_POINTER_OES              = 0x86AC;
+    int GL_WEIGHT_ARRAY_SIZE_OES                 = 0x86AB;
+    int GL_WEIGHT_ARRAY_STRIDE_OES               = 0x86AA;
+    int GL_WEIGHT_ARRAY_TYPE_OES                 = 0x86A9;
+
+    void glTexParameterfv(int target, int pname, float[] param, int offset);
+
diff --git a/opengl/tools/glgen/stubs/GL11ExtensionPackHeader.java-if b/opengl/tools/glgen/stubs/GL11ExtensionPackHeader.java-if
new file mode 100644
index 0000000..a800191
--- /dev/null
+++ b/opengl/tools/glgen/stubs/GL11ExtensionPackHeader.java-if
@@ -0,0 +1,108 @@
+**
+** Copyright 2007, 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.
+*/
+
+// This source file is automatically generated
+
+package javax.microedition.khronos.opengles;
+
+public interface GL11ExtensionPack extends GL {
+    int GL_BLEND_DST_ALPHA                                  = 0x80CA;
+    int GL_BLEND_DST_RGB                                    = 0x80C8;
+    int GL_BLEND_EQUATION                                   = 0x8009;
+    int GL_BLEND_EQUATION_ALPHA                             = 0x883D;
+    int GL_BLEND_EQUATION_RGB                               = 0x8009;
+    int GL_BLEND_SRC_ALPHA                                  = 0x80CB;
+    int GL_BLEND_SRC_RGB                                    = 0x80C9;
+    int GL_COLOR_ATTACHMENT0_OES                            = 0x8CE0;
+    int GL_COLOR_ATTACHMENT1_OES                            = 0x8CE1;
+    int GL_COLOR_ATTACHMENT2_OES                            = 0x8CE2;
+    int GL_COLOR_ATTACHMENT3_OES                            = 0x8CE3;
+    int GL_COLOR_ATTACHMENT4_OES                            = 0x8CE4;
+    int GL_COLOR_ATTACHMENT5_OES                            = 0x8CE5;
+    int GL_COLOR_ATTACHMENT6_OES                            = 0x8CE6;
+    int GL_COLOR_ATTACHMENT7_OES                            = 0x8CE7;
+    int GL_COLOR_ATTACHMENT8_OES                            = 0x8CE8;
+    int GL_COLOR_ATTACHMENT9_OES                            = 0x8CE9;
+    int GL_COLOR_ATTACHMENT10_OES                           = 0x8CEA;
+    int GL_COLOR_ATTACHMENT11_OES                           = 0x8CEB;
+    int GL_COLOR_ATTACHMENT12_OES                           = 0x8CEC;
+    int GL_COLOR_ATTACHMENT13_OES                           = 0x8CED;
+    int GL_COLOR_ATTACHMENT14_OES                           = 0x8CEE;
+    int GL_COLOR_ATTACHMENT15_OES                           = 0x8CEF;
+    int GL_DECR_WRAP                                        = 0x8508;
+    int GL_DEPTH_ATTACHMENT_OES                             = 0x8D00;
+    int GL_DEPTH_COMPONENT                                  = 0x1902;
+    int GL_DEPTH_COMPONENT16                                = 0x81A5;
+    int GL_DEPTH_COMPONENT24                                = 0x81A6;
+    int GL_DEPTH_COMPONENT32                                = 0x81A7;
+    int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES           = 0x8CD1;
+    int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES           = 0x8CD0;
+    int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES = 0x8CD3;
+    int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES         = 0x8CD2;
+    int GL_FRAMEBUFFER_BINDING_OES                          = 0x8CA6;
+    int GL_FRAMEBUFFER_COMPLETE_OES                         = 0x8CD5;
+    int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES            = 0x8CD6;
+    int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES            = 0x8CD9;
+    int GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES           = 0x8CDB;
+    int GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES               = 0x8CDA;
+    int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES    = 0x8CD7;
+    int GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES           = 0x8CDC;
+    int GL_FRAMEBUFFER_OES                                  = 0x8D40;
+    int GL_FRAMEBUFFER_UNSUPPORTED_OES                      = 0x8CDD;
+    int GL_FUNC_ADD                                         = 0x8006;
+    int GL_FUNC_REVERSE_SUBTRACT                            = 0x800B;
+    int GL_FUNC_SUBTRACT                                    = 0x800A;
+    int GL_INCR_WRAP                                        = 0x8507;
+    int GL_INVALID_FRAMEBUFFER_OPERATION_OES                = 0x0506;
+    int GL_MAX_COLOR_ATTACHMENTS_OES                        = 0x8CDF;
+    int GL_MAX_CUBE_MAP_TEXTURE_SIZE                        = 0x851C;
+    int GL_MAX_RENDERBUFFER_SIZE_OES                        = 0x84E8;
+    int GL_MIRRORED_REPEAT                                  = 0x8370;
+    int GL_NORMAL_MAP                                       = 0x8511;
+    int GL_REFLECTION_MAP                                   = 0x8512;
+    int GL_RENDERBUFFER_ALPHA_SIZE_OES                      = 0x8D53;
+    int GL_RENDERBUFFER_BINDING_OES                         = 0x8CA7;
+    int GL_RENDERBUFFER_BLUE_SIZE_OES                       = 0x8D52;
+    int GL_RENDERBUFFER_DEPTH_SIZE_OES                      = 0x8D54;
+    int GL_RENDERBUFFER_GREEN_SIZE_OES                      = 0x8D51;
+    int GL_RENDERBUFFER_HEIGHT_OES                          = 0x8D43;
+    int GL_RENDERBUFFER_INTERNAL_FORMAT_OES                 = 0x8D44;
+    int GL_RENDERBUFFER_OES                                 = 0x8D41;
+    int GL_RENDERBUFFER_RED_SIZE_OES                        = 0x8D50;
+    int GL_RENDERBUFFER_STENCIL_SIZE_OES                    = 0x8D55;
+    int GL_RENDERBUFFER_WIDTH_OES                           = 0x8D42;
+    int GL_RGB5_A1                                          = 0x8057;
+    int GL_RGB565_OES                                       = 0x8D62;
+    int GL_RGB8                                             = 0x8051;
+    int GL_RGBA4                                            = 0x8056;
+    int GL_RGBA8                                            = 0x8058;
+    int GL_STENCIL_ATTACHMENT_OES                           = 0x8D20;
+    int GL_STENCIL_INDEX                                    = 0x1901;
+    int GL_STENCIL_INDEX1_OES                               = 0x8D46;
+    int GL_STENCIL_INDEX4_OES                               = 0x8D47;
+    int GL_STENCIL_INDEX8_OES                               = 0x8D48;
+    int GL_STR                                              = -1;
+    int GL_TEXTURE_BINDING_CUBE_MAP                         = 0x8514;
+    int GL_TEXTURE_CUBE_MAP                                 = 0x8513;
+    int GL_TEXTURE_CUBE_MAP_NEGATIVE_X                      = 0x8516;
+    int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y                      = 0x8518;
+    int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z                      = 0x851A;
+    int GL_TEXTURE_CUBE_MAP_POSITIVE_X                      = 0x8515;
+    int GL_TEXTURE_CUBE_MAP_POSITIVE_Y                      = 0x8517;
+    int GL_TEXTURE_CUBE_MAP_POSITIVE_Z                      = 0x8519;
+    int GL_TEXTURE_GEN_MODE                                 = 0x2500;
+    int GL_TEXTURE_GEN_STR                                  = 0x8D60;
+
diff --git a/opengl/tools/glgen/stubs/GL11Header.java-if b/opengl/tools/glgen/stubs/GL11Header.java-if
new file mode 100644
index 0000000..b0e5a6b
--- /dev/null
+++ b/opengl/tools/glgen/stubs/GL11Header.java-if
@@ -0,0 +1,145 @@
+**
+** Copyright 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.
+*/
+
+// This source file is automatically generated
+
+package javax.microedition.khronos.opengles;
+
+public interface GL11 extends GL10 {
+    int GL_ACTIVE_TEXTURE                          = 0x84E0;
+    int GL_ADD_SIGNED                              = 0x8574;
+    int GL_ALPHA_SCALE                             = 0x0D1C;
+    int GL_ALPHA_TEST_FUNC                         = 0x0BC1;
+    int GL_ALPHA_TEST_REF                          = 0x0BC2;
+    int GL_ARRAY_BUFFER                            = 0x8892;
+    int GL_ARRAY_BUFFER_BINDING                    = 0x8894;
+    int GL_BLEND_DST                               = 0x0BE0;
+    int GL_BLEND_SRC                               = 0x0BE1;
+    int GL_BUFFER_ACCESS                           = 0x88BB;
+    int GL_BUFFER_SIZE                             = 0x8764;
+    int GL_BUFFER_USAGE                            = 0x8765;
+    int GL_CLIENT_ACTIVE_TEXTURE                   = 0x84E1;
+    int GL_CLIP_PLANE0                             = 0x3000;
+    int GL_CLIP_PLANE1                             = 0x3001;
+    int GL_CLIP_PLANE2                             = 0x3002;
+    int GL_CLIP_PLANE3                             = 0x3003;
+    int GL_CLIP_PLANE4                             = 0x3004;
+    int GL_CLIP_PLANE5                             = 0x3005;
+    int GL_COLOR_ARRAY_BUFFER_BINDING              = 0x8898;
+    int GL_COLOR_ARRAY_POINTER                     = 0x8090;
+    int GL_COLOR_ARRAY_SIZE                        = 0x8081;
+    int GL_COLOR_ARRAY_STRIDE                      = 0x8083;
+    int GL_COLOR_ARRAY_TYPE                        = 0x8082;
+    int GL_COLOR_CLEAR_VALUE                       = 0x0C22;
+    int GL_COLOR_WRITEMASK                         = 0x0C23;
+    int GL_COMBINE                                 = 0x8570;
+    int GL_COMBINE_ALPHA                           = 0x8572;
+    int GL_COMBINE_RGB                             = 0x8571;
+    int GL_CONSTANT                                = 0x8576;
+    int GL_COORD_REPLACE_OES                       = 0x8862;
+    int GL_CULL_FACE_MODE                          = 0x0B45;
+    int GL_CURRENT_COLOR                           = 0x0B00;
+    int GL_CURRENT_NORMAL                          = 0x0B02;
+    int GL_CURRENT_TEXTURE_COORDS                  = 0x0B03;
+    int GL_DEPTH_CLEAR_VALUE                       = 0x0B73;
+    int GL_DEPTH_FUNC                              = 0x0B74;
+    int GL_DEPTH_RANGE                             = 0x0B70;
+    int GL_DEPTH_WRITEMASK                         = 0x0B72;
+    int GL_DOT3_RGB                                = 0x86AE;
+    int GL_DOT3_RGBA                               = 0x86AF;
+    int GL_DYNAMIC_DRAW                            = 0x88E8;
+    int GL_ELEMENT_ARRAY_BUFFER                    = 0x8893;
+    int GL_ELEMENT_ARRAY_BUFFER_BINDING            = 0x8895;
+    int GL_FRONT_FACE                              = 0x0B46;
+    int GL_GENERATE_MIPMAP                         = 0x8191;
+    int GL_GENERATE_MIPMAP_HINT                    = 0x8192;
+    int GL_INTERPOLATE                             = 0x8575;
+    int GL_LINE_WIDTH                              = 0x0B21;
+    int GL_LOGIC_OP_MODE                           = 0x0BF0;
+    int GL_MATRIX_MODE                             = 0x0BA0;
+    int GL_MAX_CLIP_PLANES                         = 0x0D32;
+    int GL_MODELVIEW_MATRIX                        = 0x0BA6;
+    int GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES  = 0x898D;
+    int GL_MODELVIEW_STACK_DEPTH                   = 0x0BA3;
+    int GL_NORMAL_ARRAY_BUFFER_BINDING             = 0x8897;
+    int GL_NORMAL_ARRAY_POINTER                    = 0x808F;
+    int GL_NORMAL_ARRAY_STRIDE                     = 0x807F;
+    int GL_NORMAL_ARRAY_TYPE                       = 0x807E;
+    int GL_OPERAND0_ALPHA                          = 0x8598;
+    int GL_OPERAND0_RGB                            = 0x8590;
+    int GL_OPERAND1_ALPHA                          = 0x8599;
+    int GL_OPERAND1_RGB                            = 0x8591;
+    int GL_OPERAND2_ALPHA                          = 0x859A;
+    int GL_OPERAND2_RGB                            = 0x8592;
+    int GL_POINT_DISTANCE_ATTENUATION              = 0x8129;
+    int GL_POINT_FADE_THRESHOLD_SIZE               = 0x8128;
+    int GL_POINT_SIZE                              = 0x0B11;
+    int GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES     = 0x8B9F;
+    int GL_POINT_SIZE_ARRAY_OES                    = 0x8B9C;
+    int GL_POINT_SIZE_ARRAY_POINTER_OES            = 0x898C;
+    int GL_POINT_SIZE_ARRAY_STRIDE_OES             = 0x898B;
+    int GL_POINT_SIZE_ARRAY_TYPE_OES               = 0x898A;
+    int GL_POINT_SIZE_MAX                          = 0x8127;
+    int GL_POINT_SIZE_MIN                          = 0x8126;
+    int GL_POINT_SPRITE_OES                        = 0x8861;
+    int GL_POLYGON_OFFSET_FACTOR                   = 0x8038;
+    int GL_POLYGON_OFFSET_UNITS                    = 0x2A00;
+    int GL_PREVIOUS                                = 0x8578;
+    int GL_PRIMARY_COLOR                           = 0x8577;
+    int GL_PROJECTION_MATRIX                       = 0x0BA7;
+    int GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898E;
+    int GL_PROJECTION_STACK_DEPTH                  = 0x0BA4;
+    int GL_RGB_SCALE                               = 0x8573;
+    int GL_SAMPLE_BUFFERS                          = 0x80A8;
+    int GL_SAMPLE_COVERAGE_INVERT                  = 0x80AB;
+    int GL_SAMPLE_COVERAGE_VALUE                   = 0x80AA;
+    int GL_SAMPLES                                 = 0x80A9;
+    int GL_SCISSOR_BOX                             = 0x0C10;
+    int GL_SHADE_MODEL                             = 0x0B54;
+    int GL_SRC0_ALPHA                              = 0x8588;
+    int GL_SRC0_RGB                                = 0x8580;
+    int GL_SRC1_ALPHA                              = 0x8589;
+    int GL_SRC1_RGB                                = 0x8581;
+    int GL_SRC2_ALPHA                              = 0x858A;
+    int GL_SRC2_RGB                                = 0x8582;
+    int GL_STATIC_DRAW                             = 0x88E4;
+    int GL_STENCIL_CLEAR_VALUE                     = 0x0B91;
+    int GL_STENCIL_FAIL                            = 0x0B94;
+    int GL_STENCIL_FUNC                            = 0x0B92;
+    int GL_STENCIL_PASS_DEPTH_FAIL                 = 0x0B95;
+    int GL_STENCIL_PASS_DEPTH_PASS                 = 0x0B96;
+    int GL_STENCIL_REF                             = 0x0B97;
+    int GL_STENCIL_VALUE_MASK                      = 0x0B93;
+    int GL_STENCIL_WRITEMASK                       = 0x0B98;
+    int GL_SUBTRACT                                = 0x84E7;
+    int GL_TEXTURE_BINDING_2D                      = 0x8069;
+    int GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING      = 0x889A;
+    int GL_TEXTURE_COORD_ARRAY_POINTER             = 0x8092;
+    int GL_TEXTURE_COORD_ARRAY_SIZE                = 0x8088;
+    int GL_TEXTURE_COORD_ARRAY_STRIDE              = 0x808A;
+    int GL_TEXTURE_COORD_ARRAY_TYPE                = 0x8089;
+    int GL_TEXTURE_MATRIX                          = 0x0BA8;
+    int GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES    = 0x898F;
+    int GL_TEXTURE_STACK_DEPTH                     = 0x0BA5;
+    int GL_VERTEX_ARRAY_BUFFER_BINDING             = 0x8896;
+    int GL_VERTEX_ARRAY_POINTER                    = 0x808E;
+    int GL_VERTEX_ARRAY_SIZE                       = 0x807A;
+    int GL_VERTEX_ARRAY_STRIDE                     = 0x807C;
+    int GL_VERTEX_ARRAY_TYPE                       = 0x807B;
+    int GL_VIEWPORT                                = 0x0BA2;
+    int GL_WRITE_ONLY                              = 0x88B9;
+
+    void glGetPointerv(int pname, java.nio.Buffer[] params);
diff --git a/opengl/tools/glgen/stubs/GL11ImplHeader.java-impl b/opengl/tools/glgen/stubs/GL11ImplHeader.java-impl
new file mode 100644
index 0000000..501be65
--- /dev/null
+++ b/opengl/tools/glgen/stubs/GL11ImplHeader.java-impl
@@ -0,0 +1,30 @@
+// Copyright 2006 The Android Open Source Project
+
+// All Rights Reserved.
+
+// This source file is automatically generated
+
+package com.google.android.gles_jni;
+
+import java.nio.Buffer;
+import javax.microedition.khronos.opengles.GL11;
+import android.graphics.Canvas;
+
+public class GL11Impl implements GL11 {
+
+    // Private accessors for native code
+
+    native private static void _nativeClassInit();
+    static {
+	_nativeClassInit();
+    }
+
+    Buffer _colorPointer = null;
+    Buffer _normalPointer = null;
+    Buffer _texCoordPointer = null;
+    Buffer _vertexPointer = null;
+
+    public GL11Impl() {
+    }
+
+
diff --git a/opengl/tools/glgen/stubs/GLCHeader.cpp b/opengl/tools/glgen/stubs/GLCHeader.cpp
new file mode 100644
index 0000000..6495686
--- /dev/null
+++ b/opengl/tools/glgen/stubs/GLCHeader.cpp
@@ -0,0 +1,129 @@
+**
+** Copyright 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.
+*/
+
+// This source file is automatically generated
+
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+
+#include <assert.h>
+#include <GLES/gl.h>
+
+#include <private/opengles/gl_context.h>
+
+#define _NUM_COMPRESSED_TEXTURE_FORMATS \
+        (::android::OGLES_NUM_COMPRESSED_TEXTURE_FORMATS)
+
+static int initialized = 0;
+
+static jclass nioAccessClass;
+static jclass bufferClass;
+static jclass OOMEClass;
+static jclass UOEClass;
+static jclass IAEClass;
+static jclass AIOOBEClass;
+static jmethodID getBasePointerID;
+static jmethodID getBaseArrayID;
+static jmethodID getBaseArrayOffsetID;
+static jfieldID positionID;
+static jfieldID limitID;
+static jfieldID elementSizeShiftID;
+
+/* Cache method IDs each time the class is loaded. */
+
+void
+nativeClassInitBuffer(JNIEnv *_env)
+{
+    jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
+    nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
+
+    jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
+    bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
+
+    getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+            "getBasePointer", "(Ljava/nio/Buffer;)J");
+    getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+            "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+    getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+            "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+
+    positionID = _env->GetFieldID(bufferClass, "position", "I");
+    limitID = _env->GetFieldID(bufferClass, "limit", "I");
+    elementSizeShiftID =
+        _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+}
+
+
+static void
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
+{
+    nativeClassInitBuffer(_env);
+
+    jclass IAEClassLocal =
+        _env->FindClass("java/lang/IllegalArgumentException");
+    jclass OOMEClassLocal =
+         _env->FindClass("java/lang/OutOfMemoryError");
+    jclass UOEClassLocal =
+         _env->FindClass("java/lang/UnsupportedOperationException");
+    jclass AIOOBEClassLocal =
+         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
+
+    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
+    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
+    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
+    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
+}
+
+static void *
+getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
+{
+    jint position;
+    jint limit;
+    jint elementSizeShift;
+    jlong pointer;
+    jint offset;
+    void *data;
+
+    position = _env->GetIntField(buffer, positionID);
+    limit = _env->GetIntField(buffer, limitID);
+    elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+    *remaining = (limit - position) << elementSizeShift;
+    pointer = _env->CallStaticLongMethod(nioAccessClass,
+            getBasePointerID, buffer);
+    if (pointer != 0L) {
+        *array = NULL;
+        return (void *) (jint) pointer;
+    }
+    
+    *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
+            getBaseArrayID, buffer);
+    offset = _env->CallStaticIntMethod(nioAccessClass,
+            getBaseArrayOffsetID, buffer);
+    data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
+    
+    return (void *) ((char *) data + offset);
+}
+
+
+static void
+releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
+{
+    _env->ReleasePrimitiveArrayCritical(array, data,
+					   commit ? 0 : JNI_ABORT);
+}
+
+// --------------------------------------------------------------------------
+
diff --git a/opengl/tools/glgen/stubs/GLHeader.java-if b/opengl/tools/glgen/stubs/GLHeader.java-if
new file mode 100644
index 0000000..3b78f3d
--- /dev/null
+++ b/opengl/tools/glgen/stubs/GLHeader.java-if
@@ -0,0 +1,22 @@
+/* //device/java/android/javax/microedition/khronos/opengles/GL.java
+**
+** Copyright 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.
+*/
+
+package javax.microedition.khronos.opengles;
+
+public interface GL {
+}
+
diff --git a/opengl/tools/glgen/stubs/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/GLImplHeader.java-impl
new file mode 100644
index 0000000..db3a41c
--- /dev/null
+++ b/opengl/tools/glgen/stubs/GLImplHeader.java-impl
@@ -0,0 +1,48 @@
+**
+** Copyright 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.
+*/
+
+// This source file is automatically generated
+
+package com.google.android.gles_jni;
+
+import java.nio.Buffer;
+import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.opengles.GL10Ext;
+import javax.microedition.khronos.opengles.GL11;
+import javax.microedition.khronos.opengles.GL11Ext;
+import javax.microedition.khronos.opengles.GL11ExtensionPack;
+
+public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack {
+
+    // Private accessors for native code
+
+    native private static void _nativeClassInit();
+    static {
+	_nativeClassInit();
+    }
+
+    Buffer _colorPointer = null;
+    Buffer _normalPointer = null;
+    Buffer _texCoordPointer = null;
+    Buffer _vertexPointer = null;
+
+    public GLImpl() {
+    }
+
+     public void glGetPointerv(int pname, java.nio.Buffer[] params) {
+         throw new UnsupportedOperationException("glGetPointerv");
+     }
+
diff --git a/opengl/tools/glgen/stubs/glGetString.cpp b/opengl/tools/glgen/stubs/glGetString.cpp
new file mode 100644
index 0000000..22e1297
--- /dev/null
+++ b/opengl/tools/glgen/stubs/glGetString.cpp
@@ -0,0 +1,10 @@
+#include <string.h>

+

+/* const GLubyte * glGetString ( GLenum name ) */

+jstring

+android_glGetString

+  (JNIEnv *_env, jobject _this, jint name) {

+    const char * chars = (const char *)glGetString((GLenum)name);

+    jstring output = _env->NewStringUTF(chars);

+    return output;

+}

diff --git a/opengl/tools/glgen/stubs/glGetString.java-10-if b/opengl/tools/glgen/stubs/glGetString.java-10-if
new file mode 100644
index 0000000..898fabc
--- /dev/null
+++ b/opengl/tools/glgen/stubs/glGetString.java-10-if
@@ -0,0 +1,4 @@
+    public String glGetString(

+        int name

+    );

+

diff --git a/opengl/tools/glgen/stubs/glGetString.java-if b/opengl/tools/glgen/stubs/glGetString.java-if
new file mode 100644
index 0000000..898fabc
--- /dev/null
+++ b/opengl/tools/glgen/stubs/glGetString.java-if
@@ -0,0 +1,4 @@
+    public String glGetString(

+        int name

+    );

+

diff --git a/opengl/tools/glgen/stubs/glGetString.java-impl b/opengl/tools/glgen/stubs/glGetString.java-impl
new file mode 100644
index 0000000..8c7881c
--- /dev/null
+++ b/opengl/tools/glgen/stubs/glGetString.java-impl
@@ -0,0 +1,16 @@
+    // C function const GLubyte * glGetString ( GLenum name )

+

+    public native String _glGetString(

+        int name

+    );

+

+    public String glGetString(

+        int name

+    ) {

+        String returnValue;

+        returnValue = _glGetString(

+            name

+        );

+        return returnValue;

+    }

+

diff --git a/opengl/tools/glgen/stubs/glGetString.nativeReg b/opengl/tools/glgen/stubs/glGetString.nativeReg
new file mode 100644
index 0000000..e64187c
--- /dev/null
+++ b/opengl/tools/glgen/stubs/glGetString.nativeReg
@@ -0,0 +1 @@
+{"_glGetString", "(I)Ljava/lang/String;", (void *) android_glGetString },

diff --git a/services/Android.mk b/services/Android.mk
new file mode 100644
index 0000000..5e912d6
--- /dev/null
+++ b/services/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+
+# the library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+            $(call all-subdir-java-files)
+
+LOCAL_MODULE:= services
+
+LOCAL_JAVA_LIBRARIES := android.policy
+
+include $(BUILD_JAVA_LIBRARY)
+
+include $(BUILD_DROIDDOC)
+